饼图把整圆当 100%,扇区角度就是占比。占比和角度是同一件事的两种说法。 startangle=90 让第一块从正上方开始,符合人的阅读习惯。 环形图靠 wedgeprops 的 width 挖空中心,那块空地可以放一个总数。
上一篇看分布,这一篇看占比。饼图是最容易画错、也最容易被滥用的一种图。 材料是一份六项支出:房租 2500、吃饭 1800、交通 400、娱乐 600、购物 700、其他 300。
一、六项支出,合计 6300
房租 2500(39.7%,扇区 142.9 度)、吃饭 1800(28.6%,102.9 度)。
| 项目 | 金额 | 占比 | 扇区角度 |
|---|---|---|---|
| 房租 | 2500 | 39.7% | 142.9 |
| 吃饭 | 1800 | 28.6% | 102.9 |
| 购物 | 700 | 11.1% | 40.0 |
| 娱乐 | 600 | 9.5% | 34.3 |
| 交通 | 400 | 6.3% | 22.9 |
| 其他 | 300 | 4.8% | 17.1 |
占比和角度是同一件事的两种说法。整圆 360 度对应 100%,乘一下就对得上。 最后一项「其他」只占 4.8%、17.1 度——已经在「看不见」的边缘了。
二、饼图的两个参数
ax.pie(vals, labels=lab, autopct='%.1f%%', startangle=90)。
autopct 给百分比格式。注意里面是两个百分号,因为 % 在格式串里要转义。
startangle=90 让第一块从正上方开始,顺时针排。
不写 startangle 默认从右侧水平线起,第一块看起来像被切了一刀。
三、环形图:中间挖空
ax.pie(..., wedgeprops=dict(width=0.4)),width 是环的厚度。
0.4 就是环厚占半径的四成,剩下六成是空的。
中间那块空地可以放一个总数:六项合计 6300 元。
环形图的唯一好处就是那块空地。没有要在中间放的东西,就用普通饼图。
四、饼图的三条硬规矩
| 规矩 | 原因 |
|---|---|
| 块数不超过 6 | 再多就分不清谁大谁小 |
| 不要 3D | 3D 会把前面的块拉大,视觉上骗人 |
| 必须标百分比 | 不标就只能靠眼睛估 |
还有一条没进表:各部分必须加起来 100%,有「其他」也得占一块。 柱形图能替代九成的饼图。要占比就把百分比标在柱子上,比看角度准得多。
五、动手 Demo:饼形图与环形图
先算六项支出的占比和扇区角度,再画饼图和环形图各一张。 最后对比一下有多少块落进了「30 度以下」的区域。
import os
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
LAB = ["房租", "吃饭", "交通", "娱乐", "购物", "其他"]
VAL = [2500, 1800, 400, 600, 700, 300]
TOT = sum(VAL)
for a, b in zip(LAB, VAL):
print("%s %4d 元 %4.1f%% %5.1f 度" % (a, b, b * 100.0 / TOT, b * 360.0 / TOT))
fig, ax = plt.subplots(figsize=(5, 5))
ax.pie(VAL, labels=LAB, autopct="%.1f%%", startangle=90)
ax.set_title("月度支出构成")
fig.savefig("pie.png")
fig, ax = plt.subplots(figsize=(5, 5))
ax.pie(VAL, labels=LAB, autopct="%.1f%%", startangle=90,
wedgeprops=dict(width=0.4))
ax.set_title("月度支出构成(环形)")
fig.savefig("donut.png")
print("两张图 %d / %d 字节" % (os.path.getsize("pie.png"),
os.path.getsize("donut.png")))
实跑输出:
--------------------------------------------------------------------
饼形图与环形图
--------------------------------------------------------------------
① 一份支出构成
--------------------------------------------------------------------
六项合计 6300 元。占比最大的是房租 2500,39.7%。
房租 2500 元,39.7%,扇区 142.9 度。
吃饭 1800 元,28.6%,扇区 102.9 度。
交通 400 元,6.3%,扇区 22.9 度。
娱乐 600 元,9.5%,扇区 34.3 度。
购物 700 元,11.1%,扇区 40.0 度。
其他 300 元,4.8%,扇区 17.1 度。
! 占比和角度是同一件事的两种说法:整圆 360 度对应 100%。
② 饼图:autopct 与 startangle
--------------------------------------------------------------------
autopct 给百分比格式,startangle=90 让第一块从正上方开始。
不写 startangle 默认从右侧水平线起,第一块看起来像被切了一刀。
! startangle=90 是饼图最好记的一条。从 12 点方向顺时针排,符合人的阅读习惯。
③ 环形图:中间挖空
--------------------------------------------------------------------
wedgeprops 里的 width 是环的宽度,0.4 就是环厚占半径的四成。
中间空出来的地方可以放一个总数:六项合计 6300 元。
! 环形图的唯一好处就是中间那块空地。放个关键数字,或者干脆不用环形。
④ 饼图的三条硬规矩
--------------------------------------------------------------------
| 规矩 | 原因 |
|---|---|
| 块数不超过 6 | 再多就分不清谁大谁小 |
| 不要 3D | 3D 会把前面的块拉大,视觉上骗人 |
| 必须标百分比 | 不标就只能靠眼睛估 |
还有一条没写进表里的:饼图的各部分必须加起来是 100%,有「其他」也得占一块。
! 柱形图能替代九成的饼图。要占比就标百分比在柱子上,比看角度准得多。
autopct='%.1f%%' 里的两个百分号必须都写,不然会报格式化错误。
环形图比饼图多出来的只有 wedgeprops=dict(width=0.4) 这一个参数。
30 秒实验
- 把 startangle 去掉,对比两张图的起始位置。
- 把 width 改成 0.7,看环会不会细得像根线。
- 想一想:这六项里最小的「其他」占 4.8%,如果把六项扩到十二项会怎样?
常见误区
- 块数太多:扇区小于 30 度就分不清,最后只能看标签。
- 用 3D 饼图:前面的块被拉大,占比看起来全变了。
- 不标百分比:读者靠眼睛估,估出来的数没有一次是对的。
- 各部分加起来不等于 100%:分母错了,所有百分比都错。
自测三问(点开对答案)
1. 扇区角度和占比怎么换算? —— 占比乘 360 得角度。100% 对应整圆 360 度,所以 39.7% 就是 142.9 度。 2. 为什么饼图块数不能多? —— 块越多每块角度越小。30 度以下人眼分不清大小,图就失去意义。 3. 环形图比饼图多解决了什么? —— 中间挖出一块空地,可以放总数或关键指标,省一个标题位。占比看完了。下一篇看关系:散点图和面积图。
- ☐ (本篇完,下一篇 5.9 散点图与面积图)