问题
I am working on a self-organizing map that I want to show as a hexagonal lattice with spider charts representing the weight vector/neuron in the corresponding cells and have been able to create a hexagonal grid via the following:
def hex_plot(ws,a=1):
"""
plots a m (rows) x n (cols) hexagonal grid with offset rows where a is
the hexagon's side length and m and n are determined by the first two
dimensions of the weight vectors ws
"""
m,n,_ = ws.shape
offsety = .75 * 2*a
offsetx = numpy.sqrt(3) * a
oddrow = numpy.sqrt(3)/2 * a
x,y = 0,0
fig,ax = plt.subplots(figsize=(7.5,7.5))
ax.set_aspect('equal')
ax.set_zorder(1)
cs = {}
for i in range(m):
for j in range(n):
offsetr = oddrow if i % 2 != 0 else 0
cp = (j*offsetx+offsetr,-i*offsety)
cs[(i,j)] = cp
hexg = RegularPolygon(cp,numVertices=6,radius=a,facecolor='white',edgecolor='k')
ax.add_patch(hexg)
ax.text(cp[0], cp[1], "{},{}\n{:.2f},{:.2f}".format(i,j,cp[0],cp[1]), ha='center', va='center', size=10)
xy = [cs[(i,j)] for i in range(m) for j in range(n)]
ax.scatter([x for x,_ in xy],[y for _,y in xy],c='white',alpha=0.5)
ax.set_xticks([])
ax.set_yticks([])
plt.show()
This gives me the following:
5x4 blank hexagon grid
With that I am trying to place spider charts of the neurons 5x4 trained SOM representing each weight vector such that the spider chart at 0,0 (top left) is inside the hexagonal cell at 0,0 (top left). I tried using sub plots but the difficulty arises in the spider charts having a polar projections whereas the grids do not. My second attempt involves using "add_axes". By adding the following immediately prior to plt.show() in the code above:
w = ws[0][0] # current weight vector
a = numpy.linspace(0,2*numpy.pi,len(w),endpoint=False)
a = numpy.concatenate((a,[a[0]]))
w = numpy.concatenate((w,[w[0]]))
ax1 = fig.add_axes([0.0,0.0,0.1,0.1],polar=True,zorder=2)
ax1.set_thetagrids([])
ax1.fill(a,w,alpha=1.0)
ax1.set_yticklabels([])
ax1.set_rticks([])
I can place a spider chart in the lower left canvas: Spider chart over hex, But since the rectangle specified in add_axes is in coordinates relative to the figure, I cannot figure out to determine what coordinate 0,0 in the orginal axes (hexagon 0,0) would map to in relative coordinates. I looked at transformations but it wasn't helpful.
Has anyone ran into this and come up with a solution? Thanks
回答1:
I see two options here:
Plot all shapes in a single axes
Since it does not look like there is a need for a special polar axes you could just plot the fills all in the same axes at the respective positions of the hexagons.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import RegularPolygon
def hex_plot(ws,a=1):
"""
plots a m (rows) x n (cols) hexagonal grid with offset rows where a is
the hexagon's side length and m and n are determined by the first two
dimensions of the weight vectors ws
"""
m,n,l = ws.shape
offsety = .75 * 2*a
offsetx = np.sqrt(3) * a
oddrow = np.sqrt(3)/2 * a
theta = np.linspace(0, 2*np.pi, l+1)
fig,ax = plt.subplots(figsize=(7.5,7.5))
ax.set_aspect('equal')
ax.set_zorder(1)
cs = {}
for i in range(m):
for j in range(n):
offsetr = oddrow if i % 2 != 0 else 0
cp = (j*offsetx+offsetr,-i*offsety)
cs[(i,j)] = cp
hexg = RegularPolygon(cp,numVertices=6,radius=a,
facecolor='white',edgecolor='k')
ax.add_patch(hexg)
ax.text(cp[0], cp[1], "{},{}\n{:.2f},{:.2f}".format(i,j,cp[0],cp[1]),
ha='center', va='center', size=10)
r = ws[i,j,:]
r = np.concatenate((r, [r[0]]))
x,y = (np.c_[r*np.sin(theta), r*np.cos(theta)] + cp).T
ax.fill(x,y, color="C0")
ax.autoscale()
ax.set_xticks([])
ax.set_yticks([])
plt.show()
hex_plot(np.random.rand(5,4,6),a=1)
Use inset_axes
If you really need the axes, e.g. to show the grids, you may position inset_axes at the respective positions.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import RegularPolygon
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
from matplotlib.projections import get_projection_class
def hex_plot(ws,a=1):
"""
plots a m (rows) x n (cols) hexagonal grid with offset rows where a is
the hexagon's side length and m and n are determined by the first two
dimensions of the weight vectors ws
"""
m,n,l = ws.shape
offsety = .75 * 2*a
offsetx = np.sqrt(3) * a
oddrow = np.sqrt(3)/2 * a
theta = np.linspace(0, 2*np.pi, l+1)
fig,ax = plt.subplots(figsize=(7.5,7.5))
ax.set_aspect('equal')
ax.set_zorder(1)
cs = {}
axcs = {}
for i in range(m):
for j in range(n):
offsetr = oddrow if i % 2 != 0 else 0
cp = (j*offsetx+offsetr,-i*offsety)
cs[(i,j)] = cp
hexg = RegularPolygon(cp,numVertices=6,radius=a,
facecolor='white',edgecolor='k')
ax.add_patch(hexg)
ax.text(cp[0], cp[1], "{},{}\n{:.2f},{:.2f}".format(i,j,cp[0],cp[1]),
ha='center', va='center', size=10)
axins=inset_axes(ax, width="100%", height="100%",
bbox_to_anchor=(cp[0]-offsetx/2, cp[1]-offsety/2, offsetx, offsety),
bbox_transform=ax.transData, borderpad=0,
axes_class=get_projection_class("polar"),
)
axins.set_zorder(4)
axcs[(i,j)] = axins
r = ws[i,j,:]
r = np.concatenate((r, [r[0]]))
axins.fill(theta,r)
axins.set_yticklabels([])
axins.set_xticklabels([])
ax.autoscale()
ax.set_xticks([])
ax.set_yticks([])
plt.show()
hex_plot(np.random.rand(5,4,6),a=1)
来源:https://stackoverflow.com/questions/53204267/matplotlib-figure-add-axes-convert-from-x-y-to-relative-coordinates