Matplotlib 饼图:Python 中创建饼图的完整指南
Updated on
创建有效的数据可视化对于清晰传达洞察至关重要。当你需要展示整体中的占比或百分比时,饼图会成为你可视化工具箱中的重要工具。然而,许多数据分析师在制作“看起来专业”的饼图时会遇到困难:如何正确突出关键扇区、如何选择合适的配色、如何准确显示百分比等。默认的 matplotlib 饼图往往显得朴素、缺少语境,也不擅长强调关键数据点。
当你要向需要快速理解市场份额分布、预算分配或问卷结果拆分的利益相关者进行展示时,这些可视化挑战会更为突出。一个设计不佳的饼图可能会“越看越糊涂”,从而导致对关键业务指标的误读。
Matplotlib 提供了功能全面的 plt.pie() 函数,拥有大量自定义选项,可以把基础的圆形图表升级为专业级可视化。本指南将演示如何从简单的占比饼图到复杂的嵌套分层图表逐步构建,并提供涵盖标签、颜色、分离扇区(explode)、甜甜圈图、以及与 pandas DataFrame 集成的真实工作流示例。
基础 Matplotlib 饼图语法
在 matplotlib 中创建饼图的基础是 plt.pie()。它只需要一个列表或数组,用来表示每个扇区的大小。
import matplotlib.pyplot as plt
# Basic pie chart data
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
# Create pie chart
plt.pie(sizes, labels=labels)
plt.title('Market Share Distribution')
plt.show()这会创建一个基础的圆形图表,其中扇区大小与 sizes 列表中的数值成比例。Matplotlib 会自动计算每个扇区的百分比与角度。图表颜色来自默认的颜色循环,但它不一定适合你的展示需求。
为了确保饼图呈现为标准圆形(而不是椭圆),请添加 plt.axis('equal'):
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
plt.pie(sizes, labels=labels)
plt.axis('equal') # Equal aspect ratio ensures circular shape
plt.title('Market Share Distribution')
plt.show()使用 autopct 显示百分比
autopct 参数可以自动格式化并在每个扇区上显示百分比,无需手动计算,让图表信息更完整。
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
plt.pie(sizes, labels=labels, autopct='%1.1f%%')
plt.axis('equal')
plt.title('Market Share with Percentages')
plt.show()格式字符串 '%1.1f%%' 会把百分比显示为 1 位小数:第一个 % 开启格式说明符,1.1f 表示小数点前 1 位、小数点后 1 位,%% 则用于输出字面量的百分号。
如果希望显示整数百分比(不带小数),使用 '%1.0f%%':
plt.pie(sizes, labels=labels, autopct='%1.0f%%')你也可以给 autopct 传入自定义函数,以更灵活地控制百分比展示:
import matplotlib.pyplot as plt
sizes = [350, 250, 200, 200]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
def make_autopct(values):
def my_autopct(pct):
total = sum(values)
val = int(round(pct * total / 100.0))
return f'{pct:.1f}%\n({val:d})'
return my_autopct
plt.pie(sizes, labels=labels, autopct=make_autopct(sizes))
plt.axis('equal')
plt.title('Market Share with Counts and Percentages')
plt.show()这样会在每个扇区同时显示百分比与实际计数。
自定义颜色与 Colormap
colors 参数可以接收一个颜色列表,用于覆盖 matplotlib 默认配色。你可以使用命名颜色、hex 色值或 RGB 元组。
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%')
plt.axis('equal')
plt.title('Market Share with Custom Colors')
plt.show()若希望基于数据生成颜色,可以使用 matplotlib 的 colormap:
import matplotlib.pyplot as plt
import numpy as np
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
# Generate colors from a colormap
cmap = plt.cm.Set3
colors = cmap(np.linspace(0, 1, len(sizes)))
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%')
plt.axis('equal')
plt.title('Market Share with Colormap')
plt.show()饼图常用的 colormap 包括 Set1、Set2、Set3、Pastel1、Pastel2 和 tab10。
使用 explode 强调扇区
explode 参数可以把某些扇区从中心“拉”出来,以强调关键数据点。explode 元组中每个值对应一个扇区的径向偏移量。
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
explode = (0.1, 0, 0, 0) # Explode the first slice
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%',
explode=explode)
plt.axis('equal')
plt.title('Market Share with Exploded Slice')
plt.show()0.1 会把第一个扇区向外移动半径的 10%。你也可以同时分离多个扇区:
explode = (0.1, 0.05, 0, 0) # Explode first two slices
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%',
explode=explode)添加阴影与设置起始角度
shadow 参数会添加投影以产生“立体”效果;startangle 用于旋转整张饼图,让扇区从指定角度开始绘制。
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
explode = (0.1, 0, 0, 0)
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%',
explode=explode, shadow=True, startangle=90)
plt.axis('equal')
plt.title('Market Share with Shadow and Rotation')
plt.show()startangle=90 会把图旋转到让第一个扇区从 90 度(圆的顶部)开始,而不是默认的 0 度(圆的右侧)。这有助于把重要扇区放在顶部,提升可见性。
创建甜甜圈图(Donut Charts)
甜甜圈图是在饼图中心挖空形成的环形图。可以通过 wedgeprops 参数设置扇形宽度来实现。
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
# Create donut chart
wedgeprops = {'width': 0.4}
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%',
wedgeprops=wedgeprops)
plt.axis('equal')
plt.title('Market Share Donut Chart')
plt.show()width=0.4 表示环的厚度为整体半径的 40%。值越小环越薄;接近 1.0 时会越来越接近普通饼图。
你也可以在甜甜圈中心添加文字:
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
wedgeprops = {'width': 0.4, 'edgecolor': 'white', 'linewidth': 2}
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%',
wedgeprops=wedgeprops)
plt.axis('equal')
# Add center text
plt.text(0, 0, 'Total\nSales', ha='center', va='center',
fontsize=14, fontweight='bold')
plt.title('Market Share Donut Chart')
plt.show()嵌套与同心饼图
通过绘制多个不同半径的饼图/甜甜圈图,你可以创建更复杂的可视化,用于表达层级关系数据。
import matplotlib.pyplot as plt
import numpy as np
# Outer ring data
outer_sizes = [35, 25, 20, 20]
outer_labels = ['Product A', 'Product B', 'Product C', 'Product D']
outer_colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
# Inner ring data (subcategories)
inner_sizes = [15, 20, 12, 13, 10, 10, 8, 12]
inner_labels = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2']
inner_colors = ['#ffcccc', '#ff6666', '#99ccff', '#3399ff',
'#ccffcc', '#66ff66', '#ffe6cc', '#ffb366']
fig, ax = plt.subplots()
# Outer pie
ax.pie(outer_sizes, labels=outer_labels, colors=outer_colors,
autopct='%1.1f%%', radius=1.2, wedgeprops={'width': 0.4})
# Inner pie
ax.pie(inner_sizes, labels=inner_labels, colors=inner_colors,
autopct='%1.0f%%', radius=0.8, wedgeprops={'width': 0.4})
ax.axis('equal')
plt.title('Nested Pie Chart: Products and Subcategories')
plt.show()这会生成两个同心的甜甜圈图:外环显示产品大类,内环显示外环各部分对应的子类。
添加图例(Legends)
当扇区较多或标签会造成拥挤时,可以把标签移到图例中,用 legend() 来展示。
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 15, 5]
labels = ['Product A', 'Product B', 'Product C', 'Product D', 'Others']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
plt.pie(sizes, colors=colors, autopct='%1.1f%%', startangle=90)
plt.axis('equal')
plt.legend(labels, loc='upper left', bbox_to_anchor=(1, 0, 0.5, 1))
plt.title('Market Share Distribution')
plt.tight_layout()
plt.show()bbox_to_anchor 用于把图例放到图表区域外侧。tight_layout() 会调整绘图区域,避免图例被裁剪。
如果希望图例中也包含百分比,可自定义图例文本:
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 15, 5]
labels = ['Product A', 'Product B', 'Product C', 'Product D', 'Others']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
wedges, texts, autotexts = plt.pie(sizes, colors=colors, autopct='%1.1f%%',
startangle=90)
plt.axis('equal')
# Create legend with labels and percentages
legend_labels = [f'{label} ({size}%)' for label, size in zip(labels, sizes)]
plt.legend(wedges, legend_labels, loc='upper left',
bbox_to_anchor=(1, 0, 0.5, 1))
plt.title('Market Share Distribution')
plt.tight_layout()
plt.show()饼图参数速查表
| Parameter | Type | Description | Example |
|---|---|---|---|
x | array-like | 扇区大小(必填) | [30, 25, 20, 25] |
labels | list of str | 每个扇区的文本标签 | ['A', 'B', 'C', 'D'] |
colors | list | 每个扇区的颜色 | ['red', 'blue', 'green'] |
autopct | str or function | 百分比格式字符串或函数 | '%1.1f%%' |
explode | tuple | 每个扇区的径向偏移 | (0.1, 0, 0, 0) |
shadow | bool | 是否添加投影 | True or False |
startangle | float | 旋转角度(度) | 90 |
radius | float | 饼图半径 | 1.0 (default) |
wedgeprops | dict | 扇形 patch 的属性 | {'width': 0.4} |
textprops | dict | 文本标签属性 | {'fontsize': 12} |
labeldistance | float | 标签到中心的距离 | 1.1 (default) |
pctdistance | float | 百分比文本到中心的距离 | 0.6 (default) |
counterclock | bool | 扇区绘制方向 | True (default) |
frame | bool | 是否绘制坐标轴边框 | False (default) |
自定义文本属性
textprops 参数可以统一控制饼图中的文字样式,包括标签和百分比文本。
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
textprops = {'fontsize': 14, 'fontweight': 'bold', 'color': 'darkblue'}
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%',
textprops=textprops)
plt.axis('equal')
plt.title('Market Share with Custom Text', fontsize=16, fontweight='bold')
plt.show()如果要分别控制标签与百分比文本,可以使用返回的文本对象:
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
wedges, texts, autotexts = plt.pie(sizes, labels=labels, colors=colors,
autopct='%1.1f%%')
# Customize label text
for text in texts:
text.set_fontsize(12)
text.set_fontweight('bold')
# Customize percentage text
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontsize(10)
autotext.set_fontweight('bold')
plt.axis('equal')
plt.title('Market Share with Styled Text')
plt.show()与 Pandas DataFrames 配合使用
在真实的数据分析中,你通常会使用 pandas DataFrame。你可以直接用 DataFrame 的列来绘制饼图。
import matplotlib.pyplot as plt
import pandas as pd
# Sample DataFrame
data = {
'Product': ['Product A', 'Product B', 'Product C', 'Product D'],
'Sales': [350000, 250000, 200000, 200000]
}
df = pd.DataFrame(data)
# Create pie chart from DataFrame
plt.pie(df['Sales'], labels=df['Product'], autopct='%1.1f%%',
startangle=90)
plt.axis('equal')
plt.title('Sales Distribution by Product')
plt.show()对于分组数据,可以先用 pandas 聚合再绘图:
import matplotlib.pyplot as plt
import pandas as pd
# Sample DataFrame with categories
data = {
'Region': ['North', 'South', 'East', 'West', 'North', 'South', 'East', 'West'],
'Product': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B'],
'Sales': [120000, 80000, 95000, 105000, 90000, 110000, 85000, 95000]
}
df = pd.DataFrame(data)
# Group by region and sum sales
region_sales = df.groupby('Region')['Sales'].sum()
plt.pie(region_sales.values, labels=region_sales.index, autopct='%1.1f%%',
startangle=90)
plt.axis('equal')
plt.title('Total Sales by Region')
plt.show()将饼图保存为文件
在调用 plt.show() 之前,使用 plt.savefig() 可以把饼图保存为多种格式。
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%')
plt.axis('equal')
plt.title('Market Share Distribution')
# Save as PNG with high DPI
plt.savefig('market_share.png', dpi=300, bbox_inches='tight')
# Save as PDF for vector graphics
plt.savefig('market_share.pdf', bbox_inches='tight')
# Save as SVG for web use
plt.savefig('market_share.svg', bbox_inches='tight')
plt.show()bbox_inches='tight' 会去掉图表周围多余空白。dpi 用于控制 PNG 等位图格式的分辨率。
真实案例:预算拆分
import matplotlib.pyplot as plt
import pandas as pd
# Annual budget data
budget_data = {
'Category': ['Salaries', 'Marketing', 'Operations', 'R&D', 'Infrastructure'],
'Amount': [450000, 180000, 120000, 150000, 100000]
}
df = pd.DataFrame(budget_data)
# Calculate total budget
total_budget = df['Amount'].sum()
# Define colors
colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#f9ca24', '#6c5ce7']
# Create pie chart
fig, ax = plt.subplots(figsize=(10, 7))
wedges, texts, autotexts = ax.pie(df['Amount'], labels=df['Category'],
colors=colors, autopct='%1.1f%%',
startangle=90, explode=(0.05, 0, 0, 0, 0))
# Customize text
for text in texts:
text.set_fontsize(12)
text.set_fontweight('bold')
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontsize(10)
autotext.set_fontweight('bold')
ax.axis('equal')
plt.title(f'Annual Budget Breakdown\nTotal: ${total_budget:,}',
fontsize=16, fontweight='bold', pad=20)
plt.tight_layout()
plt.savefig('budget_breakdown.png', dpi=300, bbox_inches='tight')
plt.show()真实案例:问卷结果
import matplotlib.pyplot as plt
import numpy as np
# Survey response data
responses = {
'Very Satisfied': 145,
'Satisfied': 230,
'Neutral': 85,
'Dissatisfied': 30,
'Very Dissatisfied': 10
}
labels = list(responses.keys())
sizes = list(responses.values())
total_responses = sum(sizes)
# Color scheme from red to green
colors = ['#2ecc71', '#3498db', '#95a5a6', '#e67e22', '#e74c3c']
fig, ax = plt.subplots(figsize=(10, 7))
wedges, texts, autotexts = ax.pie(sizes, labels=labels, colors=colors,
autopct=lambda pct: f'{pct:.1f}%\n({int(pct * total_responses / 100)})',
startangle=90, wedgeprops={'edgecolor': 'white', 'linewidth': 2})
for text in texts:
text.set_fontsize(11)
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontsize(9)
autotext.set_fontweight('bold')
ax.axis('equal')
plt.title(f'Customer Satisfaction Survey Results\nTotal Responses: {total_responses}',
fontsize=16, fontweight='bold', pad=20)
plt.tight_layout()
plt.show()真实案例:市场份额分析
import matplotlib.pyplot as plt
import pandas as pd
# Market share data for multiple quarters
data = {
'Company': ['Company A', 'Company B', 'Company C', 'Company D', 'Others'],
'Q1_Share': [28, 24, 18, 15, 15],
'Q2_Share': [30, 22, 19, 14, 15],
'Q3_Share': [32, 21, 18, 15, 14],
'Q4_Share': [35, 20, 17, 16, 12]
}
df = pd.DataFrame(data)
# Create subplots for each quarter
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
quarters = ['Q1_Share', 'Q2_Share', 'Q3_Share', 'Q4_Share']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
for idx, (ax, quarter) in enumerate(zip(axes.flat, quarters)):
wedges, texts, autotexts = ax.pie(df[quarter], labels=df['Company'],
colors=colors, autopct='%1.1f%%',
startangle=90)
for text in texts:
text.set_fontsize(10)
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontsize(9)
autotext.set_fontweight('bold')
ax.set_title(f'Market Share {quarter.replace("_Share", "")}',
fontsize=12, fontweight='bold')
plt.suptitle('Quarterly Market Share Analysis', fontsize=16, fontweight='bold', y=0.995)
plt.tight_layout()
plt.savefig('market_share_analysis.png', dpi=300, bbox_inches='tight')
plt.show()将饼图与其他可视化组合
通过把饼图与柱状图、折线图或表格组合,你可以制作更完整的仪表盘式展示。
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# Sample data
categories = ['Product A', 'Product B', 'Product C', 'Product D']
current_sales = [350000, 250000, 200000, 200000]
previous_sales = [320000, 280000, 180000, 220000]
# Create figure with subplots
fig = plt.figure(figsize=(14, 6))
# Pie chart showing current market share
ax1 = plt.subplot(1, 2, 1)
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
ax1.pie(current_sales, labels=categories, colors=colors, autopct='%1.1f%%',
startangle=90)
ax1.set_title('Current Market Share', fontsize=14, fontweight='bold')
# Bar chart showing comparison
ax2 = plt.subplot(1, 2, 2)
x = np.arange(len(categories))
width = 0.35
bars1 = ax2.bar(x - width/2, previous_sales, width, label='Previous Period',
color='#95a5a6', alpha=0.8)
bars2 = ax2.bar(x + width/2, current_sales, width, label='Current Period',
color='#3498db', alpha=0.8)
ax2.set_xlabel('Products', fontsize=12, fontweight='bold')
ax2.set_ylabel('Sales ($)', fontsize=12, fontweight='bold')
ax2.set_title('Sales Comparison', fontsize=14, fontweight='bold')
ax2.set_xticks(x)
ax2.set_xticklabels(categories)
ax2.legend()
ax2.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('combined_visualization.png', dpi=300, bbox_inches='tight')
plt.show()何时使用饼图 vs 柱状图
饼图适用于特定场景,但在许多情况下柱状图能提供更清晰的对比。
适合使用饼图的情况:
- 展示整体中的组成(百分比总和必须为 100%)
- 类别数不超过 5 个
- 需要强调 1~2 个占比明显更大的扇区
- 相比精确比例,更关注总体构成
- 制作高层汇报/管理摘要
适合使用柱状图的情况:
- 在类别之间做对比
- 类别超过 5 个
- 需要精确比较数值
- 数值并不构成有意义的“整体”
- 展示时间趋势
- 利益相关者需要对相近大小的类别进行比较
对比示例:
import matplotlib.pyplot as plt
data = {'Category A': 23, 'Category B': 19, 'Category C': 18,
'Category D': 17, 'Category E': 13, 'Category F': 10}
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
# Pie chart
ax1.pie(data.values(), labels=data.keys(), autopct='%1.1f%%', startangle=90)
ax1.set_title('Pie Chart: Harder to Compare Similar Values', fontweight='bold')
# Bar chart
ax2.bar(data.keys(), data.values(), color='#3498db')
ax2.set_ylabel('Value', fontweight='bold')
ax2.set_title('Bar Chart: Easier to Compare Similar Values', fontweight='bold')
ax2.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()柱状图能比饼图更清晰地呈现类别之间的细微差异。
使用 PyGWalker 创建交互式饼图
如果你的探索性分析需要交互式可视化,PyGWalker (opens in a new tab) 可以把 pandas DataFrame 转换为类似 Tableau 的交互界面,支持拖拽式创建饼图。
import pandas as pd
import pygwalker as pyg
# Sample DataFrame
data = {
'Product': ['Product A', 'Product B', 'Product C', 'Product D', 'Product E'],
'Sales': [350000, 250000, 200000, 200000, 150000],
'Region': ['North', 'South', 'East', 'West', 'North']
}
df = pd.DataFrame(data)
# Launch interactive visualization interface
walker = pyg.walk(df)PyGWalker 让不具备编码能力的业务分析师也能以交互方式制作饼图和其他图表、动态筛选数据并导出展示结果。它能够处理复杂聚合并提供内置统计摘要,非常适合在用 matplotlib 做最终产出前进行快速原型验证。
高级自定义:边缘颜色与线条样式
通过 wedgeprops 你可以设置边缘颜色和线宽,从而增强扇区之间的分隔感。
import matplotlib.pyplot as plt
sizes = [35, 25, 20, 20]
labels = ['Product A', 'Product B', 'Product C', 'Product D']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
wedgeprops = {
'edgecolor': 'black',
'linewidth': 2,
'linestyle': '-',
'antialiased': True
}
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%',
startangle=90, wedgeprops=wedgeprops)
plt.axis('equal')
plt.title('Market Share with Edge Styling')
plt.show()如果想要更柔和的效果,可以使用白色边缘:
wedgeprops = {'edgecolor': 'white', 'linewidth': 3}处理小扇区与标签重叠
当扇区较多且包含很多小扇区时,标签容易重叠。常见解决方案包括:改用图例、增大画布、或调整标签位置。
import matplotlib.pyplot as plt
# Data with several small slices
sizes = [30, 25, 15, 10, 8, 5, 4, 3]
labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
colors = plt.cm.Set3(range(len(sizes)))
fig, ax = plt.subplots(figsize=(10, 8))
wedges, texts, autotexts = ax.pie(sizes, colors=colors, autopct='%1.1f%%',
startangle=90, pctdistance=0.85)
# Remove labels from pie and use legend
for text in texts:
text.set_text('')
ax.legend(wedges, labels, title="Categories", loc="center left",
bbox_to_anchor=(1, 0, 0.5, 1))
ax.axis('equal')
ax.set_title('Distribution with Many Categories', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()另一种方式是只在图上显示百分比,用图例展示类别名称,从而减少视觉杂乱。
创建多环的比例甜甜圈图
构建更复杂的层级可视化,用多个环展示不同层级的拆分结果。
import matplotlib.pyplot as plt
import numpy as np
# Department budget data
departments = ['Engineering', 'Sales', 'Marketing', 'Operations']
dept_budgets = [400000, 300000, 200000, 100000]
# Team breakdown within departments
teams = ['Backend', 'Frontend', 'Mobile',
'Field Sales', 'Inside Sales',
'Digital', 'Content',
'Logistics', 'Support']
team_budgets = [200000, 150000, 50000,
180000, 120000,
120000, 80000,
60000, 40000]
fig, ax = plt.subplots(figsize=(12, 8))
# Outer ring (departments)
dept_colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12']
outer_pie = ax.pie(dept_budgets, labels=departments, colors=dept_colors,
autopct='%1.1f%%', radius=1.3, wedgeprops={'width': 0.35})
# Inner ring (teams)
team_colors = ['#c0392b', '#e74c3c', '#ec7063',
'#2980b9', '#3498db',
'#27ae60', '#2ecc71',
'#d68910', '#f39c12']
inner_pie = ax.pie(team_budgets, labels=teams, colors=team_colors,
autopct='%1.0f%%', radius=0.95,
wedgeprops={'width': 0.35}, labeldistance=0.7,
textprops={'fontsize': 9})
ax.axis('equal')
plt.title('Organizational Budget Breakdown\nDepartments and Teams',
fontsize=16, fontweight='bold', pad=20)
plt.tight_layout()
plt.show()这会生成两层甜甜圈:外环展示部门预算,内环展示与外环部门对应的团队预算。
常见问题(FAQ)
如何在 matplotlib 中创建基础饼图?
使用 plt.pie() 并传入数值列表与可选的标签。加入 plt.axis('equal') 以确保图形为圆而不是椭圆。基础语法是 plt.pie(sizes, labels=labels),再调用 plt.show() 显示图表。
matplotlib 饼图里的 autopct 参数有什么用?
autopct 会自动在每个扇区上显示百分比。可以使用 '%1.1f%%' 显示 1 位小数百分比,或 '%1.0f%%' 显示整数百分比。也可以传入自定义函数,同时显示百分比与实际值。
如何在 matplotlib 中创建甜甜圈图?
通过设置 wedgeprops 并将 width 设为小于 1 的值来创建甜甜圈图。例如 wedgeprops={'width': 0.4} 会生成环形宽度为半径 40% 的甜甜圈。结合 plt.text() 可在中心空白处添加文字。
如何把饼图中的某些扇区“拉出来”(explode)?
使用 explode 参数,并为每个扇区提供对应的偏移值。例如 explode=(0.1, 0, 0, 0) 会将第一个扇区向外移动半径的 10%,其他扇区保持不动。数值越大,分离越明显。
何时应该使用饼图而不是柱状图?
当你要展示“整体的组成”,且类别不超过 5 个并且百分比总和必须为 100% 时,适合用饼图。当你需要跨类别比较数值、类别超过 5 个,或更重视精确对比时,更建议使用柱状图。柱状图更容易比较相近的数值。
如何自定义 matplotlib 饼图颜色?
把颜色列表传入 colors 参数即可,可使用命名颜色、hex 色值或 RGB 元组。若要基于数据生成颜色,可结合 plt.cm.Set3 等 colormap 与 np.linspace() 生成颜色数组。饼图常用的 colormap 包括 Set1、Set2、Set3 和 Pastel1。
如何用图例替代扇区标签?
调用 plt.legend() 并用 loc 与 bbox_to_anchor 控制位置。例如:plt.legend(labels, loc='upper left', bbox_to_anchor=(1, 0, 0.5, 1)) 可将图例放在图表右侧区域外。配合 plt.tight_layout() 可防止图例被裁剪。
结论
在使用得当的前提下,Matplotlib 饼图是展示比例数据的有力方式。本指南涵盖了从基础饼图到高级嵌套甜甜圈可视化的完整范围,并通过实用示例演示了标签、配色、扇区分离、百分比展示以及与 DataFrame 集成等关键技巧。参数速查表可作为自定义配置的快速参考,而真实案例则展示了如何将这些方法应用到预算分析、问卷结果与市场份额报告中。
请记住:饼图更适合类别少且比例关系清晰的场景;如果需要更细致的对比,柱状图通常更合适。在分析阶段进行交互式探索时,PyGWalker 可作为无代码的快速原型方案,在你用 matplotlib 定稿生产级可视化之前提供高效验证。将这些 matplotlib 技巧与“何时用饼图/何时用柱状图”的设计判断结合起来,你就能制作出清晰、信息充分、能有效传达洞察的可视化作品。