Seaborn 绘图函数概述#
您与 Seaborn 的大部分交互将通过一组绘图函数进行。教程中的后续章节将探讨每个函数提供的具体功能。本章将从较高层面介绍您将遇到的不同类型的函数。
类似任务的类似函数#
Seaborn 命名空间是扁平的;所有功能都在顶层可用。但是代码本身是分层结构的,包含通过不同方式实现类似可视化目标的函数模块。大多数文档都围绕这些模块结构:您将遇到“关系”,“分布”和“分类”之类的名称。
例如,分布模块 定义了专门用于表示数据点分布的函数。这包括直方图等常用方法
penguins = sns.load_dataset("penguins")
sns.histplot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack")
以及类似但可能不太熟悉的选项,例如核密度估计
sns.kdeplot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack")
模块内的函数共享很多底层代码,并提供类似的功能,这些功能可能在库的其他组件中不存在(例如上面的示例中的 multiple="stack"
)。它们旨在促进在您探索数据集时在不同的视觉表示之间切换,因为不同的表示通常具有互补的优势和劣势。
图级函数与轴级函数#
除了不同的模块之外,还有一种跨切 Seaborn 函数的分类,即“轴级”或“图级”。上面的示例是轴级函数。它们将数据绘制到单个 matplotlib.pyplot.Axes
对象上,该对象是函数的返回值。
相反,图级函数通过 Seaborn 对象与 Matplotlib 进行交互,通常是一个 FacetGrid
,它管理图形。每个模块都有一个图级函数,它为其各种轴级函数提供了一个统一的接口。该组织看起来有点像这样
例如,displot()
是分布模块的图级函数。它的默认行为是绘制直方图,使用与 histplot()
相同的代码在幕后
sns.displot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack")
要绘制核密度图,使用与 kdeplot()
相同的代码,使用 kind
参数进行选择
sns.displot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack", kind="kde")
您会注意到,图级绘图看起来与它们的轴级对应项非常相似,但也有一些区别。值得注意的是,图例被放置在绘图之外。它们也具有稍微不同的形状(稍后会详细介绍)。
图级函数提供的最有用的功能是它们可以轻松地创建具有多个子图的图形。例如,我们不是将每个企鹅物种的三个分布叠加在同一坐标轴上,而是可以“分面”它们,将每个分布绘制到图形的列中
sns.displot(data=penguins, x="flipper_length_mm", hue="species", col="species")
图级函数包装它们的轴级对应项并将特定于类型的关键字参数(例如直方图的 bin 大小)传递到底层函数。这意味着它们并不缺乏灵活性,但有一个缺点:特定于类型的参数不会出现在函数签名或文档字符串中。它们的一些功能可能难以发现,您可能需要查看两个不同的文档页面才能了解如何实现特定目标。
轴级函数创建独立的绘图#
轴级函数被编写为像 Matplotlib 函数的直接替换一样起作用。虽然它们会自动添加坐标轴标签和图例,但它们不会修改它们绘制到的坐标轴之外的任何内容。这意味着它们可以以可预测的结果组合到任意复杂的 Matplotlib 图形中。
轴级函数在内部调用 matplotlib.pyplot.gca()
,它挂钩到 Matplotlib 状态机接口,以便它们在其“当前活动”坐标轴上绘制图形。但它们也接受一个 ax=
参数,它与面向对象的接口集成在一起,让您可以精确地指定每个绘图应该放在哪里
f, axs = plt.subplots(1, 2, figsize=(8, 4), gridspec_kw=dict(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=.8, alpha=.8, legend=False, ax=axs[1])
f.tight_layout()
图级函数拥有自己的图形#
相反,图级函数不能(轻松地)与其他绘图组合。通过设计,它们“拥有”自己的图形,包括其初始化,因此没有使用图级函数在现有坐标轴上绘制绘图的概念。此约束允许图级函数实现一些功能,例如将图例放在绘图之外。
然而,通过访问它们返回的对象上的 Matplotlib 坐标轴并以这种方式向绘图添加其他元素,可以超越图级函数提供的功能
tips = sns.load_dataset("tips")
g = sns.relplot(data=tips, x="total_bill", y="tip")
g.ax.axline(xy1=(10, 2), slope=.2, color="b", dashes=(5, 2))
从图级函数自定义绘图#
图级函数返回一个 FacetGrid
实例,该实例有一些方法可以以“智能”的方式自定义绘图的属性,并考虑子图的组织方式。例如,您可以使用一行代码更改外部坐标轴上的标签
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 绘图的大小,您可以在设置绘图时(例如使用 figsize
参数 全局 rcParams)或通过调用图形对象上的方法(例如 matplotlib.Figure.set_size_inches()
)来设置整个图形的宽度和高度。当在 Seaborn 中使用轴级函数时,相同的规则适用:绘图的大小由其所属的图形的大小以及该图形中的坐标轴布局决定。
当使用图级函数时,有一些关键的区别。首先,函数本身具有控制图形大小的参数(尽管这些实际上是底层 FacetGrid
的参数,它管理图形)。其次,这些参数,height
和 aspect
,对大小的规范方式与 Matplotlib 中的 width
,height
参数化略有不同(使用 Seaborn 参数,width = height * aspect
)。最重要的是,这些参数对应于每个子图的大小,而不是整个图形的大小。
为了说明这些方法之间的区别,以下是具有一个子图的 matplotlib.pyplot.subplots()
的默认输出
f, ax = plt.subplots()
具有多个列的图形将具有相同的大小,但坐标轴将水平压缩以适应空间
f, ax = plt.subplots(1, 2, sharey=True)
相反,通过图级函数创建的绘图将是正方形的。为了证明这一点,让我们通过直接使用 FacetGrid
来设置一个空绘图。这在 relplot()
,displot()
或 catplot()
等函数中幕后发生
g = sns.FacetGrid(penguins)
当添加其他列时,图形本身会变宽,以便其子图具有相同的大小和形状
g = sns.FacetGrid(penguins, col="sex")
并且您可以调整每个子图的大小和形状,而无需考虑图形中总的行数和列数
g = sns.FacetGrid(penguins, col="sex", height=3.5, aspect=.75)
结果是,您可以分配分面变量,而无需停下来考虑如何调整图形的总大小。缺点是,当您确实想要更改图形大小时,您需要记住它们的工作方式与 Matplotlib 中略有不同。
图级函数的相对优点#
以下是我们上面讨论的优缺点的总结
优点 |
缺点 |
---|---|
通过数据变量轻松分面 |
许多参数不在函数签名中 |
默认情况下,图例位于图外部。 |
不能作为更大的 matplotlib 图的一部分。 |
轻松进行图级别自定义。 |
与 matplotlib 的 API 不同。 |
不同的图形大小参数化。 |
不同的图形大小参数化。 |
总的来说,图级别函数增加了一些额外的复杂性,可能会让初学者感到困惑,但它们独特的特性也赋予了它们额外的功能。教程文档主要使用图级别函数,因为它们可以生成更简洁的图形,并且我们通常建议在大多数应用程序中使用它们。它们不适合的唯一情况是,当您需要创建一个复杂的、独立的图形,该图形由多个不同的绘图类型组成时。此时,建议使用 matplotlib 直接设置图形,并使用轴级别函数填充各个组件。
组合数据上的多个视图#
Seaborn 中有两个重要的绘图函数,它们不能很好地融入上面讨论的分类方案。这两个函数,jointplot()
和 pairplot()
,使用来自不同模块的多种绘图类型,在一个图形中表示数据集的多个方面。这两个绘图都是图级别函数,默认情况下会创建具有多个子图的图形。但它们使用不同的对象来管理图形:JointGrid
和 PairGrid
,分别。
jointplot()
绘制两个变量的关系或联合分布,同时添加边缘轴,分别显示每个变量的单变量分布。
sns.jointplot(data=penguins, x="flipper_length_mm", y="bill_length_mm", hue="species")
pairplot()
与此类似——它组合了联合视图和边缘视图——但它不是专注于单一关系,而是同时可视化每个变量的成对组合。
sns.pairplot(data=penguins, hue="species")
在幕后,这些函数使用您已经遇到的轴级别函数 (scatterplot()
和 kdeplot()
),并且它们还有一个 kind
参数,可以让您快速切换到不同的表示。
sns.jointplot(data=penguins, x="flipper_length_mm", y="bill_length_mm", hue="species", kind="hist")