>>> from env_helper import info; info()
页面更新时间: 2024-01-06 20:43:32
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-16-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

5.2. seaborn 绘图功能概述

您与seaborn的大多数交互将通过一组绘图函数发生。本教程后面的章节将探讨每个函数提供的具体特性。本章将从高层次上介绍你将会遇到的不同类型的函数。

5.2.1. 类似的功能用于类似的任务

海上命名空间是平面的;所有的功能都可以在顶层访问。但是代码本身是分层结构的,函数模块通过不同的方式实现类似的可视化目标。大多数文档都是围绕这些模块构建的:你会遇到像“关系”、“分布”和“分类”这样的名字。

例如,distribution模块定义了专门用于表示数据点分布的函数。这包括我们熟悉的直方图方法:

>>> import seaborn as sns
>>>
>>>
>>> sns.set_theme()
>>>
>>> penguins = sns.load_dataset("penguins")
>>> sns.histplot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack")
<AxesSubplot: xlabel='flipper_length_mm', ylabel='Count'>
_images/sec02_overview_2_1.png

除了类似但可能不太熟悉的选项,例如核密度估计:

>>> sns.kdeplot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack")
<AxesSubplot: xlabel='flipper_length_mm', ylabel='Density'>
_images/sec02_overview_4_1.png

模块中的函数共享大量底层代码,并提供库的其他组件(如上面的示例的参数multiple="stack")中可能不存在的类似功能。它们旨在促进在浏览数据集时在不同的视觉表示形式之间切换,因为不同的表示形式通常具有互补的优势和劣势。

5.2.2. 图形级函数与轴级函数

除了不同的模块外,海洋功能还有“轴级”或“图形级”的横切分类。上面的示例是轴级函数。它们将数据绘制到单个matplotlib.pyplot.Axes对象上,该对象是函数的返回值。

相比之下,图形级函数通过管理图形的 seaborn 对象(通常是 FacetGrid)与 matplotlib 交互。每个模块都有一个图形级功能,为其各个轴级功能提供单一接口。组织看起来有点像这样:

_images/function_overview_8_0.png

例如,displot()是分布模块的图形级函数。它的默认行为是绘制直方图,使用与histplot()幕后相同的代码:

>>> sns.displot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack")
<seaborn.axisgrid.FacetGrid at 0x7fbbf0cd9c90>
_images/sec02_overview_6_1.png

要改为绘制核密度图,请使用与kdeplot()相同的代码,使用kind参数选择该图:

>>> sns.displot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack", kind="kde")
<seaborn.axisgrid.FacetGrid at 0x7fbbf0bb6310>
_images/sec02_overview_8_1.png

您会注意到,图形级图看起来与轴级图大多相似,但也存在一些差异。值得注意的是,图例被放置在情节之外。它们的形状也略有不同(稍后会详细介绍)。

图形级函数提供的最有用的功能是它们可以轻松创建具有多个子图的图形。例如,我们可以通过在图的各列上绘制每个分布来“分面”它们,而不是将每种企鹅的三个分布堆叠在同一轴上:

>>> sns.displot(data=penguins, x="flipper_length_mm", hue="species", col="species")
<seaborn.axisgrid.FacetGrid at 0x7fbbf0bf8350>
_images/sec02_overview_10_1.png

图窗级函数包装其轴级对应函数,并将特定于种类的关键字参数(例如直方图的条柱大小)向下传递到基础函数。这意味着它们同样灵活,但有一个缺点:特定于种类的参数不会出现在函数签名或文档字符串中。它们的某些功能可能不太容易被发现,您可能需要查看文档的两个不同页面,然后才能了解如何实现特定目标。

轴级函数可生成独立的绘图

轴级函数的编写方式类似于 matplotlib 函数的直接替换。虽然它们会自动添加轴标签和图例,但它们不会修改绘制到的轴之外的任何内容。这意味着它们可以组合成任意复杂的 matplotlib 图形,并具有可预测的结果。

轴级函数在内部调用matplotlib.pyplot.gca(),它与matplotlib状态机接口挂钩,以便它们在“当前活动的”轴上绘制它们的图。但它们还接受ax=参数,该参数与面向对象接口集成,并允许您指定每个绘图应该放在哪里:

>>> import matplotlib.pyplot as plt
>>> 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()
_images/sec02_overview_12_0.png

图形级函数拥有自己的图形

相比之下,图形级函数不能(容易)与其他图组合在一起。根据设计,它们“拥有”自己的图形,包括其初始化,因此没有使用图形级函数将绘图绘制到现有轴上的概念。此约束允许图窗级函数实现一些功能,例如将图例置于绘图之外。

尽管如此,通过访问它们返回的对象上的 matplotlib 轴并以这种方式向图中添加其他元素,可以超越图形级函数提供的功能:

>>> tips = sns.load_dataset("tips",data_home='seaborn-data',cache=True)
>>> g = sns.relplot(data=tips, x="total_bill", y="tip")
>>> g.ax.axline(xy1=(10, 2), slope=.2, color="b", dashes=(5, 2))
<matplotlib.lines._AxLine at 0x7fbbf08ad7d0>
_images/sec02_overview_14_1.png

从图形级函数自定义绘图

图窗级函数返回一个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)")
<seaborn.axisgrid.FacetGrid at 0x7fbbf088b7d0>
_images/sec02_overview_16_1.png

指定图形尺寸

要增加或减少matplotlib图的大小,您可以在全局rcParams中设置整个图的宽度和高度,同时设置图(例如使用matplotlib.pyplot.subplots()figsize参数),或者通过调用图对象上的方法(例如matplotlib. figure .set_size_inches())。当在seaborn中使用轴级函数时,同样的规则也适用:绘图的大小取决于它所在的图形的大小和该图形中的轴布局。

在使用图形级功能时,有几个关键的区别。首先,函数本身具有控制图形大小的参数(尽管这些参数实际上是管理图形的底层FacetGrid的参数)。其次,这些参数,heightaspect,参数化大小与matplotlib中的widthheight参数化略有不同(使用seaborn参数,width = height * aspect)。最重要的是,参数对应于每个子图的大小,而不是整个图的大小。

为了说明这些方法之间的区别,下面是带有一个子图的matplotlib.pyplot.subplots()的默认输出:

>>> f, ax = plt.subplots()
_images/sec02_overview_18_0.png

具有多列的图形将具有相同的整体大小,但轴将被水平挤压以适合空间:

>>> f, ax = plt.subplots(1, 2, sharey=True)
_images/sec02_overview_20_0.png

相反,由图形级函数创建的绘图将是方形的。为了演示这一点,让我们直接使用FacetGrid设置一个空图。这发生在后台函数中,如relplot()displot()catplot():

>>> g = sns.FacetGrid(penguins)
_images/sec02_overview_22_0.png

添加其他列时,图形本身将变宽,因此其子图具有相同的大小和形状:

>>> g = sns.FacetGrid(penguins, col="sex")
_images/sec02_overview_24_0.png

您可以调整每个子图的大小和形状,而无需考虑图中的行和列总数:

>>> g = sns.FacetGrid(penguins, col="sex", height=3.5, aspect=.75)
_images/sec02_overview_26_0.png

结果是,您可以分配刻面变量,而无需停下来考虑需要如何调整总图形大小。缺点是,当您确实想更改图形大小时,您需要记住,事情的工作方式与 matplotlib 中的工作方式略有不同。

图形级函数的相对优点

以下是我们上面讨论的优缺点的总结:

<tr><td>

默认情况下,图例在绘图之外

优势

缺点

通过数据变量轻松分面

许多参数不在函数签名中

不能是更大的 matplotlib 图的一部分

轻松的图形级定制

与 matplotlib 不同的 API

不同的图形尺寸参数化

不同的图形尺寸参数化

总的来说,图形级函数增加了一些额外的复杂性,可能会让初学者更加困惑,但它们独特的功能赋予了它们额外的功能。教程文档主要使用图形级函数,因为它们生成的绘图稍微清晰一些,我们通常建议在大多数应用程序中使用它们。它们不是一个好的选择的一种情况是,当你需要制作一个复杂的、独立的人物,组成多种不同的情节类型时。此时,建议直接使用 matplotlib 设置图形,并使用轴级函数填充各个组件。

5.2.3. 组合数据的多个视图

海产的两个重要绘图函数不能很好地适用于上面讨论的分类方案。jointplot()pairplot()这两个函数使用来自不同模块的多种绘图来在单个图中表示数据集的多个方面。这两个绘图都是图形级函数,默认情况下创建具有多个子绘图的图形。但是它们使用不同的对象来管理图形:分别是JointGridPairGrid

Jointplot()绘制两个变量的关系或联合分布,并添加分别表示每个变量的单变量分布的边缘轴:

>>> sns.jointplot(data=penguins, x="flipper_length_mm", y="bill_length_mm", hue="species")
<seaborn.axisgrid.JointGrid at 0x7fbbf06aa450>
_images/sec02_overview_28_1.png

pairplot()是相似的——它结合了联合视图和边际视图——但不是专注于单一关系,而是同时可视化每个成对的变量组合:

>>> sns.pairplot(data=penguins, hue="species")
<seaborn.axisgrid.PairGrid at 0x7fbbf0498a10>
_images/sec02_overview_30_1.png

在幕后,这些函数使用了你已经见过的轴级函数(scatterplot()kdeploy()),它们也有一个kind参数,可以让你快速交换不同的表示:

>>> sns.jointplot(data=penguins, x="flipper_length_mm", y="bill_length_mm", hue="species", kind="hist")
<seaborn.axisgrid.JointGrid at 0x7fbbeb9a7c50>
_images/sec02_overview_32_1.png