首页 > 编程笔记 > Python笔记 阅读:3

Python绘制饼图(附带实例)

饼图(Pie Chart)用于展示各类别在整体中的比例关系。它以圆形为基础,将整体分成多个扇形,每个扇形的角度大小表示该类别在总体中的比例或占比。

饼图的优点是可以直观地展示各类别在整体中的相对比例,常用于表示不同类别的市场份额、调查结果中的频数分布等。在使用饼图时,应选择合适的数据和合适的类别数量,以确保图表的可读性和准确传达数据。在使用饼图时,建议明确标记饼图每个部分的百分比或数字。

【实例 1】饼图绘制示例 1。输入如下代码:
import pandas as pd
import matplotlib.pyplot as plt

# 准备数据
df_raw = pd.read_csv("D:/DingJB/PyData/mpg_ggplot2.csv")  # 读取数据
# 根据车辆类型(class)对数据进行分组,并计算每个类型的数量
df = df_raw.groupby('class').size()
df.plot(kind='pie', subplots=True, figsize=(5, 5))  # 使用 Pandas 绘制饼图

# 设置标题和坐标轴标签
plt.title("Pie Chart of Vehicle Class-Bad")
plt.ylabel("")

plt.show()
上述代码使用 Pandas 从 CSV 文件中读取数据,然后根据车辆类型对数据进行分组,并计算每个类型的数量。接着使用 Pandas 绘制了一个饼图,用于展示每个车辆类型所占的比例。最后,添加了标题和坐标轴标签,使图表更具可读性。

输出的结果如下图所示:


图 1 饼图1

【实例 2】饼图绘制示例 2。输入如下代码:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# 从 csv 文件中读取数据
df_raw = pd.read_csv("D:/DingJB/PyData/mpg_ggplot2.csv")

# 准备数据
# 根据车辆类型(class)对数据进行分组,并计算每个类型的数量
df = df_raw.groupby('class').size().reset_index(name='counts')

# 绘制图形
# 创建图形和轴对象,设置图形大小和等轴比例
fig, ax = plt.subplots(figsize=(8, 6), subplot_kw=dict(aspect="equal"))

# 提取数据和类别
data = df['counts']
categories = df['class']
explode = [0, 0, 0, 0, 0, 0, 1, 0]  # 设置饼图的爆炸程度

# 定义一个函数,用于在饼图上显示百分比和绝对值
def func(pct, allvals):
    absolute = int(pct/100. * np.sum(allvals))
    return "{:.1f}% ({:d})".format(pct, absolute)

# 绘制饼图
wedges, texts, autotexts = ax.pie(data,
                                  autopct=lambda pct: func(pct, data),
                                  textprops=dict(color="w"),
                                  colors=plt.cm.Dark2.colors,
                                  startangle=140,
                                  explode=explode)

# 图形修饰
ax.legend(wedges, categories, title="Vehicle Class", loc="center left",
          bbox_to_anchor=(1, 0, 0.5, 1))  # 添加图例
plt.setp(autotexts, size=10, weight=700)  # 设置自动文本的大小和字重
ax.set_title("Class of Vehicles: Pie Chart")  # 设置图形标题
plt.show()
上述代码首先从 CSV 文件中读取数据,然后根据车辆类型(class)对数据进行分组,并计算每个类型的数量。接着使用 Matplotlib 绘制了一个饼图,用于展示每个车辆类型所占的比例,并在饼图上显示百分比和绝对值。最后,添加了图例和图形标题,使图表更具可读性。

输出的结果如下图所示:


图 2 饼图2

【实例 3】饼图绘制示例3。输入如下代码:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import ConnectionPatch

# 创建图形和轴对象
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 5))
fig.subplots_adjust(wspace=0)

# 饼图参数
overall_ratios = [.27, .56, .17]
labels = ['Approve', 'Disapprove', 'Undecided']
explode = [0, 1, 0]
angle = -180 * overall_ratios[0]  # 旋转角度使得第 1 个楔形图被 X 轴分隔
wedges, *_ = ax1.pie(overall_ratios, autopct='%1.1f%%', startangle=angle,
                     labels=labels, explode=explode)

# 柱状图参数
age_ratios = [.33, .54, .07, .06]
age_labels = ['Under 35', '35-49', '50-65', 'Over 65']
bottom = 1
width = .2

# 从顶部开始添加,以匹配图例
for j, (height, label) in enumerate(reversed([(*zip(age_ratios, age_labels))])):
    bottom -= height
    bc = ax2.bar(0, height, width, bottom=bottom, color='C0', label=label,
                  alpha=0.1 + 0.25 * j)
    ax2.bar_label(bc, labels=[f"{height:.0f}%"], label_type='center')

# 设置柱状图的标题、图例和坐标轴
ax2.set_title('Age of approvers')
ax2.legend()
ax2.axis('off')
ax2.set_xlim(-2.5 * width, 2.5 * width)

# 使用 ConnectionPatch 在两个子图之间绘制连接线
theta1, theta2 = wedges[0].theta1, wedges[0].theta2
center, r = wedges[0].center, wedges[0].r
bar_height = sum(age_ratios)

# 绘制顶部连接线
x = r * np.cos(np.pi / 180 * theta2) + center[0]
y = r * np.sin(np.pi / 180 * theta2) + center[1]
con = ConnectionPatch(xyA=(-0.5 * width, bar_height), coordsA=ax2.transData,
                      xyB=(x, y), coordsB=ax1.transData)
con.set_color([0, 0, 0])
con.set_linewidth(2)
ax2.add_artist(con)

# 绘制底部连接线
x = r * np.cos(np.pi / 180 * theta1) + center[0]
y = r * np.sin(np.pi / 180 * theta1) + center[1]
con = ConnectionPatch(xyA=(-0.5 * width, 0), coordsA=ax2.transData,
                      xyB=(x, y), coordsB=ax1.transData)
con.set_color([0, 0, 0])
con.set_linewidth(2)
ax2.add_artist(con)
plt.show()
上述代码创建了一个具有两个子图的图形,一个子图是饼图,另一个是柱状图。

饼图显示了 Approve、Disapprove 和 Undecided 的比例,而柱状图显示了不同年龄段的比例。通过 ConnectionPatch 类在两个子图之间绘制连接线,将柱状图的柱子与饼图的楔形图连接起来,以突出不同年龄段在 Approve 类别中的比例。

输出的结果如下图所示:


图 3 饼图3

【实例 4】绘制环形饼图,并对其进行标记。输入如下代码:
import matplotlib.pyplot as plt
import numpy as np

# 创建一个大小为 (6,4) 的图,并设置子图属性为“等比例”
fig, ax = plt.subplots(figsize=(6, 4), subplot_kw=dict(aspect="equal"))

# 配方和数据
recipe = ["225 g flour", "90 g sugar", "1 egg",
          "60 g butter", "100 ml milk", "1/2 package of yeast"]
data = [225, 90, 50, 60, 100, 5]

# 绘制饼图
wedges, texts = ax.pie(data, wedgeprops=dict(width=0.5), startangle=-40)

# 注释框的属性
bbox_props = dict(boxstyle="square,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))
    # 水平对齐方式根据 x 坐标的正负确定
    horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
    # 设置连接线的样式
    connectionstyle = f"angle,angleA=0,angleB={ang}"
    kw["arrowprops"].update({"connectionstyle": connectionstyle})
    # 添加注释
    ax.annotate(recipe[i], xy=(x, y), xytext=(1.35*np.sign(x), 1.4*y),
                horizontalalignment=horizontalalignment, **kw)
ax.set_title("Matplotlib bakery: A donut")  # 设置标题
plt.show()
上述代码利用 Matplotlib 创建了一个饼图,展示了烘焙食谱中不同成分的比例,通过注释标明每个扇形对应的成分及其比例,并在每个扇形中心添加了成分名称的注释,使得图形更具可读性。

输出的结果如下图所示:


图 4 添加标记的环形饼图

相关文章