Python:优化空间在饼图对应分区添加Genus标签的实现
饼图添加子类别(genus)标签实现方案
数据准备
首先创建示例DataFrame:
import matplotlib.pyplot as plt import pandas as pd import numpy as np # 示例数据 data = { 'genus': ['SpeciesA', 'SpeciesB', 'SpeciesC', 'SpeciesD', 'SpeciesE', 'SpeciesF', 'SpeciesG', 'SpeciesH'], 'count': [10, 2, 1, 1, 1, 1, 1, 1], 'Type': ['Animal', 'Environment', 'Environment', 'Environment', 'Animal', 'Animal', 'Animal/Environment', 'Animal/Environment'] } df = pd.DataFrame(data)
执行df后输出:
genus count Type 0 SpeciesA 10 Animal 1 SpeciesB 2 Environment 2 SpeciesC 1 Environment 3 SpeciesD 1 Environment 4 SpeciesE 1 Animal 5 SpeciesF 1 Animal 6 SpeciesG 1 Animal/Environment 7 SpeciesH 1 Animal/Environment
现有基础饼图代码
已实现按Type分组统计总count的基础饼图:
# 按Type分组求和 type_counts = df.groupby('Type')['count'].sum() # 绘制基础饼图 plt.figure(figsize=(8, 8)) plt.pie(type_counts, labels=type_counts.index, startangle=140) plt.title('按类型统计的数量分布') plt.axis('equal') # 保证饼图为圆形 plt.show()
需求目标
需要在饼图对应分区内添加genus标签,实现以下两种方式之一:
- (A) 优化空间,将标签无重叠地随机放置在对应饼图分区内;
- (B) 若无法实现(A),则采用分区内换行列出所属genus的规整标注方式。
方案A:分区内随机无重叠放置标签
通过获取饼图每个楔形分区的范围,在分区内部随机生成位置,并通过简单的距离检测避免标签重叠:
plt.figure(figsize=(8, 8)) # 绘制饼图,获取楔形对象和标签文本对象 wedges, texts = plt.pie(type_counts, labels=type_counts.index, startangle=140, wedgeprops={'linewidth': 1, 'edgecolor': 'white'}) plt.title('按类型统计的数量分布(含Genus标签)') plt.axis('equal') # 遍历每个Type分组,添加对应genus标签 for i, (type_name, group) in enumerate(df.groupby('Type')): wedge = wedges[i] # 获取当前分区的角度范围、中心位置和半径 theta_start, theta_end = wedge.theta1, wedge.theta2 center_x, center_y = wedge.center r = wedge.r # 定义标签放置的半径范围(分区内部0.3-0.7倍饼图半径) min_r = 0.3 * r max_r = 0.7 * r genus_list = group['genus'].tolist() placed_coords = [] # 记录已放置标签的坐标 for genus in genus_list: # 循环生成不重叠的位置 while True: # 在当前分区角度范围内随机选角度 rand_theta = np.radians(np.random.uniform(theta_start, theta_end)) # 在设定半径范围内随机选半径 rand_r = np.random.uniform(min_r, max_r) # 计算坐标 x = center_x + rand_r * np.cos(rand_theta) y = center_y + rand_r * np.sin(rand_theta) # 检查是否与已放置标签重叠(距离小于0.1倍半径则判定重叠) overlap = False for (px, py) in placed_coords: if np.sqrt((x - px)**2 + (y - py)**2) < 0.1 * r: overlap = True break if not overlap: placed_coords.append((x, y)) plt.text(x, y, genus, ha='center', va='center', fontsize=9) break plt.show()
方案B:分区内换行列出所属Genus
如果随机放置仍有重叠问题,或者需要更规整的展示效果,可以在每个分区的中心位置换行列出所有所属genus:
plt.figure(figsize=(8, 8)) wedges, texts = plt.pie(type_counts, labels=type_counts.index, startangle=140, wedgeprops={'linewidth': 1, 'edgecolor': 'white'}) plt.title('按类型统计的数量分布(含Genus标签)') plt.axis('equal') # 遍历每个Type分组,添加换行的genus标签 for i, (type_name, group) in enumerate(df.groupby('Type')): wedge = wedges[i] # 计算分区中心位置(取0.5倍半径处) mid_theta = np.radians((wedge.theta1 + wedge.theta2) / 2) x = wedge.center[0] + wedge.r * 0.5 * np.cos(mid_theta) y = wedge.center[1] + wedge.r * 0.5 * np.sin(mid_theta) # 将genus列表转为换行文本 genus_text = '\n'.join(group['genus'].tolist()) plt.text(x, y, genus_text, ha='center', va='center', fontsize=8) plt.show()
内容的提问来源于stack exchange,提问作者Grendel
相关产品推荐
相关产品推荐

