文章目录
- 前言
- 正文
-
- 画多条线
- linestyle
- 调色盘
-
- 循环调色板
- 样式设置
- 画多个图
- 带标准偏差的曲线图
前言
seaborn还是挺好用的,会比原生的matplotlib美观一点,减少了工作量。本文介绍的基于0.9,注意版本问题。这里不是科普介绍,仅仅是记录个人使用过程中的心得,所以一些图(散点图,直方图等)不会涉及。
正文
画多条线
这里主要是使用特定格式的dataframe,直接进行绘制。dataframe的具体格式为,一列x轴坐标,一列y轴坐标,另一列作为标识,类似matplotlib中的label,如此三列即可。
比如有这样格式的一个dataframe:
x label y
0 0 a 0.904383
1 1 a 0.150750
2 2 a 0.892512
3 3 a 0.548114
4 4 a 0.634979
0 0 b 0.655290
1 1 b 0.183131
2 2 b 0.179457
3 3 b 0.316373
4 4 b 0.653734
可以看出,只需要将多条线的数据按行拼接起来,并通过label标识即可。一个简单的代码示例如下:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import pandas as pd
# 生成数据
x = np.arange(5)y_a = np.random.uniform(size=5)
y_b = np.random.uniform(size=5)label_a = np.full(x.shape, fill_value='a')
label_b = np.full(x.shape, fill_value='b')data_a = pd.DataFrame(np.concatenate((x[:, None], label_a[:, None], y_a[:, None]), axis=1),columns=['x', 'label', 'y'])
data_b = pd.DataFrame(np.concatenate((x[:, None], label_b[:, None], y_b[:, None]), axis=1),columns=['x', 'label', 'y'])
data = pd.concat([data_a, data_b], axis=0)# x、y轴数据需要为数字类型,但上面的操作后会变成object,所以要进行一下转换
data[['x', 'y']] = data[['x', 'y']].apply(pd.to_numeric)
# 设置样式
sns.set(context='paper', style='darkgrid')
fig = plt.figure()
plt.title('multi lines')
# 绘图
sns.lineplot(x="x", y="y", hue='label', data=data)
plt.show()
结果为:
其中最关键的函数数lineplot,也就是画折线图,即
seaborn.lineplot(
*, x=None, y=None, hue=None, size=None, style=None, data=None, palette=None, hue_order=None, hue_norm=None, sizes=None, size_order=None, size_norm=None, dashes=True, markers=None, style_order=None, units=None, estimator=‘mean’, ci=95, n_boot=1000, seed=None, sort=True, err_style=‘band’, err_kws=None, legend=‘auto’, ax=None, **kwargs
)
下面主要对其关键参数进行讲解,针对data是dataframe的情况:
- x, y:x、y对应的列名,同时也指定了xy轴的label
- hue:使用不同的线条颜色区分不同的label,这里指定的是label所在的列名
- size:使用不同的宽度来区分
- style:使用不同的破折号或者标记来区分
- data:含有数据的dataframe
- palette:颜色列表,即自定义区分线条的颜色,颜色名字与matplotlib中格式一致
- ci:数字,默认是95,即95%置信区间,如果数据遵循正态分布,68%置信区间相当于一个标准误差(standard error),或者直接’sd’得到标准差,实际中’sd’的范围会更大一点,并且对称分布,不过会更快。
- estimator:默认是求均值,可以通过np.median修改为求中位数
hue,size和style可以同时用,如果用于同一个label,那么就会同时使用这些样式进行区分,比如同时使用颜色和线的样式区分
sns.lineplot(x="x", y="y", hue='label', style='label', data=data)
这里如果使用列名进行label的设置,那么图里的label就会有列名作为标题,比如上图中的label。如果不想要,可以直接画,然后指定label就行了,比如:
sns.lineplot(x="x", y="y", label='a', data=data)
只要指定坐标系ax,那么多次调用画出的线就会在同一个图里。
sns.lineplot(x="x", y="y", label='a', data=data[:5])
sns.lineplot(x="x", y="y", label='b', data=data[5:])
当然,有时候会想要更精细的,比如两组线都是用同样的一组颜色,但其中一组实线,另一组用虚线或者markers,可以通过坐标系ax对每条线的样式进行设置
ax = sns.lineplot(x="x", y="y", label='a', data=data[:5])
sns.lineplot(x="x", y="y", label='b', data=data[5:])
ax.lines[1].set_linestyle("--")
plt.legend() # 这一步不能少,否则label的线的样式不会更新成你设置的样子,比如label里b的样式还是实线
linestyle
linestyle_str = [('solid', 'solid'), # Same as (0, ()) or '-'('dotted', 'dotted'), # Same as (0, (1, 1)) or '.'('dashed', 'dashed'), # Same as '--'('dashdot', 'dashdot')] # Same as '-.'linestyle_tuple = [('loosely dotted', (0, (1, 10))),('dotted', (0, (1, 1))),('densely dotted', (0, (1, 1))),('loosely dashed', (0, (5, 10))),('dashed', (0, (5, 5))),('densely dashed', (0, (5, 1))),('loosely dashdotted', (0, (3, 10, 1, 10))),('dashdotted', (0, (3, 5, 1, 5))),('densely dashdotted', (0, (3, 1, 1, 1))),('dashdotdotted', (0, (3, 5, 1, 5, 1, 5))),('loosely dashdotdotted', (0, (3, 10, 1, 10, 1, 10))),('densely dashdotdotted', (0, (3, 1, 1, 1, 1, 1)))]
调色盘
调色板可以定义在全局,也可以后面画图时用于color的设置,
sns.set_palette("husl") # 全局
with sns.color_palette("husl"): # 局部# TODO
不传参数就是默认的调色板
sns.color_palette()
还可以自定义
flatui = ["#9b59b6", "#3498db", "#95a5a6", "#e74c3c", "#34495e", "#2ecc71"]
sns.color_palette(flatui)
颜色可以从这里找。
然后是与matplotlib调色板默认顺序相同,但没那么强烈的tab10
sns.color_palette("tab10")
实际上,Seaborn有matplotlib调色板的六种变体,分别称为deep, muted, pastel, bright, dark, 和colorblind。 它们涵盖了平均亮度和饱和度值的范围:
许多人发现默认的“deep”调板的柔和色调在美学上令人愉悦,但它们的区别也较小。因此,在某些情况下可能更难区分它们,这在制作出版物图形时要牢记。对于色盲尽量避免使用Paired和Set2。这种比较有助于估计在模拟不同形式的色盲时,seaborn调色板的表现。
循环调色板
当您要区分任意数量的类别而不强调任何类别时,最简单的方法是在循环颜色空间中绘制间距相等的颜色(在此颜色空间中,色调会发生变化,同时保持亮度和饱和度不变)。这是大多数seaborn函数在处理当需要区分的数据集超过颜色循环中的6种颜色时时所使用的默认方法。
sns.color_palette("hls", 8) # 8个种类
hls_palette()函数允许您控制颜色的亮度(lightness)和饱和度(saturation)。
sns.hls_palette(8, l=.3, s=.8)
然而,由于人类视觉系统的工作方式,RGB强度很高的颜色也不一定看起来同样强烈。我们认为黄色和绿色是相对较亮的,蓝色是相对较暗的,当目标是与hls系统保持一致性时可能会带来一些问题。
为了解决这一问题,seaborn提供了一个husl系统(后来更名为HSLuv)的接口,这也使选择间隔均匀的色调变得容易,同时使亮度和饱和度都更加均匀。
sns.color_palette("husl", 8)
类似地,husl_palette()函数也为这个系统提供了一个更灵活的接口。
扩展阅读:https://www.cntofu.com/book/172/docs/9.md
样式设置
可以注意到,seaborn预定义了几种样式,即style,包括darkgrid, whitegrid, dark, white, ticks,下面对其进行展示
-
darkgrid
-
whitegrid
-
dark
-
white
-
ticks
画多个图
这个重要就是利用matplotlib中的ax来,具体代码如下:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import pandas as pd
# 生成数据
x = np.arange(5)y_a = np.random.uniform(size=5)
y_b = np.random.uniform(size=5)label_a = np.full(x.shape, fill_value='a')
label_b = np.full(x.shape, fill_value='b')data_a = pd.DataFrame(np.concatenate((x[:, None], label_a[:, None], y_a[:, None]), axis=1),columns=['x', 'label', 'y'])
data_b = pd.DataFrame(np.concatenate((x[:, None], label_b[:, None], y_b[:, None]), axis=1),columns=['x', 'label', 'y'])
# x、y轴数据需要为数字类型,但上面的操作后会变成object,所以要进行一下转换
data_a[['x', 'y']] = data_a[['x', 'y']].apply(pd.to_numeric)
data_b[['x', 'y']] = data_b[['x', 'y']].apply(pd.to_numeric)
# 设置样式
sns.set(context='paper', style='darkgrid')
fig = plt.figure()
# 绘图,这里是2行1列的布局
ax1 = fig.add_subplot(211)
sns.lineplot(x="x", y="y", data=data_a, ax=ax1)ax2 = fig.add_subplot(212)
sns.lineplot(x="x", y="y", data=data_b, ax=ax2)
plt.show()
结果如下:
带标准偏差的曲线图
只要把每次运行的完整数据都按行拼接在一个表里,就可以自动产生带95%置信区间阴影的曲线,中间的线是均值。可以通过ci设置置信区间,上面介绍lineplot参数时有介绍。dataframe的格式相比画多条线的,就是少了一个label列
示例代码:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import pandas as pd
# 生成数据
x = np.arange(5)y_a = np.random.uniform(size=5)
y_b = np.random.uniform(size=5)data_a = pd.DataFrame(np.concatenate((x[:, None], y_a[:, None]), axis=1),columns=['x', 'y'])
data_b = pd.DataFrame(np.concatenate((x[:, None], y_b[:, None]), axis=1),columns=['x', 'y'])
data = pd.concat([data_a, data_b], axis=0)# x、y轴数据需要为数字类型,但上面的操作后会变成object,所以要进行一下转换
data[['x', 'y']] = data[['x', 'y']].apply(pd.to_numeric)
# 设置样式
sns.set(context='paper', style='darkgrid')
fig = plt.figure()
plt.title('multi lines')
# 绘图
sns.lineplot(x="x", y="y", data=data)
plt.show()
其中data的格式是这样的:
x y
0 0.0 0.959137
1 1.0 0.788587
2 2.0 0.854879
3 3.0 0.552621
4 4.0 0.147286
0 0.0 0.729034
1 1.0 0.385160
2 2.0 0.480777
3 3.0 0.680783
4 4.0 0.130338
也就是多组x轴坐标一样的数据按行拼接在一起。
结果: