import seaborn.objects as so
seaborn.objects命名空间将提供对所有相关类的访问。最重要的是 Plot。 可以通过实例化Plot对象并调用其方法来指定绘图。
看一个简单的例子:
import seaborn as sns
sns.set_theme()
penguins = sns.load_dataset("penguins", data_home='seaborn-data',cache=True)
so.Plot(penguins, x="bill_length_mm", y="bill_depth_mm").add(so.Dot())
(
so.Plot(penguins, x="bill_length_mm", y="bill_depth_mm")
.add(so.Dot(color="g", pointsize=4))
)
(
so.Plot(
penguins, x="bill_length_mm", y="bill_depth_mm",
color="species", pointsize="body_mass_g",
)
.add(so.Dot())
)
虽然这个基本功能并不新颖,但与函数API的一个重要区别是, 属性是使用直接设置属性的相同参数名称进行映射的(而不是使用hue与color等)。 重要的是属性在哪里定义:在初始化Dot时传递一个值将直接设置它, 而在设置Plot时分配一个变量将映射相应的数据。
除了这种差异之外,对象接口还允许映射更广泛的标记属性:
(
so.Plot(
penguins, x="bill_length_mm", y="bill_depth_mm",
edgecolor="sex", edgewidth="body_mass_g",
)
.add(so.Dot(color=".8"))
)
# healthexp = sns.load_dataset("healthexp")
healthexp = sns.load_dataset("healthexp",data_home='seaborn-data',cache=True)
so.Plot(healthexp, x="Year", y="Life_Expectancy", color="Country").add(so.Line())
还可以在不更改任何视觉属性的情况下定义分组,方法是使用 group :
(
so.Plot(healthexp, x="Year", y="Life_Expectancy", group="Country")
.add(so.Line())
)
(
so.Plot(penguins, x="species", y="body_mass_g")
.add(so.Bar(), so.Agg())
)
在函数界面中,统计转换可以使用一些可视化表示(例如seaborn.barplot()), 但不能使用其他表示(例如seaborn.scatterplot())。对象接口更清晰地分离了表示和转换, 允许组合Mark和Stat对象:
(
so.Plot(penguins, x="species", y="body_mass_g")
.add(so.Dot(pointsize=10), so.Agg())
)
通过映射属性形成组时,Stat转换将分别应用于每个组:
(
so.Plot(penguins, x="species", y="body_mass_g", color="sex")
.add(so.Dot(pointsize=10), so.Agg())
)
(
so.Plot(penguins, x="species", y="body_mass_g", color="sex")
.add(so.Bar(), so.Agg())
)
然而,可以将bar标记与Agg属性和第二次转换组合在一起,由Dodge实现:
(
so.Plot(penguins, x="species", y="body_mass_g", color="sex")
.add(so.Bar(), so.Agg(), so.Dodge())
)
Dodge类是Move转换的一个例子,它类似于Stat,但只调整x和y坐标。 Move类可以应用于任何标记,并且不需要先使用Stat:
(
so.Plot(penguins, x="species", y="body_mass_g", color="sex")
.add(so.Dot(), so.Dodge())
)
还可以按顺序应用多个 Move 操作:
(
so.Plot(penguins, x="species", y="body_mass_g", color="sex")
.add(so.Dot(), so.Dodge(), so.Jitter(.3))
)
(
so.Plot(penguins, x="species")
.add(so.Bar(), so.Hist())
)
当给定数值数据时,Hist统计信息还将创建新x值(通过分箱):
(
so.Plot(penguins, x="flipper_length_mm")
.add(so.Bars(), so.Hist())
)
请注意如何使用Bar ,而不是用于具有连续x轴的Bar图。这两个标记是相关的, 但是Bar有不同的默认值,并且更适合连续直方图。 它还会产生一个不同的、更高效的 matplotlib 艺术家。 在其他地方找到单数/复数标记的模式。复数版本通常针对标记数量较多的情况进行优化。
某些转换同时接受x和y,但为每个坐标添加间隔数据。这对于在聚合后绘制误差线尤其重要:
(
so.Plot(penguins, x="body_mass_g", y="species", color="sex")
.add(so.Range(), so.Est(errorbar="sd"), so.Dodge())
.add(so.Dot(), so.Agg(), so.Dodge())
)
(
so.Plot(penguins, x="body_mass_g", y="species", color="sex")
.add(so.Bar(), so.Agg(), so.Dodge())
)
有时,正确的方向是模棱两可的,例如当x 和y 变量都是数字时。 在这些情况下,可以通过将orient参数传递给 Plot.add():
tips = sns.load_dataset("tips",data_home='seaborn-data',cache=True)
(
so.Plot(tips, x="total_bill", y="size", color="time")
.add(so.Bar(), so.Agg(), so.Dodge(), orient="y")
)
(
so.Plot(tips, x="total_bill", y="tip")
.add(so.Dots())
.add(so.Line(), so.PolyFit())
)
构造函数中Plot定义的变量映射将用于所有层:
(
so.Plot(tips, x="total_bill", y="tip", color="time")
.add(so.Dots())
.add(so.Line(), so.PolyFit())
)
(
so.Plot(tips, x="total_bill", y="tip")
.add(so.Dots(), color="time")
.add(so.Line(color=".2"), so.PolyFit())
)
或者,为整个绘图定义图层,但通过将变量设置为 None 以下值将其从特定图层中删除:
(
so.Plot(tips, x="total_bill", y="tip", color="time")
.add(so.Dots())
.add(so.Line(color=".2"), so.PolyFit(), color=None)
)
(
so.Plot(penguins, x="flipper_length_mm")
.facet("species")
.add(so.Bars(), so.Hist())
)
使用应用于定义绘图的列和/或行的变量进行调用 Plot.facet():
(
so.Plot(penguins, x="flipper_length_mm")
.facet(col="species", row="sex")
.add(so.Bars(), so.Hist())
)
可以通过“包装”另一个维度来使用具有更多级别的变量进行分面:
(
so.Plot(healthexp, x="Year", y="Life_Expectancy")
.facet(col="Country", wrap=3)
.add(so.Line())
)
除非明确排除它们,否则所有图层都将被分面,这可以有助于为每个子图提供额外的上下文:
(
so.Plot(healthexp, x="Year", y="Life_Expectancy")
.facet("Country", wrap=3)
.add(so.Line(alpha=.3), group="Country", col=None)
.add(so.Line(linewidth=3))
)
生成子图的另一种方法是Plot.pair() 。就像seaborn.PairGrid 一样, 将绘制每个子图上的所有数据,对 x 和/或 y 坐标使用不同的变量:
(
so.Plot(penguins, y="body_mass_g", color="species")
.pair(x=["bill_length_mm", "bill_depth_mm"])
.add(so.Dots())
)
可以组合分面和配对,只要操作在相反的维度上添加子图:
(
so.Plot(penguins, y="body_mass_g", color="species")
.pair(x=["bill_length_mm", "bill_depth_mm"])
.facet(row="sex")
.add(so.Dots())
)
import matplotlib.pyplot as plt
f = plt.Figure(figsize=(8, 4))
sf1, sf2 = f.subfigures(1, 2)
(
so.Plot(penguins, x="body_mass_g", y="flipper_length_mm")
.add(so.Dots())
.on(sf1)
.plot()
)
(
so.Plot(penguins, x="body_mass_g")
.facet(row="sex")
.add(so.Bars(), so.Hist())
.on(sf2)
.plot()
)
p = so.Plot(healthexp, "Year", "Spending_USD", color="Country")
我们可以用它来绘制线图:
p.add(so.Line())
或者可能是堆积面积图:
p.add(so.Area(), so.Stack())
Plot方法是完全声明性的。调用它们会更新情节规范,但实际上并没有进行任何绘图。 这样做的一个后果是,方法可以以任何顺序调用,其中许多方法可以被多次调用。
剧情实际渲染时间是什么时候?Plot针对笔记本环境进行了优化。 当Plot显示在Jupyter REPL中时,会自动触发渲染。 这就是为什么我们在上面的例子中没有看到任何东西, 在这个例子中,我们定义了一个Plot,但是将它赋值给p,而不是让它返回给REPL。
要查看笔记本中的绘图,要么从单元格的最后一行返回, 要么调用Jupyter在对象上的内置display函数 matplotlib.pyplot。 也可以通过调用Plot.show()在其他上下文中使用它的图形显示机制。 还可以通过调用plot.save()将绘图保存到文件(或缓冲区)。
自定义外观
新的界面旨在通过Plot支持深度定制,减少切换设备和直接使用 matplotlib 功能的需要。 (但请耐心等待;并非实现这一目标所需的所有功能都已实现!)
参数化的尺度
所有与数据相关的属性都由Scale概念和Plot.scale()方法控制。 此方法接受几种不同类型的参数。一种最接近于在 matplotlib 中使用尺度的可能性是传递一个转换坐标的函数的名称:
diamonds = sns.load_dataset("diamonds", data_home='seaborn-data',cache=True)
(
so.Plot(diamonds, x="carat", y="price")
.add(so.Dots())
.scale(y="log")
)
Plot.scale()还可以控制语义属性的映射,如color,可以直接向它传递任何参数, 就像在 seaborn 的函数接口中传递给palette参数一样:
(
so.Plot(diamonds, x="carat", y="price", color="clarity")
.add(so.Dots())
.scale(color="flare")
)
另一种选择是提供(min, max)值的元组,控制比例应映射到的范围。 这既适用于数值属性,也适用于颜色:
(
so.Plot(diamonds, x="carat", y="price", color="clarity", pointsize="carat")
.add(so.Dots())
.scale(color=("#88c", "#555"), pointsize=(2, 10))
)
对于其他控制,可以传递Scale对象。有几种不同类型的Scale,每种都有适当的参数。 例如,Continuous允许定义输入域(norm),输出范围(values), 以及它们之间的映射函数(trans),而Nominal允许指定顺序:
(
so.Plot(diamonds, x="carat", y="price", color="carat", marker="cut")
.add(so.Dots())
.scale(
color=so.Continuous("crest", norm=(0, 3), trans="sqrt"),
marker=so.Nominal(["o", "+", "x"], order=["Ideal", "Premium", "Good"]),
)
)
(
so.Plot(diamonds, x="carat", y="price", color="carat")
.add(so.Dots())
.scale(
x=so.Continuous().tick(every=0.5),
y=so.Continuous().label(like="${x:.0f}"),
color=so.Continuous().tick(at=[1, 2, 3, 4]),
)
)
(
so.Plot(penguins, x="body_mass_g", y="species", color="island")
.facet(col="sex")
.add(so.Dot(), so.Jitter(.5))
.share(x=False)
.limit(y=(2.5, -.5))
.label(
x="Body mass (g)", y="",
color=str.capitalize,
title="{} penguins".format,
)
)
from seaborn import axes_style
theme_dict = {**axes_style("whitegrid"), "grid.linestyle": ":"}
so.Plot().theme(theme_dict)
要更改所有Plot实例的主题,请更新Plot.config设置:
so.Plot.config.theme.update(theme_dict)