Matplotlib:在六角形图中最常见值的一组条形图周围添加边框

5

我正在使用以下Python脚本制作六边形图:

pitch = Pitch(
    line_color="#747474", pitch_color="#222222", orientation="vertical", half=True, plot_arrow=False
)

fig, ax = pitch.create_pitch()

## color-map
cmap = [
    "#222222", "#3A2527", "#52282B", "#6A2B30", 
    "#762C32", "#822D34", "#8E2F37", "#9A3039", 
    "#B2323D", "#BE3440", "#CA3542", "#E13746"
]
cmap = colors.ListedColormap(cmap)

hexbin = ax.hexbin(
    68 - shots_data['Y'], shots_data['X'], zorder=3, cmap=cmap,
    extent=(0, 68, 52, 104), gridsize=22, bins=13, ec="#222222", lw=3
)

上面的代码生成以下输出:

enter image description here

现在,我想要为出现最频繁的六边形添加边框,效果类似于下图。请注意,在下面的图片中,白色边框是手绘的,仅用于展示结果的外观。我不知道如何实现这一点。我应该在代码中添加什么以产生这样的结果。 enter image description here 编辑:
我得到了一些结果,但它们并不完美,以下是更新后的脚本:
## Pitch obejct
pitch = Pitch(
    line_color="#747474", pitch_color="#222222", orientation="vertical", half=True, plot_arrow=False
)

## create-pitch
fig, ax = pitch.create_pitch()

## colormap
cmap = [
    "#3A2527", "#52282B", "#6A2B30", "#822D34",
    "#822D34","#882E36", "#8E2F37", "#9A3039", "#B2323D", "#E13746"
]
cmap = colors.ListedColormap(cmap)

## extent
extent = (
    shots_data['Y'].min(), shots_data['Y'].max(),
    shots_data['X'].min(), shots_data['X'].max(),
)

## main hexbin
hexbin = ax.hexbin(
    68 - shots_data['Y'], shots_data['X'], zorder=3, cmap=cmap,
    extent=extent, gridsize=22, ec="#222222", lw=1, bins="log", mincnt=1
)

## hexbin with mincnt=6
cmap = [
     "#822D34", "#882E36", "#8E2F37", "#9A3039", "#B2323D", "#E13746"
]
cmap = colors.ListedColormap(cmap)
ax.hexbin(
    68 - shots_data['Y'], shots_data['X'], zorder=3, cmap=cmap,
    extent=extent, gridsize=22, ec="#bce7ef", lw=1, bins="log", mincnt=6
)


## add rectangle 
rect = plt.Rectangle(
    xy=(-0.1, 104), width=68.1, height=1, zorder=3, fc="#222222"
)
ax.add_patch(rect)

这将产生以下结果:

在此输入图片描述


请在这里查看。 - Patol75
1个回答

2
我为绘制六边形轮廓线提出了两个版本。
(标题)
import numpy as np, matplotlib.pyplot as plt, matplotlib.colors

# color-map
cmap = [ "#222222", "#3A2527", "#52282B", "#6A2B30", "#762C32", "#822D34", 
        "#8E2F37", "#9A3039", "#B2323D", "#BE3440", "#CA3542", "#E13746"]
cmap = matplotlib.colors.ListedColormap(cmap)

#prepare data
np.random.seed(10)
shotsX = np.random.randn(1000)*20+10
shotsY = np.random.randn(1000)*15+50

#original plot
cfg = dict(x=shotsX, y=shotsY, cmap=cmap, gridsize=22, extent=[0,100,0,100])
h   = plt.hexbin( ec="#222222",lw=2,zorder=-3,**cfg)
plt.axis('off');

1) 白色发光

这种方法类似于您的编辑。多次调用plt.hexbin并使用不同的线条样式以及参数mincnt

#draw thick white contours + overlay previous style
cfg = {**cfg,'vmin':h.get_clim()[0], 'vmax':h.get_clim()[1]}
plt.hexbin( ec="white"  ,lw=5,zorder=-2,mincnt=10,**cfg)
plt.hexbin( ec="#222222",lw=2,zorder=-1,mincnt=10,**cfg)
plt.xlim(-3,103) #required as second call of plt.hexbin()
plt.ylim(-3,103) #strangely affects the limits ...

enter image description here

严格来说,“glow”会为拥有许多计数的六边形添加高亮。

2) 轮廓线

仅在原始六边形上方绘制白色轮廓线更加复杂。您可以通过以下方式解决:

  • 找到六边形的顶点(即中心)
  • 对于每个顶点,计算线段
  • 提取外部线条
  • 绘制
def hexLines(a=None,i=None,off=[0,0]):
    '''regular hexagon segment lines as `(xy1,xy2)` in clockwise 
    order with points in line sorted top to bottom
    for irregular hexagon pass both `a` (vertical) and `i` (horizontal)'''
    if a is None: a = 2 / np.sqrt(3) * i;    
    if i is None: i = np.sqrt(3) / 2 * a;     
    h  = a / 2 
    xy = np.array([ [ [ 0, a], [ i, h] ], 
                    [ [ i, h], [ i,-h] ], 
                    [ [ i,-h], [ 0,-a] ], 
                    [ [-i,-h], [ 0,-a] ], #flipped
                    [ [-i, h], [-i,-h] ], #flipped
                    [ [ 0, a], [-i, h] ]  #flipped
                  ])  
    return xy+off;


#get hexagon centers that should be highlighted
verts = h.get_offsets()
cnts  = h.get_array()
highl = verts[cnts > .5*cnts.max()]

#create hexagon lines
a = ((verts[0,1]-verts[1,1])/3).round(6)
i = ((verts[1:,0]-verts[:-1,0])/2).round(6)
i = i[i>0][0]
lines = np.concatenate([hexLines(a,i,off) for off in highl])

#select contour lines and draw
uls,c = np.unique(lines.round(4),axis=0,return_counts=True)
for l in uls[c==1]: plt.plot(*l.transpose(),'w-',lw=2,scalex=False,scaley=False)

enter image description here

注意:查找匹配的轮廓线取决于浮点精度np.unique(lines.round(5),...),这里精确到4位小数。根据输入数据的不同,可能需要进行调整。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接