Matplotlib RegularPolygon在画布上的收集位置 [英] Matplotlib RegularPolygon collection location on the canvas

查看:566
本文介绍了Matplotlib RegularPolygon在画布上的收集位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用python绘制地图(SOM)。
为了简单起见,假设一个二维绘图,其中每个单位表示为六边形。



正如本主题所示: Python中的六边形自组织地图六边形位于并排格式作为一个网格。



我设法写下面的代码片段,它完全适用于设定数量的多边形,只有几个形状(6 x 6或10 x 4个六边形)。然而,这样的方法的一个重要特征是支持从3×3的任何网格形状。

  def plot_map b $ b d_matrix,
w = 10,
title ='SOM命中地图'):

绘制六边形地图,其中每个神经元由六边形表示。
颜色由神经元之间的距离(D矩阵)给定缩放
六边形将出现在背景图像的顶部是否提供hits数组
它们根据数字缩放
$ b Args:
- grid:Grid字典(键:centers,x,y),
- d_matrix:包含每个
神经元上的距离的数组每个神经元之间
- w:地图宽度,以英寸为单位
- title:地图标题

返回Matplotlib SubAxis实例

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')
#发现中心之间的差异
collection_bg = RegularPolyCollection $ b 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

我试图做一些自动理解网格形状的东西。它没有工作(我不知道为什么)。它总是在六边形之间出现一个不需要的空格。









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



正如它被问到的,这里是六边形位置的数据。您可以看到,它总是相同的模式



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

6x6

  { 'centers':array([[1.5,0.8660254],
[2.5,0.8660254],
[3.5,0.8660254],
[4.5,0.8660254],
[ 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] b $ b [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 ,
[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],
[ $ b [4.,5.19615242],
[5.,5.19615242],
[6.,5.19615242]],
'x':array([6.] b $ b'y':array([6.])}

strong>

  {'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.46410162],
[4.,3.46410162],
[5.,3.46410162],
[6.,3.46410162] $ b [8.,3.46410162],
[9.,3.46410162],
[10.,3.46410162],
[11.,3.46410162]]),
'x ':array([11.]),
'y':array([4.])}


解决方案

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



结尾没有缝隙!



import matplotlib.pyplot as plt
来自matplotlib导入颜色,cm
来自matplotlib.collections import RegularPolyCollection
来自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'):

绘制六边形地图,其中每个神经元由六边形表示。六边形
颜色通过神经元之间的距离(D矩阵)

Args:
- grid:网格字典(键:centers,x,y),
- d_matrix:每个神经元之间的距离
- w:地图宽度,以英寸为单位
- title:地图标题

返回Matplotlib SubAxis实例

n_centers = grid ['centers']
x,y = grid ['x'],grid ['y']
#以英寸为单位的图形尺寸
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')
#获取到数据点之间的像素大小
xpoints = n_centers [:, 0]
ypoints = n_centers [:, 1]
ax。 (xpoints,ypoints,s = 0.0,marker ='s')
ax.axis([min(xpoints)-1。,max(xpoints)+1。,
min 1.,max(ypoints)+1。])
xy_pixels = ax.transData.transform(np.vstack([xpoints,ypoints])。T)
xpix,ypix = xy_pixels.T

#在matplotlib中,0,0是左下角,而大多数图像软件通常是
#右上角,因此我们将翻转y-coords
width, height = fig.canvas.get_width_height()
ypix = height - ypix

#发现半径和六角形
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% = 0.05)
plt.colorbar(collection_bg,cax = cax)

return ax


I am trying to plot a feature map (SOM) using python. To keep it simple, imagine a 2D plot where each unit is represented as an hexagon.

As it is shown on this topic: Hexagonal Self-Organizing map in Python the hexagons are located side-by-side formated as a grid.

I manage to write the following piece of code and it works perfectly for a set number of polygons and for only few shapes (6 x 6 or 10 x 4 hexagons for example). However one important feature of a method like this is to support any grid shape from 3 x 3.

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

I've tried to make something that automatically understands the grid shape. It didn't work (and I'm not sure why). It always appear a undesired space between the hexagons

Summarising: I would like to generate 3x3 or 6x6 or 10x4 (and so on) grid using hexagons with no spaces in the between for given points and setting the plot width.

As it was asked, here is the data for the hexagons location. As you can see, it always the 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 to find a workaround by calculating the figure size of inches according the given dpi. After, I compute the pixel distance between two adjacent points (by plotting it using a hidden scatter plot). This way I could calculate the hexagon apothem and estimate correctly the size of the hexagon's inner circle (as the matplotlib expects).

No gaps in the end!

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

这篇关于Matplotlib RegularPolygon在画布上的收集位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆