Matplotlib: figure.add_axes convert from x,y to relative coordinates

亡梦爱人 提交于 2021-01-28 02:00:13

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!