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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 05:25:45