python - Matplotlib:在 hexbin 图中使用最常见值的 bin 组周围添加边框
问题描述
我正在使用以下 Python 脚本制作一个 hexbin 图:
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
)
上面的代码产生以下输出:
现在我想在六边形周围添加最常见值的边框,看起来像这样。请注意,在下图中,白色边框是手绘的,以显示结果的外观。我不知道该怎么做。我应该在代码中添加什么来产生这样的结果。
编辑:
我得到了一些结果,但它们并不完美,这是更新后的脚本:
## 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)
解决方案
我制定了两个版本来绘制六边形的等高线。
(标题)
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 ...
严格来说,“发光”为具有许多计数的六边形增添了亮点。
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)
注意:查找匹配的等高线取决于浮点精度np.unique(lines.round(5),...)
,这里是四舍五入到小数点后 4 位。根据输入数据,这可能需要进行调整。
推荐阅读
- python - tkinter 在一列中返回所有数据库列
- prometheus - Alertmanager 电子邮件通知不起作用
- python - 使用 python SMTP 向 Outlook/Microsoft 发送邮件会出现 SMTPAuthenticationError: Authentication unsuccessful
- next.js - Next.JS 重写没有发生
- c++ - 似乎无法使用数组指针进行第二个 for 循环
- javascript - 根据另一个输入框设置一个输入框的最大值
- java - 无法使用角色 ADMIN spring security 访问 url
- android - java.lang.IllegalStateException:回复已提交——尝试多次调用 result.success 时?
- robotframework - 我想在 HTML 页面上自动输入
- r - 最小化平均距离