记录利用 seaborn、matplot 绘制带有误差带阴影的图。
1 前言
因为在强化学习中经常要用到利用误差带绘的阴影图,因此特地记录一下。实现的时候有两种方法,一种是 seaborn,另一种是matplot。接下来将分别介绍。
2 seaborn绘制误差带图
参考链接5 给出了一个官方的示例,我们先来对这个示例进行一些把玩。数据集fmri的简介及获取方式可参考Seaborn绘图——概述。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
# 导入数据集
fmri = sns.load_dataset("fmri")
print(list(fmri)) # 获取所有列名
print(fmri.nunique()) # 获取每一列中有多少个不同的数据
print(fmri.shape) # 获取数据集大小
print(fmri.head(5)) # 打印前5行
fmri_time = fmri.loc[:, 'timepoint'] # 获取 timepoint 列的所有数据
print(fmri_time)
# 绘图
sns.relplot(x="timepoint", y="signal", data=fmri)
plt.show()
sns.relplot(x="timepoint", y="signal", kind="line", data=fmri)
plt.show()
sns.relplot(x="timepoint", y="signal", ci=None, kind="line", data=fmri)
plt.show()
sns.relplot(x="timepoint", y="signal", kind="line", ci="sd", data=fmri)
plt.show()
sns.relplot(x="timepoint", y="signal", estimator=None, kind="line", data=fmri)
plt.show()
绘制出来的曲线如下:




由于这个数据集的 timepoint 列包含0~18,共19个数,而数据集的长度是1064,因此,将timepoint作为横轴,则会有一个 timepoint 对应多个 signal 的情况,亦即横轴取值出现了重复,这点从第一幅散点图可以清晰看出。如果将relplot() 中的 kind 设置为 line,则会计算对应纵轴变量的均值(mean)和置信水平为0.95的置信区间(confidence interval)来实现一种聚合(aggregation)。对上图的简要说明如下:
- 第二幅图是默认对各点的均值做聚合绘制的阴影带;
- 第三幅图是仅绘制出均值,使用
ci=None
忽略掉置信区间; - 第四幅图是设置
ci="sd"
计算标准差作为置信区间; - 第五福图是设置
estimator=None
关闭了聚合效果,仅将点进行连线。
类似于前述文章的绘图方式,可以引入类别变量作为区分:1
2
3
4
5
6
7
8sns.relplot(x="timepoint", y="signal", hue="event", kind="line", data=fmri)
plt.show()
sns.relplot(x="timepoint", y="signal", hue="region", style="event", kind="line", data=fmri)
plt.show()
sns.relplot(x="timepoint", y="signal", hue="region", style="event", dashes=False, markers=True, kind="line", data=fmri)
plt.show()
sns.relplot(x="timepoint", y="signal", hue="event", style="event", kind="line", data=fmri)
plt.show()
效果如下:




上图中,第一幅图通过控制
hue
作为分类变量,用颜色区别开;第二幅图又引入了 style
变量,用线型区分开;第三幅图示例了如何设置标记点,还可以有其他的设置方式,可以以列表的形式传入给相应的参数。
3 构造简单数据集小试牛刀
如果觉得使用seaborn的数据集不过瘾,还可以自己来构造一个简单的数据集进行试验。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
40import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
# 构造一个含有噪声的正弦波
time = np.arange(0, 2*np.pi, 0.1)
sin_waves = np.sin(time)
sin_waves = np.expand_dims(sin_waves, axis=-1)
noise = np.random.random((time.size, 10)) - 0.5
print('noise shape: ', noise.shape) # (63, 10)
data = sin_waves + noise
data_mean = np.mean(data, axis=1)
data_std = np.std(data, axis=1)
data_var = np.var(data, axis=1)
data_max = np.max(data, axis=1)
data_min = np.min(data, axis=1)
plt.figure()
plt.plot(data_mean)
plt.show()
plt.figure()
plt.plot(data_std)
plt.show()
# 将 time 扩展为 10 列一样的数据
time_array = time
for i in range(noise.shape[1] - 1):
time_array = np.column_stack((time_array, time))
# 将 time 和 signal 平铺为两列数据,且一一对应
time_array = time_array.flatten() # (630,)
data = data.flatten() # (630,)
data = np.column_stack((time_array, data)) # (630,2)
df = pd.DataFrame(data, columns=['time', 'signal'])
# 绘图
sns.relplot(x='time', y='signal', data=df)
plt.show()
sns.relplot(x='time', y='signal', data=df, kind='line')
plt.show()
在上述程序中,构造了一个正弦波 $\sin t$,其中 $t\in[0, 2\pi)$,然后再随机化一个噪声矩阵,并将其加在正弦波上,按行求其均值、标准差、方差,再将一开始的 time 数组扩展为同等维度的数组 time_array, time_array 中的每一列都一致。接着,将 time_array 和 data 分别平铺后合并为一个两列的数据并转为 DataFrame 格式。绘图的结果如下:




4 matplot 绘制阴影带
在上节的基础上,如果想绘制包含所有数据在内的阴影带,应该怎么办呢?
可以直接将数据的最大最小值取出,然后用 matplot 的 fill_between() 函数进行填充,同时也可以绘制其标准差的误差带。1
2
3
4
5
6
7
8
9
10
11
12sns.relplot(x='time', y='signal', data=df)
plt.plot(time, data_mean, color='deeppink', label='mean')
plt.plot(time, sin_waves, 'b-', label='ideal')
plt.fill_between(time, data_min, data_max, color='violet', alpha=0.2)
plt.legend()
plt.show()
plt.plot(time, data_mean, color='deeppink', label='mean')
plt.plot(time, sin_waves, 'b-', label='ideal')
plt.fill_between(time, data_mean - data_std, data_mean + data_std, color='violet', alpha=0.2)
plt.legend()
plt.show()
效果如下:


matplot中颜色的调节可参照下表,直接输入 color='颜色名'
即可[7]。
参考链接
- Fill Between and Alpha
- Filling the area between lines
- fill_between(x, y1, y2)
- https://cloud.tencent.com/developer/ask/sof/534017
- Timeseries plot with error bands
- (一)seaborn教程——可视化统计关系
- matplot颜色表