seaborn function overview

功能相似,函数相似

Seaborn的命名空间是扁平的,所有函数功能都可以直接访问。但代码本身是有层次结构的,通过不同方式实现相似可视化目标的函数会被划分到相同的模块。大部分文档是围绕这些模块展开的:比如关系型 (relational),分布型 (distributional)、类别型 (categorical)

例如,分布模块 (distributions module)定义的函数专门用来反映数据点的分布,常见的方法包括直方图:

1
2
penguins = sns.load_dataset('penguins')
sns.histplot(data=penguins, x='flipper_length_mm', hue='species', multiple='stack')

类似的但不那么常见的包括核密度估计:

1
sns.kdeplot(data=penguins, x='flipper_length_mm', hue='species', multiple='stack')

同一个模块中的函数共用很多底层代码和参数,这些参数在其它模块可能并不存在 (比如上述例子中的multiple='stack')。这是为了在探索数据时能方便地切换不同可视化方案,因为不同的可视化方案往往可以进行优势互补

图水平函数与轴水平函数

除了不同的模块,seaborn函数还有一种交叉的分类方式:轴水平 (axes-level)和图水平 (figure-level)。上述例子展示的是轴水平的函数,将数据绘制在单个matplotlib.pyplot.Axes对象上,作为函数的返回值

图水平的函数与此不同,它通过一个seaborn对象 (通常是FacetGrid)与matplotlib进行交互,管理整张图片。每个模块有一个图水平函数,统一其各个轴水平函数。函数组织方式如下:

例如,displot()是分布模块的图水平函数,默认绘制直方图,底层使用与histplot()相同的代码:

1
sns.displot(data=penguins, x='flipper_length_mm', hue='species', multiple='stack')

绘制核密度图使用与kdeplot()相同的代码,使用kind参数进行选择:

1
sns.displot(data=penguins, x='flipper_length_mm', hue='species', multiple='stack', kind='kde')

图水平函数与轴水平函数绘制的结果十分相似,但仍有一些不同。图水平函数绘制的图例在图外,图的形状也有细微的差别

图水平函数最有用的特征是能够轻松地创建包含多个子图的图片。例如,可以把不同品种企鹅的数据分面绘制到不同的子图,而不是堆积在同一个图上:

1
sns.displot(data=penguins, x='flipper_length_mm', hue='species', col='species')

图水平函数包装了其轴水平函数并将类别特异的关键字参数 (比如直方图的分箱大小)传递到底层函数。这意味着图水平函数不失灵活,但仍有一个缺点:函数文档中并没有这些类别特异的关键字参数。函数的有些参数可能没那么容易找到,需要查看两个不同的文档才能理解如何实现一个特定目标

轴水平函数绘制独立的图像

轴水平函数可直接替代matplotlib函数。虽然函数自动添加坐标轴标签和图例,但并不改变任何其绘制的图像以外的东西。这意味着它们可以随心所欲地插入复杂的matplotlib图片中

轴水平函数在内部调用matplotlib.pyplot.gca(),将图片绘制在当前活跃的轴上。轴水平函数也可以通过ax=参数,指定每一个子图的位置

1
2
3
4
f, axs = plt.subplots(1, 2, figsize=(8, 4), gridspec_kw={width_ratios=[4, 3]})
sns.scatterplot(data=penguins, x='flipper_length_mm', y='bill_length_mm', hue='species', ax=axs[0])
sns.histplot(data=penguins, x='species', hue='species', shrink=0.8, alpha=0.8, legend=False, ax=axs[1])
f.tight_layout()

图水平函数拥有其所在的图

相较而言,图水平函数无法轻易地与其它图片进行组合。图水平函数本质上“拥有”其所在的图,包括图的初始化过程,所以不存在使用图水平函数在已有的轴上进行绘制。这一限制使得图水平函数能够实现诸如把图例画在外面等特征

然而,通过访问函数返回的对象中的matplotlib的轴,仍然能够在图水平函数的基础上添加元素:

1
2
3
tips = sns.load_dataset('tips')
g = sns.relplot(data=tips, x='total_bill', y='tip')
g.ax.axline(xy1=(10, 2), slope=0.2, color='b', dashes=(5, 2))

对图水平函数绘制的图像进行修饰

图水平函数返回一个FacetGrid实例,可以通过一些方法修改图像的属性。例如,可以使用一行代码修改坐标轴的标签:

1
2
g = sns.relplot(data=penguins, x='flipper_length_mm', y='bill_length_mm', col='sex')
g.set_axis_labels('Flipper length (mm)', 'Bill length (mm)')

虽然方便,但要注意,这种方法并不是matplotlib API的一部分,只能用于图水平的函数

指定图的大小

如果想要放大或缩小matplotlib的图像,可以设置整张图的宽度和高度,既可以在初始化图的时候设置 (使用matplotlib.pyplot.subplots()figsize参数),也可以调用图对象的方法进行设置 (matplotlib.Figure.set_size_inches())。当使用seaborn轴水平函数时,上述规则是通用的:子图的大小由整张图的大小决定

使用图水平函数时,有一些关键的不同。首先,函数本身有控制图片大小的参数。其次,参数heightaspect控制图片大小的方式与matplotlib中的widthheight不同 (在seaborn参数中,width = height * aspect)。最重要的是,这些参数控制每个子图的大小而不是整个图的大小

先用matplotlib.pyplot.subplots()默认参数绘制一个子图:

1
f, ax = plt.subplots()

包含多个子图的图片整体尺寸也是与单个子图一样的,但是每个子图的轴会被压缩以适应空间:

1
f, ax = plt.subplots(1, 2, sharey=True)

然而,由图水平函数创建的子图是正方形的。使用FacetGrid直接创建一个空的子图,这个函数是relplot()displot()的底层函数:

1
g = sns.FacetGrid(penguins)

如果添加多列,整个图会变宽,每个子图的形状大小都是一样的:

1
g = sns.FacetGrid(penguins, col='sex')

调整子图的形状大小时,不需要考虑图中一共多少行多少列:

1
g = sns.FacetGrid(penguins, col='sex', height=3.5, aspect=0.75)

图水平函数的相对优势

优点 缺点
便于使用数据中的变量进行分面 很多参数没有在函数文档中出现
图例默认画在图外 不能插入到其它matplotlib图中
便于进行图水平的定制 与matplotlib的API不同
不同的图片大小参数 不同的图片大小参数

组合数据的多个视图

Seaborn中有两个重要的绘图函数不能按照上述分类体系进行划分。jointplot()pairplot()利用不同模块中的多种图像类型在同一张图中展示数据的多个维度。这两个图水平函数默认绘制具有多个子图的图片,但它们用不同的对象管理图片:分别是JointGridPairGrid

jointplot()在绘制两个变量的相互关系或者联合分布的同时,通过添加位于边缘的轴展示两个变量各自的分布:

1
sns.jointplot(data=penguins, x='flipper_length_mm', y='bill_length_mm', hue='species')

pairplot()也是类似的情况,它整合了上述两种视图,不再聚焦单个相互关系,而是将每一对变量的组合同时进行可视化:

1
sns.pairplot(data=penguins, hue='species')

这两个函数的底层代码都是前面提到过的轴水平函数 (scatterplot()kdeplot()),因此也可以接受kind参数来实现不同表现形式的切换:

1
2
sns.jointplot(data=penguins, x='flipper_length_mm', y='bill_length_mm', hue='species', kind
='hist')