Matplotlib中如何制作放射状偏移的饼图
参考:Radially displace pie chart wedge in Matplotlib
Matplotlib是Python中强大的数据可视化库,它提供了丰富的绘图功能,其中包括制作饼图。在某些情况下,我们可能需要创建一个特殊的饼图,其中某些扇区被放射状地偏移,以突出显示或区分特定的数据。本文将详细介绍如何在Matplotlib中制作放射状偏移的饼图,包括基本概念、实现方法、常见问题及解决方案。
1. 饼图基础
在开始制作放射状偏移的饼图之前,我们先回顾一下Matplotlib中创建基本饼图的方法。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
# 创建饼图
plt.figure(figsize=(8, 8))
plt.pie(sizes, labels=labels, autopct='%1.1f%%')
plt.title('Basic Pie Chart - how2matplotlib.com')
plt.axis('equal')
plt.show()
Output:
这个示例创建了一个简单的饼图,其中包含5个扇区,每个扇区都有相应的标签和百分比显示。
2. 放射状偏移的概念
放射状偏移是指将饼图中的某个或某些扇区沿着半径方向向外移动一定距离。这种技术可以用来强调特定的数据点,或者使饼图在视觉上更加吸引人。
3. 实现放射状偏移
要实现放射状偏移,我们需要使用Matplotlib的wedgeprops
参数。这个参数允许我们为每个扇区设置特定的属性,包括偏移距离。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
# 创建偏移
explode = (0, 0.1, 0, 0, 0) # 只偏移第二个扇区
plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%')
plt.title('Radially Displaced Pie Chart - how2matplotlib.com')
plt.axis('equal')
plt.show()
Output:
在这个例子中,我们使用explode
参数来指定每个扇区的偏移量。值为0表示不偏移,正值表示向外偏移的距离。
4. 自定义偏移距离
我们可以通过调整explode
参数中的值来自定义每个扇区的偏移距离。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
# 自定义偏移
explode = (0.1, 0.2, 0.05, 0.15, 0)
plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%')
plt.title('Custom Radial Displacement - how2matplotlib.com')
plt.axis('equal')
plt.show()
Output:
这个例子展示了如何为每个扇区设置不同的偏移距离,创造出更加动态的视觉效果。
5. 结合颜色和样式
放射状偏移可以与其他饼图样式选项结合使用,如自定义颜色、阴影和边框。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
# 偏移和样式
explode = (0, 0.1, 0, 0.05, 0)
plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', shadow=True, startangle=90)
plt.title('Styled Radially Displaced Pie Chart - how2matplotlib.com')
plt.axis('equal')
plt.show()
Output:
这个示例展示了如何结合使用自定义颜色、阴影效果和起始角度,同时应用放射状偏移。
6. 添加图例
对于复杂的饼图,添加图例可以提高可读性。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['Category A', 'Category B', 'Category C', 'Category D', 'Category E']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
# 偏移
explode = (0, 0.1, 0, 0.05, 0)
plt.figure(figsize=(10, 8))
plt.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', startangle=90)
plt.title('Pie Chart with Legend - how2matplotlib.com')
plt.legend(labels, title="Categories", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1))
plt.axis('equal')
plt.tight_layout()
plt.show()
Output:
这个例子展示了如何添加一个位于图表右侧的图例,使得饼图更加易于理解。
7. 动态偏移计算
有时,我们可能想根据数据值动态计算偏移量。以下是一个根据数据大小计算偏移的例子:
import matplotlib.pyplot as plt
import numpy as np
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
# 动态计算偏移
max_size = max(sizes)
explode = [0.05 * (size / max_size) for size in sizes]
plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%')
plt.title('Dynamic Radial Displacement - how2matplotlib.com')
plt.axis('equal')
plt.show()
Output:
这个示例根据每个扇区的大小动态计算偏移量,使得较大的扇区偏移更多。
8. 突出显示特定扇区
有时我们可能想要突出显示某个特定的扇区。这可以通过结合使用偏移和颜色来实现。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
# 突出显示第三个扇区
explode = [0.05 if i == 2 else 0 for i in range(len(sizes))]
colors[2] = '#ff0000' # 将第三个扇区设置为红色
plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', startangle=90)
plt.title('Highlighting Specific Wedge - how2matplotlib.com')
plt.axis('equal')
plt.show()
Output:
这个例子展示了如何通过偏移和颜色变化来突出显示特定的扇区(在这里是第三个扇区)。
9. 添加注释
对于放射状偏移的饼图,我们可能想要为某些扇区添加额外的注释信息。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
# 偏移
explode = (0, 0.1, 0, 0, 0)
fig, ax = plt.subplots(figsize=(10, 8))
wedges, texts, autotexts = ax.pie(sizes, explode=explode, labels=labels,
autopct='%1.1f%%', startangle=90)
# 添加注释
ax.annotate('Important!', xy=(0.3, 0.5), xytext=(0.7, 0.7),
arrowprops=dict(facecolor='black', shrink=0.05))
plt.title('Pie Chart with Annotation - how2matplotlib.com')
plt.axis('equal')
plt.show()
Output:
这个示例展示了如何为偏移的扇区添加文本注释和箭头。
10. 多层饼图
我们可以创建多层饼图,其中某些层具有放射状偏移。
import matplotlib.pyplot as plt
# 数据
sizes_outer = [30, 20, 25, 15, 10]
sizes_inner = [20, 30, 15, 25, 10]
labels_outer = ['A', 'B', 'C', 'D', 'E']
labels_inner = ['1', '2', '3', '4', '5']
# 偏移
explode_outer = (0, 0.1, 0, 0, 0)
fig, ax = plt.subplots(figsize=(10, 8))
# 外层饼图
ax.pie(sizes_outer, explode=explode_outer, labels=labels_outer,
autopct='%1.1f%%', radius=1, startangle=90)
# 内层饼图
ax.pie(sizes_inner, labels=labels_inner, autopct='%1.1f%%',
radius=0.6, startangle=90)
plt.title('Multi-layer Pie Chart with Radial Displacement - how2matplotlib.com')
ax.axis('equal')
plt.show()
Output:
这个例子展示了如何创建一个双层饼图,其中外层有放射状偏移,而内层没有。
11. 动画效果
我们可以创建一个动画,展示扇区从未偏移状态逐渐偏移到最终位置的过程。
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
# 最终偏移
final_explode = (0, 0.2, 0, 0.1, 0)
fig, ax = plt.subplots(figsize=(8, 8))
def animate(frame):
current_explode = tuple(f * frame / 100 for f in final_explode)
ax.clear()
ax.pie(sizes, explode=current_explode, labels=labels, autopct='%1.1f%%')
ax.set_title('Animated Radial Displacement - how2matplotlib.com')
ax.axis('equal')
ani = animation.FuncAnimation(fig, animate, frames=100, interval=50, repeat=False)
plt.show()
Output:
这个示例创建了一个动画,展示扇区从初始位置逐渐移动到最终偏移位置的过程。
12. 自定义扇区样式
我们可以为每个扇区自定义更多的样式属性,如边框颜色、线宽等。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
# 偏移和样式
explode = (0, 0.1, 0, 0.05, 0)
wedgeprops = {'linewidth': 3, 'edgecolor': 'white'}
plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', startangle=90, wedgeprops=wedgeprops)
plt.title('Custom Wedge Styles - how2matplotlib.com')
plt.axis('equal')
plt.show()
Output:
这个例子展示了如何为饼图的每个扇区添加自定义的边框样式。
13. 结合条形图
我们可以创建一个组合图表,将放射状偏移的饼图与条形图结合起来。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
explode = (0, 0.1, 0, 0.05, 0)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 7))
# 饼图
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', startangle=90)
ax1.set_title('Pie Chart - how2matplotlib.com')
# 条形图
ax2.bar(labels, sizes)
ax2.set_title('Bar Chart - how2matplotlib.com')
ax2.set_ylabel('Values')
plt.tight_layout()
plt.show()
Output:
这个示例展示了如何在同一个图表中结合使用放射状偏移的饼图和相应的条形图。
14. 3D 效果
虽然Matplotlib主要用于2D绘图,但我们可以通过一些技巧来创造3D效果的放射状偏移饼图。
import matplotlib.pyplot as plt
import numpy as np
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
colors = plt.cm.Spectral(np.linspace(0, 1, len(sizes)))
# 创建3D效果
explode = (0.1, 0.2, 0.1, 0.15, 0.1)
angle = np.linspace(0, 2*np.pi, len(sizes), endpoint=False)
width = np.pi / 4 * np.random.rand(len(sizes))
fig, ax = plt.subplots(figsize=(10, 8), subplot_kw=dict(projection='3d'))
ax.bar3d(angle, [0]*len(sizes), [0]*len(sizes), width, sizes, explode,
color=colors, alpha=0.8)
plt.title('3D-like Pie Chart - how2matplotlib.com')
ax.set_axis_off()
plt.show()
Output:
这个示例创建了一个具有3D效果的饼图,通过使用bar3d
函数和适当的角度计算来模拟3D饼图的外观。
15. 交互式饼图
我们可以使用Matplotlib的交互式功能来创建一个可以动态调整偏移量的饼图。
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 10), gridspec_kw={'height_ratios': [4, 1]})
# 初始饼图
explode = [0] * len(sizes)
pie = ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', startangle=90)
ax1.set_title('Interactive Radial Displacement - how2matplotlib.com')
# 滑块
slider_ax = ax2
slider = Slider(slider_ax, 'Explode', 0, 0.5, valinit=0)
def update(val):
explode = [val if i == 1 else 0 for i in range(len(sizes))] # 只偏移第二个扇区
ax1.clear()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', startangle=90)
ax1.set_title('Interactive Radial Displacement - how2matplotlib.com')
slider.on_changed(update)
plt.tight_layout()
plt.show()
Output:
这个示例创建了一个交互式饼图,用户可以通过滑块来调整第二个扇区的偏移量。
16. 数据驱动的动态偏移
我们可以根据数据的特定属性来动态计算偏移量。
import matplotlib.pyplot as plt
import numpy as np
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
importance = [5, 8, 3, 6, 2] # 重要性评分
# 计算偏移量
max_importance = max(importance)
explode = [0.1 * (imp / max_importance) for imp in importance]
plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
startangle=90, colors=plt.cm.Pastel1(np.arange(len(sizes))))
plt.title('Data-Driven Radial Displacement - how2matplotlib.com')
plt.axis('equal')
plt.show()
Output:
这个例子展示了如何根据每个类别的”重要性”分数来动态计算偏移量。
17. 带有子图的复杂布局
我们可以创建一个更复杂的布局,包含多个放射状偏移的饼图作为子图。
import matplotlib.pyplot as plt
# 数据
data = {
'2020': [30, 20, 25, 15, 10],
'2021': [25, 22, 28, 15, 10],
'2022': [20, 25, 30, 15, 10]
}
labels = ['A', 'B', 'C', 'D', 'E']
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
for i, (year, sizes) in enumerate(data.items()):
explode = [0.1 if s == max(sizes) else 0 for s in sizes]
axes[i].pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', startangle=90)
axes[i].set_title(f'{year} - how2matplotlib.com')
plt.suptitle('Yearly Comparison with Radial Displacement', fontsize=16)
plt.tight_layout()
plt.show()
Output:
这个示例创建了一个包含三个子图的图表,每个子图都是一个放射状偏移的饼图,代表不同年份的数据。
18. 结合文本注释
我们可以为放射状偏移的饼图添加更详细的文本注释。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
explode = (0, 0.1, 0, 0, 0)
fig, ax = plt.subplots(figsize=(10, 8))
wedges, texts, autotexts = ax.pie(sizes, explode=explode, labels=labels,
autopct='%1.1f%%', startangle=90)
# 添加注释
bbox_props = dict(boxstyle="round,pad=0.3", fc="w", ec="k", lw=0.72)
kw = dict(arrowprops=dict(arrowstyle="->"),
bbox=bbox_props, zorder=0, va="center")
for i, p in enumerate(wedges):
ang = (p.theta2 - p.theta1) / 2. + p.theta1
y = np.sin(np.deg2rad(ang))
x = np.cos(np.deg2rad(ang))
horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
connectionstyle = f"angle,angleA=0,angleB={ang}"
kw["arrowprops"].update({"connectionstyle": connectionstyle})
ax.annotate(f"Category {labels[i]}\nValue: {sizes[i]}",
xy=(x, y), xytext=(1.35*np.sign(x), 1.4*y),
horizontalalignment=horizontalalignment, **kw)
plt.title('Detailed Annotations - how2matplotlib.com')
plt.show()
这个示例展示了如何为每个扇区添加详细的文本注释,包括类别名称和具体数值。
19. 自定义颜色映射
我们可以使用自定义的颜色映射来为放射状偏移的饼图着色。
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
explode = (0, 0.1, 0, 0.05, 0)
# 创建自定义颜色映射
colors = ['#FF9999', '#66B3FF', '#99FF99', '#FFCC99', '#FF99CC']
cmap = mcolors.ListedColormap(colors)
plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, colors=cmap(np.arange(len(sizes))),
autopct='%1.1f%%', startangle=90)
plt.title('Custom Color Map - how2matplotlib.com')
plt.axis('equal')
plt.show()
这个例子展示了如何使用自定义的颜色列表创建颜色映射,并将其应用于放射状偏移的饼图。
20. 带有图例和标题的完整饼图
最后,让我们创建一个包含所有元素的完整饼图,包括放射状偏移、自定义颜色、图例和详细标题。
import matplotlib.pyplot as plt
# 数据
sizes = [30, 20, 25, 15, 10]
labels = ['Category A', 'Category B', 'Category C', 'Category D', 'Category E']
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
explode = (0, 0.1, 0, 0.05, 0)
plt.figure(figsize=(12, 8))
wedges, texts, autotexts = plt.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', startangle=90, pctdistance=0.85)
# 添加中心空白
centre_circle = plt.Circle((0, 0), 0.70, fc='white')
fig = plt.gcf()
fig.gca().add_artist(centre_circle)
# 自定义字体大小
plt.setp(autotexts, size=8, weight="bold")
plt.setp(texts, size=10)
# 添加图例
plt.legend(wedges, labels,
title="Categories",
loc="center left",
bbox_to_anchor=(1, 0, 0.5, 1))
plt.title("Comprehensive Radially Displaced Pie Chart\nhow2matplotlib.com", fontsize=16)
plt.axis('equal')
plt.tight_layout()
plt.show()
Output:
这个最终的示例综合了我们讨论过的多个元素,创建了一个全面的放射状偏移饼图,包括自定义颜色、图例、中心空白区域和详细的标题。
总结起来,Matplotlib提供了丰富的工具和选项来创建放射状偏移的饼图。通过调整偏移量、颜色、标签和其他视觉元素,我们可以创建出既信息丰富又视觉吸引的数据可视化图表。无论是用于数据分析、报告还是演示,这些技术都能帮助我们更有效地传达数据中的重要信息和见解。