Matplotlib RegularPolygon集合在画布上的位置

2024-05-17 04:35:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图用python绘制一个特性图(SOM)。 为了简单起见,设想一个二维绘图,其中每个单元都表示为一个六边形。在

如本主题所示:Hexagonal Self-Organizing map in Python六边形并排放置,格式为网格。在

我设法写了下面的一段代码,它完美地适用于一定数量的多边形,并且只适用于少数形状(例如6×6或10×4的六边形)。然而,这种方法的一个重要特性是支持3x3的任何网格形状。在

def plot_map(grid,
             d_matrix,
             w=10,
             title='SOM Hit map'):
    """
    Plot hexagon map where each neuron is represented by a hexagon. The hexagon
    color is given by the distance between the neurons (D-Matrix) Scaled
    hexagons will appear on top of the background image whether the hits array
    is provided. They are scaled according to the number of hits on each
    neuron.

    Args:
    - grid: Grid dictionary (keys: centers, x, y ),
    - d_matrix: array contaning the distances between each neuron
    - w: width of the map in inches
    - title: map title

    Returns the 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,  # a 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

我试着做一些能自动理解网格形状的东西。它没用(我也不知道为什么)。它总是在六边形之间出现一个不希望看到的空间

6x6

3 x 3

11 x 3

总结:我想生成3x3或6x6或10x4(等等)网格使用六边形之间没有空格为给定点和设置绘图宽度。在

按照要求,这是六边形位置的数据。正如你所看到的,它总是相同的模式

3x3

^{pr2}$

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.])}

Tags: the网格maptitleaxarraymatrixcollection
1条回答
网友
1楼 · 发布于 2024-05-17 04:35:10

我已经设法找到一个解决办法,根据给定的dpi计算出英寸的大小。之后,我计算两个相邻点之间的像素距离(通过使用隐藏散点图绘制)。这样我就可以计算出六边形apotem并正确估计六边形内圈的大小(正如matplotlib所期望的那样)。在

最后没有差距!在

import matplotlib.pyplot as plt
from matplotlib import colors, cm
from matplotlib.collections import RegularPolyCollection
from mpl_toolkits.axes_grid1 import make_axes_locatable
import math
import numpy as np

def plot_map(grid,
             d_matrix,
             w=1080,
            dpi=72.,
            title='SOM Hit map'):
"""
Plot hexagon map where each neuron is represented by a hexagon. The hexagon
color is given by the distance between the neurons (D-Matrix)

Args:
- grid: Grid dictionary (keys: centers, x, y ),
- d_matrix: array contaning the distances between each neuron
- w: width of the map in inches
- title: map title

Returns the 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')
# Get pixel size between to 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 is the lower left corner, whereas it's usually the
# upper right for most image software, so we'll flip the y-coords
width, height = fig.canvas.get_width_height()
ypix = height - ypix

# discover radius and hexagon
apothem = .9 * (xpix[1] - xpix[0]) / math.sqrt(3)
area_inner_circle = math.pi * (apothem ** 2)
collection_bg = RegularPolyCollection(
    numsides=6,  # a 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

相关问题 更多 >