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

如何为环形饼图内部饼块添加箭头标注?

环形饼图内部饼块添加箭头标注的修改方案

现有Matplotlib环形饼图代码仅能为外部饼块添加箭头链接的标注框,内部饼块无法实现该效果。以下是修改后的完整代码及关键调整说明:

import matplotlib.pyplot as plt
import numpy as np

def autopct_format(values):
    def my_format(pct):
        total = sum(values)
        val = int(round(pct*total/100.0)/1000000)
        if val == 0:
            return ""
        else:
            return '{:.1f}%\n({v:,d})'.format(pct, v=val)
    return my_format

fig, ax = plt.subplots(1,1,figsize=(10,10),dpi=100,layout="constrained")

ax.axis('equal')

width = 0.3
# 配色
A, B, C=[plt.cm.Blues, plt.cm.Reds, plt.cm.Greens]

# 外层饼图
cin = [A(0.5),A(0.4),A(0.3),B(0.5),B(0.4),B(0.3),B(0.2),B(0.1), C(0.5),C(0.4),C(0.3)]

Labels_Smalls = ['groupA', 'groupB', 'groupC']
labels = ['A.1', 'A.2', 'A.3', 'B.1', 'B.2', 'C.1', 'C.2', 'C.3', 
'C.4', 'C.5']
Sizes_Detail = [4,3,5,6,5,10,5,5,4,6]
Sizes = [12,11,30]

pie2, _ ,junk = ax.pie(Sizes_Detail ,radius=1,
                 labels=labels,labeldistance=0.85, 
                 autopct=autopct_format(Sizes_Detail) ,pctdistance = 1.15,
                 colors=cin)

for ea, eb in zip(pie2, _):
    mang =(ea.theta1 + ea.theta2)/2
    tourner = 360 - mang
    eb.set_rotation(mang+tourner)         # 旋转标签至对应角度
    eb.set_va("center")
    eb.set_ha("center")
    
plt.setp(pie2, width=width, edgecolor='white')

# 内层饼图
pie, _, junk = ax.pie(Sizes, radius=1-width, 
                autopct=autopct_format(Sizes) ,pctdistance = 0.8,
                colors = [A(0.6), B(0.6), C(0.6)])

plt.setp(pie, width=width, edgecolor='white')
plt.margins(0,0)

bbox_props = dict(boxstyle="square,pad=0.3", fc="w", ec="k", lw=0.72)
kw = dict(arrowprops=dict(arrowstyle="-"),
          bbox=bbox_props, zorder=3, va="center")

# 修改内层饼块的标注逻辑
for i, p in enumerate(pie):
    ang = (p.theta2 - p.theta1)/2. + p.theta1
    y = np.sin(np.deg2rad(ang))
    x = np.cos(np.deg2rad(ang))
    # 内层饼图半径为1-width,修正标注起点坐标,确保箭头指向内层饼块边缘
    inner_radius = 1 - width
    xy_pos = (x * inner_radius, y * inner_radius)
    horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
    connectionstyle = "angle,angleA=0,angleB={}".format(ang)
    kw["arrowprops"].update({"connectionstyle": connectionstyle})
    # 调整文本位置系数,避免与外层标注重叠
    ax.annotate(Labels_Smalls[i], xy=xy_pos, xytext=(1.25*np.sign(x), 1.3*y),
                horizontalalignment=horizontalalignment, **kw)
    
for ea, eb in zip(pie, _):
    mang =(ea.theta1 + ea.theta2)/2.  # 获取饼块的平均角度
    tourner = 360 - mang
    eb.set_rotation(mang+tourner)         # 旋转标签至对应角度
    eb.set_va("center")
    eb.set_ha("center")

plt.show()

关键修改说明

  • 标注起点修正:内层饼图的实际半径是1 - width,原代码直接使用(x,y)作为标注起点(对应半径1的位置),导致箭头指向外层饼块区域。修改后乘以内层半径,确保箭头准确连接到内层饼块的边缘。
  • 文本位置优化:微调xytext的系数(从1.35/1.4改为1.25/1.3),避免内层标注框与外层饼块的百分比文本重叠,提升整体布局的可读性。

内容的提问来源于stack exchange,提问作者TourEiffel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 18:01:06