如何在Matplotlib饼图中按组explode多块扇区?
Matplotlib饼图实现按组拆分(Explode in Groups)功能
我非常喜欢Matplotlib饼图的explode选项,希望实现**按组拆分(explode in groups)**功能——绘制多个分属3-4个类别的小扇区,将同一类别的所有小扇区作为整体拆分出来。
数据格式与现有代码
# 数据格式示例 axis1 Unix A 3 B 1 D 1 Window C 30 Apple A 1 D 12 Linux A 10 C 20 import matplotlib.pyplot as plt import numpy as np fig, ax = plt.subplots() ax.set_aspect('equal') labels=["{0} {1}".format(l1, l2) for l1, l2 in data.index] wedges, texts, percs = ax.pie(data, labels=labels, autopct='%1.1f%%', shadow=True, radius=3) ax.axes.get_yaxis().set_visible(False)
尝试的代码及报错
我尝试了以下代码:
groups = ["{0}".format(l1, l2) for l1, l2 in data.index] for i in groups: ang = np.deg2rad((wedges[i[-1]].theta2 + wedges[i[0]].theta2)/2)
出现错误:"list indices must be integers or slices, not str"
期望效果:同一类别的扇区整体向外突出显示(类似分组拆分的饼图)
问题原因
wedges是Matplotlib返回的楔形对象列表,只能用整数索引访问,用字符串i去索引自然会报错。要实现按组拆分,核心是先给每个类别(比如A/B/C/D)分配对应的拆分距离,生成explode数组后传给pie函数。
解决方案代码
基础实现:按类别拆分
先整理数据,给目标类别的所有扇区设置拆分距离:
import matplotlib.pyplot as plt import pandas as pd import numpy as np # 把数据转为多层索引的DataFrame data = pd.DataFrame( [['Unix', 'A', 3], ['Unix', 'B', 1], ['Unix', 'D', 1], ['Window', 'C', 30], ['Apple', 'A', 1], ['Apple', 'D', 12], ['Linux', 'A', 10], ['Linux', 'C', 20]], columns=['OS', 'Category', 'Value'] ).set_index(['OS', 'Category']) fig, ax = plt.subplots() ax.set_aspect('equal') # 提取每个扇区对应的类别 categories = [idx[1] for idx in data.index] # 定义拆分规则:比如让A、D类别的扇区向外拆分0.1,其他类别不拆分 explode = [0.1 if cat in ['A', 'D'] else 0 for cat in categories] labels = ["{0} {1}".format(l1, l2) for l1, l2 in data.index] wedges, texts, percs = ax.pie( data['Value'], labels=labels, autopct='%1.1f%%', shadow=True, radius=3, explode=explode # 传入拆分数组 ) ax.axes.get_yaxis().set_visible(False) plt.show()
进阶优化:同一类别统一拆分方向
如果希望同一类别的所有扇区向同一个方向拆分(更贴合“整体拆分”的视觉效果),可以额外调整楔形的中心偏移:
# 按类别分组,记录每个类别对应的扇区索引 category_indices = {} for idx, cat in enumerate(categories): if cat not in category_indices: category_indices[cat] = [] category_indices[cat].append(idx) # 对目标类别的扇区统一调整拆分方向 for cat, indices in category_indices.items(): if cat in ['A', 'D']: # 计算该类别所有扇区的平均角度 avg_angle = np.mean([(wedges[i].theta1 + wedges[i].theta2)/2 for i in indices]) angle_rad = np.deg2rad(avg_angle) # 按平均角度计算偏移量 explode_dist = 0.1 offset_x = np.cos(angle_rad) * explode_dist offset_y = np.sin(angle_rad) * explode_dist # 逐个调整扇区的中心位置 for i in indices: wedges[i].set_center((offset_x, offset_y))
这样就能实现同一类别所有扇区作为整体向外拆分的效果,和期望的一致。
内容的提问来源于stack exchange,提问作者Andy Singal
相关产品推荐
相关产品推荐

