You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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工具,它可以跨子图连接两个点。具体步骤如下:

  1. 导入ConnectionPatch模块:
from matplotlib.patches import ConnectionPatch
  1. 保存饼图的扇区对象:调用pie()时会返回扇区(wedges)和文本对象,我们需要获取红色扇区(对应explode中第四个元素)的位置:
# 替换原ax1.pie行,保存返回值
wedges, texts = ax1.pie(operator['Count'], explode=explode)
# 红色扇区是第四个(索引3)
red_wedge = wedges[3]
  1. 获取两个子图中需要连接的点坐标:
  • 饼图侧:取红色扇区的右侧边缘点,转换为figure全局坐标系
  • 柱状图侧:取堆叠柱状图的左侧边缘点,同样转换为figure全局坐标系
  1. 创建并添加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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:55:04