如何在Matplotlib子图间绘制线条/箭头关联饼图与堆叠柱状图?
如何在Matplotlib子图间添加连线/箭头关联饼图与堆叠柱状图?
我已经用Matplotlib创建了两个子图(饼图+堆叠柱状图),想添加线条或箭头,明确饼图的红色部分对应右侧的堆叠柱状图。
初始效果:
目标效果:
现有代码:
opfig, (ax1, ax2) = plt.subplots(1, 2, figsize = (12,6), dpi=80) percentage = operator['Percentage'] labels = operator['Operator'] explode = (0,0,0,0.1) label = [f'{lab}, {per:0.1f}%' for lab, per in zip(labels,percentage*100)] ax1.pie(operator['Count'], explode = explode) ax1.legend(labels=label, title='Operator Type') militaryPer = military['Percentage'] militaryLab = military["Military"] bottom = 1 width = 0.2 for j, (height, label) in enumerate([*zip(militaryPer, militaryLab)]): bottom -= height bc = ax2.bar(0, height, width, bottom = bottom, color="C0", label=label, alpha=0.1+0.25*j) ax2.bar_label(bc, labels=[F"{height:.0%}"], label_type='center') ax2.set_title('Military Operators') ax2.legend(loc='lower right', prop={'size': 10}, borderpad=1, framealpha=0.9) ax2.axis('off') ax2.set_xlim(-1.5 * width, 1.5 * width) plt.show()
实现方法
要添加关联的箭头/线条,核心是利用Matplotlib的ConnectionPatch工具,它可以跨子图连接两个点。具体步骤如下:
- 导入
ConnectionPatch模块:
from matplotlib.patches import ConnectionPatch
- 保存饼图的扇区对象:调用
pie()时会返回扇区(wedges)和文本对象,我们需要获取红色扇区(对应explode中第四个元素)的位置:
# 替换原ax1.pie行,保存返回值 wedges, texts = ax1.pie(operator['Count'], explode=explode) # 红色扇区是第四个(索引3) red_wedge = wedges[3]
- 获取两个子图中需要连接的点坐标:
- 饼图侧:取红色扇区的右侧边缘点,转换为figure全局坐标系
- 柱状图侧:取堆叠柱状图的左侧边缘点,同样转换为figure全局坐标系
- 创建并添加
ConnectionPatch:设置箭头样式、颜色等参数,添加到figure中。
修改后的完整代码
import matplotlib.pyplot as plt from matplotlib.patches import ConnectionPatch opfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,6), dpi=80) percentage = operator['Percentage'] labels = operator['Operator'] explode = (0,0,0,0.1) label = [f'{lab}, {per:0.1f}%' for lab, per in zip(labels,percentage*100)] # 保存饼图扇区对象 wedges, texts = ax1.pie(operator['Count'], explode=explode) ax1.legend(labels=label, title='Operator Type') militaryPer = military['Percentage'] militaryLab = military["Military"] bottom = 1 width = 0.2 for j, (height, label) in enumerate([*zip(militaryPer, militaryLab)]): bottom -= height bc = ax2.bar(0, height, width, bottom=bottom, color="C0", label=label, alpha=0.1+0.25*j) ax2.bar_label(bc, labels=[F"{height:.0%}"], label_type='center') ax2.set_title('Military Operators') ax2.legend(loc='lower right', prop={'size': 10}, borderpad=1, framealpha=0.9) ax2.axis('off') ax2.set_xlim(-1.5 * width, 1.5 * width) # 添加关联箭头 # 获取饼图红色扇区的右侧点(转换到figure坐标系) theta = (red_wedge.get_theta1() + red_wedge.get_theta2()) / 2 x_pie = red_wedge.get_center()[0] + (red_wedge.get_radius() + explode[3]) * plt.cos(theta * plt.pi / 180) y_pie = red_wedge.get_center()[1] + (red_wedge.get_radius() + explode[3]) * plt.sin(theta * plt.pi / 180) # 获取柱状图的左侧中间点 bar_x = -width/2 bar_y = 0.5 # 堆叠柱状图的中心位置,可根据实际调整 # 创建ConnectionPatch conn = ConnectionPatch( xyA=(x_pie, y_pie), coordsA=ax1.transData, xyB=(bar_x, bar_y), coordsB=ax2.transData, arrowstyle="->", linewidth=2, color="red", shrinkA=5, shrinkB=5 ) opfig.add_artist(conn) plt.show()
说明
arrowstyle参数可以调整箭头样式,比如"-"是直线,"->"是箭头,还可以自定义样式shrinkA和shrinkB用来设置箭头两端与图形的间距,避免紧贴扇区或柱子- 柱状图的y坐标
bar_y如果需要更精准,可以根据堆叠柱状图的总高度计算实际中心位置,比如用bottom + height/2取对应柱子的中心
内容的提问来源于stack exchange,提问作者kingmic
相关产品推荐
相关产品推荐

