python - Matplotlib RegularPolygon collection location on the canvas -
i trying plot feature map (som) using python. keep simple, imagine 2d plot each unit represented hexagon.
as shown on topic: hexagonal self-organizing map in python hexagons located side-by-side formated grid.
i manage write following piece of code , works set number of polygons , few shapes (6 x 6 or 10 x 4 hexagons example). 1 important feature of method support grid shape 3 x 3.
def plot_map(grid, d_matrix, w=10, title='som hit map'): """ plot hexagon map each neuron represented hexagon. hexagon color given distance between neurons (d-matrix) scaled hexagons appear on top of background image whether hits array provided. scaled according number of hits on each neuron. args: - grid: grid dictionary (keys: centers, x, y ), - d_matrix: array contaning distances between each neuron - w: width of map in inches - title: map title returns matplotlib subaxis instance """ n_centers = grid['centers'] x, y = grid['x'], grid['y'] fig = plt.figure(figsize=(1.05 * w, 0.85 * y * w / x), dpi=100) ax = fig.add_subplot(111) ax.axis('equal') # discover difference between centers collection_bg = regularpolycollection( numsides=6, # hexagon rotation=0, sizes=(y * (1.3 * 2 * math.pi * w) ** 2 / x,), edgecolors = (0, 0, 0, 1), array= d_matrix, cmap = cm.gray, offsets = n_centers, transoffset = ax.transdata, ) ax.add_collection(collection_bg, autolim=true) ax.axis('off') ax.autoscale_view() ax.set_title(title) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) plt.colorbar(collection_bg, cax=cax) return ax
i've tried make automatically understands grid shape. didn't work (and i'm not sure why). appear undesired space between hexagons
summarising: generate 3x3 or 6x6 or 10x4 (and on) grid using hexagons no spaces in between given points , setting plot width.
as asked, here data hexagons location. can see, same pattern
3x3
{'centers': array([[ 1.5 , 0.8660254 ], [ 2.5 , 0.8660254 ], [ 3.5 , 0.8660254 ], [ 1. , 1.73205081], [ 2. , 1.73205081], [ 3. , 1.73205081], [ 1.5 , 2.59807621], [ 2.5 , 2.59807621], [ 3.5 , 2.59807621]]), 'x': array([ 3.]), 'y': array([ 3.])}
6x6
{'centers': array([[ 1.5 , 0.8660254 ], [ 2.5 , 0.8660254 ], [ 3.5 , 0.8660254 ], [ 4.5 , 0.8660254 ], [ 5.5 , 0.8660254 ], [ 6.5 , 0.8660254 ], [ 1. , 1.73205081], [ 2. , 1.73205081], [ 3. , 1.73205081], [ 4. , 1.73205081], [ 5. , 1.73205081], [ 6. , 1.73205081], [ 1.5 , 2.59807621], [ 2.5 , 2.59807621], [ 3.5 , 2.59807621], [ 4.5 , 2.59807621], [ 5.5 , 2.59807621], [ 6.5 , 2.59807621], [ 1. , 3.46410162], [ 2. , 3.46410162], [ 3. , 3.46410162], [ 4. , 3.46410162], [ 5. , 3.46410162], [ 6. , 3.46410162], [ 1.5 , 4.33012702], [ 2.5 , 4.33012702], [ 3.5 , 4.33012702], [ 4.5 , 4.33012702], [ 5.5 , 4.33012702], [ 6.5 , 4.33012702], [ 1. , 5.19615242], [ 2. , 5.19615242], [ 3. , 5.19615242], [ 4. , 5.19615242], [ 5. , 5.19615242], [ 6. , 5.19615242]]), 'x': array([ 6.]), 'y': array([ 6.])}
11x4
{'centers': array([[ 1.5 , 0.8660254 ], [ 2.5 , 0.8660254 ], [ 3.5 , 0.8660254 ], [ 4.5 , 0.8660254 ], [ 5.5 , 0.8660254 ], [ 6.5 , 0.8660254 ], [ 7.5 , 0.8660254 ], [ 8.5 , 0.8660254 ], [ 9.5 , 0.8660254 ], [ 10.5 , 0.8660254 ], [ 11.5 , 0.8660254 ], [ 1. , 1.73205081], [ 2. , 1.73205081], [ 3. , 1.73205081], [ 4. , 1.73205081], [ 5. , 1.73205081], [ 6. , 1.73205081], [ 7. , 1.73205081], [ 8. , 1.73205081], [ 9. , 1.73205081], [ 10. , 1.73205081], [ 11. , 1.73205081], [ 1.5 , 2.59807621], [ 2.5 , 2.59807621], [ 3.5 , 2.59807621], [ 4.5 , 2.59807621], [ 5.5 , 2.59807621], [ 6.5 , 2.59807621], [ 7.5 , 2.59807621], [ 8.5 , 2.59807621], [ 9.5 , 2.59807621], [ 10.5 , 2.59807621], [ 11.5 , 2.59807621], [ 1. , 3.46410162], [ 2. , 3.46410162], [ 3. , 3.46410162], [ 4. , 3.46410162], [ 5. , 3.46410162], [ 6. , 3.46410162], [ 7. , 3.46410162], [ 8. , 3.46410162], [ 9. , 3.46410162], [ 10. , 3.46410162], [ 11. , 3.46410162]]), 'x': array([ 11.]), 'y': array([ 4.])}
i've manage find workaround calculating figure size of inches according given dpi. after, compute pixel distance between 2 adjacent points (by plotting using hidden scatter plot). way calculate hexagon apothem , estimate correctly size of hexagon's inner circle (as matplotlib expects).
no gaps in end!
import matplotlib.pyplot plt matplotlib import colors, cm matplotlib.collections import regularpolycollection mpl_toolkits.axes_grid1 import make_axes_locatable import math import numpy np def plot_map(grid, d_matrix, w=1080, dpi=72., title='som hit map'): """ plot hexagon map each neuron represented hexagon. hexagon color given distance between neurons (d-matrix) args: - grid: grid dictionary (keys: centers, x, y ), - d_matrix: array contaning distances between each neuron - w: width of map in inches - title: map title returns matplotlib subaxis instance """ n_centers = grid['centers'] x, y = grid['x'], grid['y'] # size of figure in inches xinch = (x * w / y) / dpi yinch = (y * w / x) / dpi fig = plt.figure(figsize=(xinch, yinch), dpi=dpi) ax = fig.add_subplot(111, aspect='equal') # pixel size between data points xpoints = n_centers[:, 0] ypoints = n_centers[:, 1] ax.scatter(xpoints, ypoints, s=0.0, marker='s') ax.axis([min(xpoints)-1., max(xpoints)+1., min(ypoints)-1., max(ypoints)+1.]) xy_pixels = ax.transdata.transform(np.vstack([xpoints, ypoints]).t) xpix, ypix = xy_pixels.t # in matplotlib, 0,0 lower left corner, whereas it's # upper right image software, we'll flip y-coords width, height = fig.canvas.get_width_height() ypix = height - ypix # discover radius , hexagon apothem = .9 * (xpix[1] - xpix[0]) / math.sqrt(3) area_inner_circle = math.pi * (apothem ** 2) collection_bg = regularpolycollection( numsides=6, # hexagon rotation=0, sizes=(area_inner_circle,), edgecolors = (0, 0, 0, 1), array= d_matrix, cmap = cm.gray, offsets = n_centers, transoffset = ax.transdata, ) ax.add_collection(collection_bg, autolim=true) ax.axis('off') ax.autoscale_view() ax.set_title(title) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="10%", pad=0.05) plt.colorbar(collection_bg, cax=cax) return ax
Comments
Post a Comment