如何为环形饼图内部饼块添加箭头标注?
环形饼图内部饼块添加箭头标注的修改方案
现有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
相关产品推荐
相关产品推荐

