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)
# sns.stripplot()

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)
# sns.stripplot()

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中的元素设置颜色。

barplot

6. 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'白色
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容