>>> from  env_helper import info; info()
页面更新时间: 2024-04-07 23:39:54
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-18-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

5.13. 选择调色板

Seaborn 可以轻松使用适合您的数据特征和可视化目标的颜色。本章讨论了指导您选择的一般原则,以及 seaborn 中帮助您快速找到给定应用的最佳解决方案的工具。

5.13.1. 在绘图中使用颜色的一般原则

颜色的组成部分

由于我们眼睛的工作方式,可以使用三个组件来定义特定的颜色。我们通常通过指定 RGB 值来对计算机中的颜色进行编程,这些值设置显示器中红色、绿色和蓝色通道的强度。但是,要分析颜色的感知属性,最好从色调、饱和度和亮度通道的角度来考虑。

色相是在非技术意义上区分“不同颜色”的组件。它是颜色的属性,导致“红色”和“蓝色”等一阶名称:

_images/img1.png

饱和度(或色度)是色彩。当具有不同色调的两种颜色具有更高的饱和度时,它们看起来会更加明显:

_images/img2.png

亮度对应于从黑色到白色的发射量(或反射量,对于印刷颜色):

_images/img3.png

改变色调以区分类别

如果要在图中表示多个类别,通常应改变元素的颜色。考虑这个简单的例子:在这两个图中,哪个更容易计算三角形点的数量?

_images/color_palettes_9_0.png

在右边的图中,橙色三角形“弹出”,很容易将它们与圆圈区分开来。之所以会出现这种弹出效应,是因为我们的视觉系统优先考虑色差。

蓝色和橙色的区别主要在于色调。色相对于表示类别很有用:大多数人可以相对容易地区分适度数量的色相,而具有不同色调但亮度或强度相似的点似乎同样重要。它还使情节更容易谈论。请看这个例子:

_images/color_palettes_11_0.png

大多数人将能够快速确定左侧图中有五个不同的类别,如果被要求描述“蓝色”点,将能够这样做。

在右边的图中,这些点都是蓝色的,但亮度和饱和度各不相同,很难说有多少个独特的类别。我们将如何谈论特定类别?“公平但不是太蓝的点?”更重要的是,灰点似乎逐渐消失在背景中,相对于更强烈的蓝点,它们不再强调。如果类别同样重要,则表示性较差。

因此,作为一般规则,使用色相变化来表示类别。话虽如此,这里有一些注意事项。如果您的绘图中有几种颜色,则很难记住每种颜色的含义,除非类别与用于表示它们的颜色之间存在预先存在的关联。这使得你的情节更难解释:观众将不得不不断参考图例来理解所显示的内容,而不是专注于数据。所以你应该尽量不要制作太复杂的情节。请注意,并非每个人都以相同的方式看待颜色。改变形状(或其他属性)和颜色可以帮助色觉异常的人理解你的绘图,如果将它们打印成黑白,它可以使它们(在某种程度上)可解释。

改变亮度以表示数字

另一方面,色调变化不太适合表示数值数据。考虑这个例子,我们需要颜色来表示双变量直方图中的计数。在左侧,我们使用圆形颜色图,其中每个箱内观测值的逐渐变化与色调的逐渐变化相对应。在右侧,我们使用一个调色板,该调色板使用更亮的颜色来表示具有较大计数的条柱:

_images/color_palettes_14_0.png

使用基于色调的调色板时,很难确定二元分布的形状。相比之下,亮度调色板更清楚地表明有两个突出的峰值。

不同的亮度有助于查看数据中的结构,并且亮度的变化可以更直观地处理为重要性的变化。但右边的图没有使用灰度颜色图。它的色彩使它更加有趣,微妙的色调变化增加了两个值之间的感知距离。因此,微小的差异稍微容易解决。

这些示例表明,调色板的选择不仅仅是美观:如果使用得当,您选择的颜色可以揭示数据中的模式,或者如果使用不当,则可以隐藏它们。没有一个最佳调色板,但对于特定的数据集和可视化方法,有一些调色板更好或更差。

美学确实很重要:人们越想看你的人物,他们就越有可能从中学到一些东西。即使你为自己制作情节也是如此。在探索性数据分析期间,您可能会生成许多相似的数字。改变调色板将增加一种新颖感,让您保持参与并准备好注意到数据的有趣特征。

那么,如何选择既能很好地代表您的数据又能看起来很有吸引力的调色板呢?

5.13.2. 选择调色板的工具

处理调色板最重要的函数是color_palette()。这个函数为在seaborn中生成调色板的大多数可能方法提供了一个接口。它在内部被任何有palette参数的函数使用。

color_palette()的主要参数通常是一个字符串:特定调色板的名称或一个系列的名称,以及用于选择特定成员的附加参数。在后一种情况下,color_palette()将委托给更具体的函数,例如cubehelix_palette()。还可以以matplotlib接受的任何方式传递指定的颜色列表(RGB元组、十六进制代码或X11表中的名称)。返回值是一个对象,它用一些有用的方法包装了RGB元组列表,例如转换为十六进制代码和丰富的HTML表示。

不带参数调用color_palette()将返回当前默认调色板,如果没有指定颜色,matplotlib(和大多数seaborn函数)将使用该调色板。可以使用相应的set_palette()函数设置此默认调色板,该函数在内部调用color_palette()并接受相同的参数。

为了激发color_palette()提供的不同选项,为调色板引入一个分类方案将是有用的。从广义上讲,调色板可以分为三类:

  • 定性调色板,适用于表示分类数据

  • 顺序调色板,适合表示数值数据

  • 发散调色板,适用于表示具有分类边界的数值数据

5.13.3. 定性调色板

定性调色板非常适合表示分类数据,因为它们的大部分变化都存在于色调分量中。seaborn 中的默认调色板是具有十种不同色调的定性调色板:

>>> import seaborn as sns
>>> sns.color_palette()

这些颜色与默认的matplotlib调色板“tab10”具有相同的顺序,但它们不那么强烈。比较:

>>> sns.color_palette("tab10")

Seaborn实际上有六个matplotlib调色板的变体,分别是deepmutedpastelbrightdark,和 colorblind。它们跨越了平均亮度和饱和度值的范围:

_images/color_palettes_22_0.svg

许多人发现默认"deep"调色板的温和色调在美学上令人愉悦,但它们也不那么明显。因此,在某些情况下,它们可能更难以区分,这是在制作出版物图形时要记住的。这种比较有助于估计在模拟不同形式的色盲时,海运调色板的表现。

使用圆形色彩系统

当你有任意数量的类别时,寻找独特色调的最简单方法是在圆形色彩空间中绘制均匀间隔的颜色(在保持亮度和饱和度不变的情况下,色调会发生变化)。这是大多数seaborn函数在需要使用比当前默认颜色周期中设置的更多颜色时的默认设置。

最常用的方法是使用hls色彩空间,这是对RGB值的简单转换。我们之前看到过这个调色板作为如何绘制直方图的反例:

>>> sns.color_palette("hls", 8)

由于人类视觉系统的工作方式,在RGB值方面具有相同亮度和饱和度的颜色不一定看起来同样强烈 为了解决这个问题,seaborn 提供了一个 husl 系统的接口(后来更名为 HSLuv),当您围绕色轮旋转时,它可以实现更少的强度变化:

>>> sns.color_palette("husl", 8)

当 seaborn 需要一个分类调色板,其颜色比当前默认值中可用的颜色多时,它将使用这种方法。

使用分类 Color Brewer 调色板

视觉上令人愉悦的分类调色板的另一个来源来自Color Brewer工具(该工具还具有顺序和发散的调色板,我们将在下面看到)。

>>> sns.color_palette("Set2")

请注意,定性Color Brewer调色板有不同的长度,color_palette()的默认行为是给你完整的列表:

>>> sns.color_palette("Paired")

5.13.4. 顺序调色板

第二类调色板被称为“顺序调色板”。当数据范围从相对低或无趣的值到相对高或有趣的值(反之亦然)时,这种映射是合适的。如上所述,顺序调色板中变化的主要维度是亮度。当您映射数字数据时,一些派生函数将默认使用顺序调色板。(由于历史原因,在relplot()displot()等函数中,分类映射和数字映射都使用hue参数指定,尽管数字映射使用色调变化相对较小的调色板)。

感知上统一的调色板

因为它们旨在表示数值,所以最好的顺序调色板在感知上是一致的,这意味着两种颜色的相对可分辨性与相应数据值之间的差异成正比。Seaborn包括四个感知上一致的顺序颜色图:"rocket""mako""flare""crest"。前两种具有非常宽的亮度范围,非常适合于热图等应用,其中颜色填充了它们绘制的空间:

>>> sns.color_palette("rocket", as_cmap=True)
rocket
rocket colormap
under
bad
over
>>> sns.color_palette("mako", as_cmap=True)
mako
mako colormap
under
bad
over

由于这些颜色图的极值接近白色,因此它们不太适合为线或点等元素着色:很难区分白色或灰色背景中的重要值。“耀斑”和“波峰”颜色图是此类绘图的更好选择。它们的亮度变化范围更有限,它们通过稍微更明显的色调变化来补偿。亮度渐变的默认方向也相反,因此较小的值具有较浅的颜色:

>>> sns.color_palette("flare", as_cmap=True)
flare
flare colormap
under
bad
over
>>> sns.color_palette("crest", as_cmap=True)
crest
crest colormap
under
bad
over

也可以使用matplotlib提供的感知一致的颜色图,例如“magma”“viridis”:

>>> sns.color_palette("magma", as_cmap=True)
magma
magma colormap
under
bad
over
>>> sns.color_palette("viridis", as_cmap=True)
viridis
viridis colormap
under
bad
over

与matplotlib中的约定一样,每个连续色图都有一个反向版本,其后缀为“_r”:

>>> sns.color_palette("rocket_r", as_cmap=True)
rocket_r
rocket_r colormap
under
bad
over

离散映射与连续映射

需要注意的一件事是,seaborn可以从顺序颜色映射生成离散值,并且在这样做时,它不会使用最极端的值。将“rocket”的离散版本与上面所示的连续版本进行比较:

>>> sns.color_palette("rocket")

在内部,seaborn 对分类数据使用离散版本,在数字映射模式下使用连续版本。离散顺序颜色图非常适合可视化具有内在顺序的分类数据,尤其是在存在一些色调变化的情况下。

顺序“cubehelix”调色板

感知均匀的颜色图很难以编程方式生成,因为它们不是基于 RGB 颜色空间的。cubehelix系统提供了一个基于RGB的折衷方案:它生成连续的调色板,亮度线性增加或减少,色调有一些连续的变化。虽然在感知上并不完全一致,但生成的颜色图具有许多良好的特性。重要的是,设计过程的许多方面都是可参数化的。

Matplotlib 内置了默认的 cubehelix 版本:

>>> sns.color_palette("cubehelix", as_cmap=True)
cubehelix
cubehelix colormap
under
bad
over

seaborn cubehelix_palette()函数返回的默认调色板与matplotlib的默认调色板略有不同,因为它不会绕色调轮旋转那么远,也不会覆盖那么宽的强度范围。它还反转了亮度渐变:

>>> sns.cubehelix_palette(as_cmap=True)
seaborn_cubehelix
seaborn_cubehelix colormap
under
bad
over

cubehelix_palette()的其他参数控制面板的外观。您将更改的两个主要内容是开始(0到3之间的值)rot,或旋转次数(一个任意值,但通常在-1到1之间)。

>>> sns.cubehelix_palette(start=.5, rot=-.5, as_cmap=True)
seaborn_cubehelix
seaborn_cubehelix colormap
under
bad
over

旋转得越多,看到的色调变化就越多:

>>> sns.cubehelix_palette(start=.5, rot=-.75, as_cmap=True)
seaborn_cubehelix
seaborn_cubehelix colormap
under
bad
over

您可以控制端点的深色和浅色及其顺序:

>>> sns.cubehelix_palette(start=2, rot=0, dark=0, light=.95, reverse=True, as_cmap=True)
seaborn_cubehelix
seaborn_cubehelix colormap
under
bad
over

color_palette()接受以"ch:"开头的字符串代码,用于生成任意立方体螺旋调色板。你可以在字符串中传递参数的名称:

>>> sns.color_palette("ch:start=.2,rot=-.3", as_cmap=True)
seaborn_cubehelix
seaborn_cubehelix colormap
under
bad
over

为了紧凑起见,每个参数都可以用其首字母指定:

>>> sns.color_palette("ch:s=-.2,r=.6", as_cmap=True)
seaborn_cubehelix
seaborn_cubehelix colormap
under
bad
over

自定义顺序调色板

对于自定义顺序调色板的简单接口,您可以使用light_palette()dark_palette(),它们都是单一颜色的种子,并产生从浅色或深色去饱和值渐变到该颜色的调色板:

>>> sns.light_palette("seagreen", as_cmap=True)
blend
blend colormap
under
bad
over
>>> sns.dark_palette("#69d", reverse=True, as_cmap=True)
blend
blend colormap
under
bad
over

与立方螺旋调色板一样,你也可以通过color_palette()或任何可接受的palette指定浅色或深色调色板:

>>> sns.color_palette("light:b", as_cmap=True)
blend
blend colormap
under
bad
over

通过添加“_r”来反转颜色图:

>>> sns.color_palette("dark:salmon_r", as_cmap=True)
blend
blend colormap
under
bad
over

Sequential Color Brewer 调色板

Color Brewer 库也有一些不错的顺序调色板选项。它们包括具有一种主要色调的调色板:

>>> sns.color_palette("Blues", as_cmap=True)
Blues
Blues colormap
under
bad
over

除了多色调选项外:

>>> sns.color_palette("YlOrBr", as_cmap=True)
YlOrBr
YlOrBr colormap
under
bad
over

5.13.5. 不同的调色板

第三类调色板称为“发散”。这些值用于同时具有较大的低值和高值的数据,并且跨越应取消强调的中点值(通常为 0)。选择好的发散调色板的规则与好的顺序调色板类似,只是现在颜色图中应该有两个主色调,一个在(或靠近)每个极点。起始值的亮度和饱和度相似也很重要。

感知均匀的发散调色板

Seaborn包括两个感知上一致的不同调色板:“vlag”“icefire”。它们的两极都是蓝色和红色,许多人直观地将其处理为“冷”和“热”:

>>> sns.color_palette("vlag", as_cmap=True)
vlag
vlag colormap
under
bad
over
>>> sns.color_palette("icefire", as_cmap=True)
icefire
icefire colormap
under
bad
over

自定义发散调色板

您还可以使用seaborn函数diverging_palette()为发散数据创建自定义颜色图。这个功能使用husl颜色系统来制作不同的调色板。你给它传递两种色调(以度为单位),以及可选的极端亮度和饱和度值。使用husl意味着极值,以及由此产生的向中点的倾斜,虽然在感知上不是完全一致的,但将得到很好的平衡:

>>> sns.diverging_palette(220, 20, as_cmap=True)
blend
blend colormap
under
bad
over

当您想摆脱冷热方法的无聊范围时,这很方便:

>>> sns.diverging_palette(145, 300, s=60, as_cmap=True)
blend
blend colormap
under
bad
over

也可以制作一个中点为深色而不是浅色的调色板:

>>> sns.diverging_palette(250, 30, l=65, center="dark", as_cmap=True)
blend
blend colormap
under
bad
over

这里需要强调的是,使用红色和绿色虽然很直观,但应该避免使用。

其他发散调色板

matplotlib 中还内置了一些其他不错的发散调色板,包括 Color Brewer 调色板:

>>> sns.color_palette("Spectral", as_cmap=True)
Spectral
Spectral colormap
under
bad
over

coolwarm调色板,中间值和极端值之间的对比较小:

>>> sns.color_palette("coolwarm", as_cmap=True)
coolwarm
coolwarm colormap
under
bad
over

如您所见,在可视化中使用颜色的选项有很多。Seaborn 尝试使用良好的默认值并提供很大的灵活性。

此讨论只是一个开始,有许多很好的资源可用于了解有关在可视化中使用颜色的技术的更多信息。一个很好的例子是NASA地球天文台的这一系列博客文章。matplotlib 文档也有一个很好的教程,说明了它们颜色图的一些感知属性。