seaborn + matplotlib 画图(一): 小提琴图
Seaborn 是一个基于 matplotlib 且数据结构与 pandas 统一的统计图制作库
前段时间有一些作图需求,处理数据用的又是pandas,于是就发现了Seaborn这个作图的好工具。之前的代码在Jupyter notebook里,比较分散又没有整理,平时也记不住这么多函数和参数,想想还是整理一下分享出来,即方便自己查看,也能帮助有需要的人。
另外,在写这篇文章的时候发现了Seaborn的中文文档,相见恨晚啊,向翻译大大们致敬。链接贴到下面了,有空了要好好学习学习。
Seaborn 中文文档:https://seaborn.apachecn.org/#/README
seaborn + matplotlib 画图(一): 小提琴图,箱型图
seaborn + matplotlib 画图(二): 柱状图,散点图
seaborn + matplotlib 画图(三): 热图
这篇文章中使用Iris数据集作为示例,提供一些简单图形的绘制方法,下面正式开始。
1. 导入所需包
主要用到的包有numpy,pandas,matplotlib 和 seaborn。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
2. 载入Iris数据
df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data', header=None)
df.columns = ['sepal_length','sepal_width','petal_length','petal_width','class']
print(df.shape)
print(df.head())
print(df['class'].value_counts())
-----outputs-----
(150, 5)
sepal_length sepal_width petal_length petal_width class
0 5.1 3.5 1.4 0.2 Iris-setosa
1 4.9 3.0 1.4 0.2 Iris-setosa
2 4.7 3.2 1.3 0.2 Iris-setosa
3 4.6 3.1 1.5 0.2 Iris-setosa
4 5.0 3.6 1.4 0.2 Iris-setosa
Iris-virginica 50
Iris-setosa 50
Iris-versicolor 50
Name: class, dtype: int64
Iris数据集为 150行 5列,每一行为一个观测对象,前4列分别是 sepal_length(花萼长度),sepal_width (花萼宽度),petal_length(花瓣长度),petal_width(花瓣宽度)。最后一列为class类别。共三类(Iris-virginica,Iris-setosa,Iris-versicolor),每类各50条记录。
3. 颜色和marker类型
这里贴了3个网站,是matplotlib预设的颜色和marker,方便我们选择颜色和marker形状。
Named colors: https://matplotlib.org/stable/gallery/color/named_colors.html
Colormaps: https://matplotlib.org/stable/tutorials/colors/colormaps.html
Markers: https://matplotlib.org/stable/api/markers_api.html
这里我先为3种不同的鸢尾花指定3种颜色,存放到字典里,方便后面使用。选择的颜色都是named colors里预设的。
另外,用一个列表存储3种鸢尾花的绘图顺序。
pal = {'Iris-setosa':'lightcoral','Iris-versicolor':'navajowhite','Iris-virginica':'cornflowerblue'}
class_order = ['Iris-setosa','Iris-versicolor','Iris-virginica']
4. violinplot小提琴图
首先使用violinplot()画一个简单的小提琴图。
plt.figure(figsize=(5,5)) #定义图像大小
g = sns.violinplot(data=df, x='class', y='sepal_length', #传入数据,对sepal_length这一列画图,根据class分组
linewidth=3, #线宽
inner='box', #内部数据形式,默认为box,内部画个小箱型图
palette=pal, #指定颜色盘绘制不同颜色,若使用color参数,则统一设置为一种颜色
order=class_order, #指定顺序
saturation=1) #色彩饱和度,默认0.75
plt.show()
violinplot
虽然还行,不过还需要一些修改,比如轴标签有下划线,字体太小,想去掉上框线和右框线。
plt.figure(figsize=(5,5))
g = sns.violinplot(data=df, x='class', y='sepal_length', linewidth=3,
inner='box', palette=pal, order=class_order, saturation=1)
ylabel = 'Sepal length'
plt.ylabel(ylabel, fontsize=18) #设置y轴标签
plt.yticks(fontsize=15) #设置y轴刻度字体大小
plt.xlabel('') #去掉x轴标签
plt.xticks(ticks=[0,1,2], #设置要显示的x轴刻度,若指定空列表则去掉x轴刻度
labels=['Setosa','Versicolor','Virginiical'], #设置x轴刻度显示的文字,要与ticks对应
fontsize=15, #设置刻度字体大小
rotation=60, #设置刻度文字旋转角度
ha='right', va='center', #刻度文字对齐方式,当rotation_mode为’anchor'时,对齐方式决定了文字旋转的中心。ha也可以写成horizontalalignment,va也可以写成verticalalignment。
rotation_mode='anchor') #我的设置表示文字以右边线的中点为中心旋转。
ax = plt.axes()
ax.spines['top'].set_visible(False) #去掉图像上边框和右边框
ax.spines['right'].set_visible(False)
plt.show()
violinplot
看起来还不错,但如果想要知道每个点的具体情况呢?不如把所有的点也画上去吧。swarmplot()看起来非常合适。
plt.figure(figsize=(5,5))
g1 = sns.violinplot(data=df, x='class', y='sepal_length', linewidth=3,
inner='box', palette=pal, order=class_order, saturation=1)
ylabel = 'Sepal length'
plt.ylabel(ylabel, fontsize=18)
plt.yticks(fontsize=15)
plt.xlabel('')
plt.xticks(ticks=[0,1,2], labels=['Setosa','Versicolor','Virginiical'],
fontsize=15, rotation=60, ha='right', va='center', rotation_mode='anchor')
ax = plt.axes()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
g2 = sns.swarmplot(data=df, x='class', y='sepal_length',
color='grey', alpha=0.5, size=4, #颜色,透明度,大小
linewidth=0.5, edgecolor='black', #边线宽度,边线颜色
order=class_order) #顺序和violinplot保持一致
plt.show()
violinplot
5. boxplot箱型图
单独的箱型图
plt.figure(figsize=(5,5))
g = sns.boxplot(data=df, x='class', y='sepal_length', #传入数据
linewidth=3, #箱边线宽度
width=0.8, #箱体宽度,默认0.8
whis=1.5 #计算上限和下限时四分位距(IQR)前的系数,默认1.5
showfliers=True, #是否显示异常值
fliersize=5, #异常值大小,默认5
palette=pal, #颜色盘
order=class_order, #顺序
saturation=1) #颜色饱和度,默认0.75
ylabel = 'Sepal length'
plt.ylabel(ylabel, fontsize=18)
plt.yticks(fontsize=15)
plt.xlabel('')
plt.xticks(ticks=[0,1,2], labels=['Setosa','Versicolor','Virginiical'],
fontsize=15, ha='center', va='top')
ax = plt.axes()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.show()
boxplot
这里顺便对箱型图做个介绍:
箱体(有颜色的部分)上边缘:上四分位数,Q3
箱体下边缘:下四分位数,Q1
箱体中线:中位数
上方横线:上限范围内的最大值
下方横线:下限范围内的最小值
横线之外的点:异常值
上限计算:Q3+1.5×IQR
下限计算:Q1-1.5×IQR
IQR:四分位距 (interquartile range),IQR = Q3 - Q1
barplot + swarmplot
和小提琴图一样,我们可以在箱型图的基础上,画上散点图,这样所有数据点的分布更加直观。
plt.figure(figsize=(5,5))
g = sns.boxplot(data=df, x='class', y='sepal_length', linewidth=3, showfliers=False,
palette=pal, order=class_order, saturation=1)
sns.swarmplot(data=df, x='class', y='sepal_length',
color='grey', size=4, linewidth=0.5, edgecolor='k',
order=class_order, alpha=0.75)
ylabel = 'Sepal length'
plt.ylabel(ylabel, fontsize=18)
plt.yticks(fontsize=15)
plt.xlabel('')
plt.xticks(ticks=[0,1,2], labels=['Setosa','Versicolor','Virginiical'],
fontsize=15, ha='center', va='top')
ax = plt.axes()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.show()
barplot
空心的箱型图
有时会在一些文献中看到空心的箱型图,虽然可以通过将颜色设置成白色达到空心的效果,但是barplot()中似乎没有参数可以用来设置线的颜色,所以只能是黑色的线。好在还是有其它办法设置的。
plt.figure(figsize=(5,5))
g = sns.boxplot(data=df, x='class', y='sepal_length', linewidth=5,showfliers=False,
order=class_order,saturation=1)
for i in range(len(g.artists)):
box = g.artists[i]
box.set_edgecolor(pal[class_order[i]])
box.set_facecolor('white')
for j in range(5):
k = i*5 + j
line = g.lines[k]
line.set_color(pal[class_order[i]])
sns.swarmplot(data=df, x='class', y='sepal_length',
color='grey', size=4, linewidth=0.5, edgecolor='k',
order=class_order, alpha=0.75)
ylabel = 'Sepal length'
plt.ylabel(ylabel, fontsize=18)
plt.yticks(fontsize=15)
plt.xlabel('')
plt.xticks(ticks=[0,1,2], labels=['Setosa','Versicolor','Virginiical'],
fontsize=15, ha='center', va='top')
ax = plt.axes()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.show()
barplot
其它部分基本一样,主要的不同在于添加了4~11行设置颜色的代码。
g.artists是一个列表,有3个元素(数量和箱型图的数量一样,对象类型是matplotlib.patches.PathPatch),分别是3个箱型图的箱体,通过set_edgecolor()和set_facecolor()方法这是边线颜色(不包括中位线的颜色)和箱体颜色。
g.lines也是一个列表,有15个元素(对象类型是matplotlib.lines.Line2D),包含了箱体那个长方形之外的所有其它线,一个箱型图有5条线(上边线,下边线,2条垂直线,1条中位线),第i个(从0开始)箱型图的5条线index范围是[i*5+0, i*5+4],通过set_color()方法设置颜色。
下面的例子可以更清楚的看到g.lines中的每个元素所对应的线是哪条。
plt.figure(figsize=(5,5))
g = sns.boxplot(data=df, x='class', y='sepal_length', linewidth=5,showfliers=False,
palette=pal, order=class_order,saturation=1)
for i in range(len(g.artists)):
box = g.artists[i]
box.set_edgecolor(pal[class_order[i]])
box.set_facecolor('white')
g.lines[i*5 + 0].set_color('r')
g.lines[i*5 + 1].set_color('g')
g.lines[i*5 + 2].set_color('b')
g.lines[i*5 + 3].set_color('y')
g.lines[i*5 + 4].set_color('purple')
ylabel = 'Sepal length'
plt.ylabel(ylabel, fontsize=18)
plt.yticks(fontsize=15)
plt.xlabel('')
plt.xticks(ticks=[0,1,2], labels=['Setosa','Versicolor','Virginiical'],
fontsize=15, ha='center', va='top')
ax = plt.axes()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.show()
按照红、绿、蓝、黄、紫的顺序对g.lines中的元素设置颜色。
barplot6. savefig保存图片
目前支持的图片格式:eps, pdf, pgf, png, ps, raw, rgba, svg, svgz。
plt.savefig() 需要放在 plt.show() 之前。
outfig = 'E:/fig.png' #supported formats: eps, pdf, pgf, png, ps, raw, rgba, svg, svgz
plt.savefig(outfig,
dpi=300, # 设置分辨率
format=None, #设置图片格式,默认None,如果未设置使用文件名设置的格式
bbox_inches='tight', #设置为tight,防止有时图片保存不完整
facecolor='w', #背景颜色,默认'w'白色
edgecolor='w') #边框颜色,默认'w'白色