如何在Matplotlib嵌套饼图中设置不同数量的子分类
解决Matplotlib嵌套饼图父类子分类数量自由设置的问题
原来的代码依赖二维numpy数组,要求每个父类的子分类数量必须一致,一旦子类数量不同就会触发AxisError。要实现自由设置各父类的子分类数量,核心是放弃二维numpy数组,改用普通列表的列表来存储数据,这样就能灵活处理不同长度的子分类,再分别计算父类总和、扁平化子类数据即可。
关键改动点:
- 用普通列表的列表替代二维numpy数组存储各父类的子分类数值,允许子列表长度不同
- 父类总和通过列表推导式计算:
[sum(sub_vals) for sub_vals in vals] - 子类数据扁平化用嵌套列表推导式:
[val for sublist in vals for val in sublist] - 对应调整子类标签、颜色的数量,匹配实际子分类个数
修改后的完整代码
import matplotlib.pyplot as plt import numpy as np fig, ax = plt.subplots() # 用列表的列表存储数据,允许各父类子分类数量不同 vals = [ [60., 32., 13.], # Car的3个子分类 [37., 40., 45.], # Public Transport的3个子分类 [29., 10., 35., 15., 12.] # Bike的5个子分类(新增Tricycle、Unicycle) ] cmap = plt.get_cmap("tab20c") outer_colors = cmap(np.arange(3)*4) # 3个父类对应3种颜色 # 11个子分类对应11种颜色(3+3+5),按父类分组选取 inner_colors = cmap([1,2,3, 5,6,7, 9,10,11,12,13]) # 绘制内圈(父类) ax.pie( [sum(sub) for sub in vals], # 计算每个父类的总和 radius=3-0.9, colors=outer_colors, wedgeprops=dict(width=0.9, edgecolor='w'), labels=["Car","Public Transport","Bike"], pctdistance=1.1, labeldistance=0.65 ) # 绘制外圈(子类) ax.pie( [val for sublist in vals for val in sublist], # 扁平化子类数据 radius=3, colors=inner_colors, wedgeprops=dict(width=0.9, edgecolor='w'), labels=["Gasoline","Diesel","Electric", "Bus","Tram","Train", "Normal Bike","E-Bike","Motorbike","Tricycle","Unicycle"], pctdistance=1.1, labeldistance=0.85 ) ax.set(aspect="equal", title='') plt.show()
为什么原来的代码会报错?
原来的代码用np.array()创建二维数组,当子列表长度不一致时,numpy会生成dtype=object的数组,此时调用sum(axis=1)会触发AxisError——因为object类型数组不支持按轴求和。改用普通列表处理后,就能避开numpy的这个限制,完全自由设置各父类的子分类数量。
内容的提问来源于stack exchange,提问作者Spooman11
相关产品推荐
相关产品推荐

