绘制带有误差线的分组数据

先给出一批数据:

小学生标准身高参照数据(标准差为编造, 方便演示):

年级 身高(男) 标准差(男) 身高(女) 标准差(女)
一年级 122cm 9 120cm 11
二年级 125cm 8 125cm 7
三年级 130cm 10 130cm 9
四年级 135cm 8 136cm 8
五年级 140cm 9 143cm 10
六年级 145cm 10 148cm 8

代码和注释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

matplotlib.rcParams['font.family'] = 'SIMHEI' # 设置全局字体
matplotlib.rcParams['font.size'] = 10 # 设置全局字体大小

groups = 6 # 共有六个年级

boysMeans = (122, 125, 130, 135, 140, 145) # 每个年级男性的平均身高
boysStd = (9, 8, 10, 8, 9, 10) # 每个年级男性身高的标准差

girlsMeans = (120, 125, 130, 136, 143, 148) # 每个年级女性的平均身高
girlsStd = (11, 7, 9, 8, 10, 8) # 每个年级女性身高的标准差

fig, ax = plt.subplots()

index = np.arange(groups) # 六个年级的横坐标, index值为 [0, 1, 2, 3, 4, 5]
barWidth = 0.35 # 确定柱形图宽度

opacity = 0.4 # 柱形图透明度
error_config = {'ecolor': '0.3'} # 误差线配置

rects1 = ax.bar(index, boysMeans, barWidth, alpha=opacity,
color='b', yerr=boysStd, error_kw=error_config, label='男') # 绘制男性身高柱形图
# for rect in rects1: # 为每个男性身高柱形创建标签 rect为各个柱形
# x_val = rect.get_x() # 获取每个柱形的x坐标
# y_val = rect.get_height() # 获取每个柱形的y坐标
# ax.text(x_val, y_val+0.5, str(y_val)+'cm') # 在每个柱形相应位置创建标签


rects2 = ax.bar(index + barWidth, girlsMeans, barWidth, alpha=opacity,
color='r', yerr=girlsStd, error_kw=error_config, label='女') # 绘制女性身高柱形图, 注意横坐标的位置要加一个柱形宽度, 这样才能和男性身高柱形紧挨着
# for rect in rects2: # 为每个女性身高柱形创建标签 rect为各个柱形
# x_val = rect.get_x()
# y_val = rect.get_height()
# ax.text(x_val, y_val+0.5, str(y_val)+'cm')

ax.set_xlabel('年级') # x轴标签
ax.set_ylabel('身高(cm)') # y轴标签
ax.set_title('小学生标准身高柱形图', fontsize=20) # 标题
ax.set_xticks(index + barWidth / 2) # 确定x轴标签位置
ax.set_xticklabels(('一年级', '二年级', '三年级', '四年级', '五年级', '六年级')) # 绘制x轴各年级标签
ax.legend() # 绘制图例
# plt.grid(True) # 是否有网格线
fig.tight_layout() # 自动调整子图参数, 使其填充整个图像区域
plt.show()

绘制出来的图形:

01

堆积条形图

同样使用上面的数据, 这次将女性的数据堆积到男性上面, 这里只用将绘制的两句代码改为下面这样即可:

1
2
3
4
rects1 = ax.bar(index, boysMeans, barWidth, alpha=opacity,
color='b', yerr=boysStd, error_kw=error_config, label='男')
rects2 = ax.bar(index, girlsMeans, barWidth, bottom=boysMeans, alpha=opacity,
color='r', yerr=girlsStd, error_kw=error_config, label='女')

其实只是简单地在绘制女孩身高的时候加了一个 bottom=boyMeans 参数即可.

得到的结果如图:

02

破碎条形图

制作一个”破损”的水平条形图, 即一个有间隙的条形图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import matplotlib.pyplot as plt

fig, ax = plt.subplots()

# 绘制从y=10处开始9单位长度的 在x=110处开始30单位长度, 在x=150处开始10单位长度, 颜色为蓝色的图形
ax.broken_barh([(110, 30), (150, 10)], (10, 9), facecolors='blue')

# 绘制从y=20开始9单位长度的 在x=10处开始50单位长度, 在x=100处开始20单位长度, 在x=130开始10单位长度, 颜色分别为红黄绿的图形
ax.broken_barh([(10, 50), (100, 20), (130, 10)], (20, 9),
facecolors=('red', 'yellow', 'green'))

ax.set_ylim(5, 35) # 设置y轴为5-35
ax.set_xlim(0, 200) # 设置x轴为0-200
ax.set_yticks([15, 25]) # 设置y轴15, 25处刻度线
ax.set_yticklabels(['A', 'B']) # 给y轴刻度线添加标签
ax.grid(True) # 加网格
plt.show()

得到的图形如下:

03