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

如何在Matplotlib饼图中仅绘制特定扇区间的分隔线

饼图仅绘制特定扇区间分隔线的实现方案

需求说明

我需要在饼图中仅绘制特定扇区间的分隔线:

  • 当前图表:所有扇区间均有黑色分隔线,包括橙红色的allocated扇区与三文鱼色的padded扇区间
  • 目标图表:仅在不同类型的扇区间显示黑色分隔线,取消allocated与padded扇区间的分隔线

已尝试方法及问题

  1. 通过wedgeprops设置扇区边缘:
wedges = plt.pie(sizes, labels=labels, colors=colours, autopct='%1.1f%%')
for wedge in wedges[0]:
    wedge.set_lw(0.5)
    wedge.set_edgecolor("black")

问题:该设置会作用于扇区的整个边缘,无法单独控制某一条边的显示。

  1. 使用Circle绘制轮廓圆:
circle = matplotlib.patches.Circle(center, radius, fill=False, edgecolor="k", linewidth=2)
ax.add_patch(circle)

问题:只能绘制完整外轮廓,无法绘制特定扇区间的分隔线;已知matplotlib.lines.Line2D但不清楚如何在饼图场景中应用。

我的完整代码

def graph_memory_layout(memory_layout):
    # Format: F(ree)/A(llocated)[number of bytes]P(adding)[number of bytes] [space] [next entry]

    # Extract infomation
    layout = memory_layout.split()
    colours = []
    sizes=[]

    for memory in layout:
        first_char = memory[0]
        if (first_char == 'A'):
            allocated_bytes = 0
            padded_bytes = 0
            padded_flag = None

            for i, char in enumerate(memory[1:]):
                if char == 'P':
                    padded_flag = i + 1

            allocated_bytes = int(memory[1:padded_flag])
            padded_bytes = int(memory[padded_flag + 1:])

            payload_bytes = allocated_bytes - padded_bytes
            sizes.append(payload_bytes)
            colours.append(ALLOCATED_COLOUR)

            if padded_bytes is not 0:
                sizes.append(padded_bytes)
                colours.append(PADDED_COLOUR)
                # 这里可以记录哪些相邻扇区不需要分隔线,后续使用
            
        elif (first_char == 'F'):
            sizes.append(memory[1:])
            colours.append(FREE_COLOUR)

    # Create pie chart 
    wedges = plt.pie(sizes, colors=colours)
    for wedge in wedges[0]:
        wedge.set_lw(0.5)
        wedge.set_edgecolor("black")

    plt.axis("equal")
    plt.title("Memory Layout")

     # Draw the chart
    plt.show()

解决方案

核心思路

  1. 数据解析阶段:记录不需要分隔线的相邻扇区索引对(即allocated紧跟padded的情况)
  2. 饼图绘制阶段:先移除所有扇区的默认边缘线
  3. 按需绘制分隔线:遍历所有扇区分隔线角度,仅保留需要显示的分隔线,跳过标记的无分隔线位置

修改后的完整代码

import matplotlib.pyplot as plt
import numpy as np

# 定义颜色常量
ALLOCATED_COLOUR = 'orangered'
PADDED_COLOUR = 'salmon'
FREE_COLOUR = 'lightblue'

def graph_memory_layout(memory_layout):
    # Format: F(ree)/A(llocated)[number of bytes]P(adding)[number of bytes] [space] [next entry]

    # Extract infomation
    layout = memory_layout.split()
    colours = []
    sizes = []
    # 记录不需要分隔线的相邻扇区索引对
    no_divider_pairs = []
    current_idx = 0

    for memory in layout:
        first_char = memory[0]
        if first_char == 'A':
            padded_flag = memory.index('P')
            allocated_bytes = int(memory[1:padded_flag])
            padded_bytes = int(memory[padded_flag + 1:])

            payload_bytes = allocated_bytes - padded_bytes
            sizes.append(payload_bytes)
            colours.append(ALLOCATED_COLOUR)
            
            if padded_bytes != 0:
                sizes.append(padded_bytes)
                colours.append(PADDED_COLOUR)
                # 标记当前allocated扇区与下一个padded扇区间不需要分隔线
                no_divider_pairs.append((current_idx, current_idx + 1))
                current_idx += 1
            current_idx += 1
            
        elif first_char == 'F':
            sizes.append(int(memory[1:]))  # 转换为数值类型,避免绘图报错
            colours.append(FREE_COLOUR)
            current_idx += 1

    # 转换为浮点数组,计算角度
    sizes = np.array(sizes, dtype=float)
    angle_percent = sizes / sizes.sum() * 360
    # 生成每个扇区的起始角度(包含初始0度)
    angles = np.insert(np.cumsum(angle_percent), 0, 0)

    # 绘制饼图,先移除所有默认边缘线
    wedges, _ = plt.pie(sizes, colors=colours, wedgeprops={'edgecolor': 'none'})

    # 绘制需要保留的分隔线
    ax = plt.gca()
    radius = 1  # 饼图默认半径为1
    for i in range(len(angles)-1):
        # 检查当前分隔线是否属于需要跳过的对
        skip = False
        for pair in no_divider_pairs:
            if pair[0] == i or pair[1] == i:
                skip = True
                break
        if skip:
            continue
        # 角度转弧度,计算线的端点坐标
        theta = angles[i] * np.pi / 180
        line = plt.Line2D([0, radius*np.cos(theta)], 
                          [0, radius*np.sin(theta)], 
                          color='black', linewidth=0.5)
        ax.add_line(line)

    # 绘制饼图外轮廓
    circle = plt.Circle((0, 0), radius, fill=False, edgecolor='black', linewidth=0.5)
    ax.add_patch(circle)

    plt.axis("equal")
    plt.title("Memory Layout")
    plt.show()

代码说明

  1. 数据标记:新增no_divider_pairs列表,精准记录不需要分隔线的扇区组合
  2. 角度计算:通过扇区占比计算每个扇区的起始角度,为绘制分隔线提供坐标依据
  3. 按需画线:使用Line2D从圆心到边缘绘制分隔线,跳过标记的无分隔线位置,最后补充外轮廓保证整体视觉完整

内容的提问来源于stack exchange,提问作者Wzrd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:16:15