选择调色板#
Seaborn 使得使用适合数据特征和可视化目标的颜色的操作变得容易。本章将讨论指导选择的一般原则以及 seaborn 中帮助您快速找到最佳解决方案的工具。
在绘图中使用颜色的基本原则#
颜色的组成部分#
由于我们眼睛的工作方式,特定颜色可以使用三个组成部分来定义。我们通常通过指定颜色的 RGB 值来在计算机中编程颜色,这些值设置显示器中红色、绿色和蓝色通道的强度。但为了分析颜色的感知属性,最好从色调、饱和度和亮度通道的角度考虑。
色调是区分非技术意义上的“不同颜色”的组成部分。它是导致“红色”和“蓝色”等一级名称的颜色的属性。
饱和度(或色度)是色彩度。两种不同色调的颜色,当它们具有更高的饱和度时,看起来会更加明显。
亮度对应于发射的光量(或印刷颜色反射的光量),从黑色到白色不等。
改变色调以区分类别#
当您想要在绘图中表示多个类别时,通常应该改变元素的颜色。考虑这个简单的例子:在这两个图中哪个更容易计算三角形点的数量?
在右边的图中,橙色的三角形“脱颖而出”,使其易于与圆形区分开来。这种脱颖而出的效果发生是因为我们的视觉系统优先考虑颜色差异。
蓝色和橙色的颜色主要在色调方面有所不同。色调对于表示类别很有用:大多数人可以比较容易地区分适度的色调,并且具有不同色调但亮度或强度相似的点看起来同样重要。它还使绘图更容易讨论。考虑这个例子
大多数人能够很快地确定左边的图中有五个不同的类别,如果被要求描述“蓝色”点,他们能够做到。
对于右边的图,其中所有点都是蓝色,但亮度和饱和度不同,很难说有多少个独特的类别。我们如何谈论一个特定的类别?“相当但不太蓝的点?”更重要的是,灰色点似乎淡入背景,相对较强的蓝色点而言,它们被弱化了。如果类别同等重要,那么这是一种糟糕的表示。
因此,作为一个通用的规则,使用色调变化来表示类别。也就是说,这里有一些注意事项。如果您的绘图中有多于几个颜色,那么可能很难记住每个颜色代表什么,除非类别和用于表示它们的颜色的之间存在预先存在的关联。这使得您的绘图更难解释:观察者不会专注于数据,而是必须不断参考图例才能理解所显示的内容。因此,您应该努力避免制作过于复杂的绘图。还要注意,并非每个人都以相同的方式看到颜色。改变形状(或其他属性)和颜色可以帮助具有异常色觉的人理解您的绘图,并且如果它们被打印成黑白,它可以使它们(稍微)可解释。
改变亮度以表示数字#
另一方面,色调变化不适合表示数值数据。考虑这个例子,我们需要颜色来表示双变量直方图中的计数。在左边,我们使用循环颜色图,其中每个箱中观察结果数量的逐渐变化对应于色调的逐渐变化。在右边,我们使用一个调色板,使用更亮的色调来表示具有较大计数的箱。
使用基于色调的调色板,很难确定双变量分布的形状。相反,亮度调色板更清楚地表明存在两个明显的峰值。
改变亮度可以帮助您看到数据中的结构,亮度的变化更直观地被处理为重要性的变化。但是右边的图没有使用灰度颜色图。它的色彩度使它更有趣,微妙的色调变化增加了两个值之间的感知距离。因此,微小的差异更容易分辨。
这些例子表明,调色板的选择不仅仅是审美问题:如果您有效地使用颜色,您可以揭示数据中的模式,或者如果使用不当,可能会隐藏这些模式。没有一个最佳的调色板,但对于特定的数据集和可视化方法而言,有些调色板更好或更差。
审美也确实很重要:人们越想看您的图形,他们从中学到东西的机会就越大。即使您是在为自己制作绘图时也是如此。在探索性数据分析期间,您可能会生成许多相似的图形。改变调色板会增加一种新颖感,这会让您保持参与并准备注意到数据中的有趣特征。
那么,您如何选择既能很好地代表数据又看起来美观的调色板呢?
选择调色板的工具#
用于处理调色板的最重要函数是 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()
提供的不同选项,介绍一种对调色板进行分类的方案将是有用的。总体而言,调色板属于以下三类之一
定性调色板,适合表示分类数据
连续调色板,适合表示数值数据
发散调色板,适合表示具有分类边界的数值数据
定性调色板#
定性调色板非常适合表示分类数据,因为它们的大部分变化都在色调组成部分中。seaborn 中的默认调色板是一个具有十种不同色调的定性调色板
sns.color_palette()
这些颜色的顺序与默认的 matplotlib 调色板 "tab10"
相同,但它们的颜色强度略低。比较
sns.color_palette("tab10")
实际上,Seaborn 有 matplotlib 调色板的六种变体,分别称为 deep
、muted
、pastel
、bright
、dark
和 colorblind
。它们跨越了一系列平均亮度和饱和度值
许多人发现默认的 "deep"
调色板的适度色调在审美上令人愉悦,但它们也鲜明度较低。因此,在某些情况下它们可能更难区分,在制作出版物图形时要牢记这一点。 此比较 可以帮助估计模拟不同色盲形式时 seaborn 调色板的表现。
使用循环色系#
当您有任意数量的类别时,找到独特色调的最简单方法是在循环色空间(色调发生变化而亮度和饱和度保持恒定)中绘制等间距的颜色。当 seaborn 函数需要使用比当前默认颜色循环中设置的颜色更多的颜色时,这就是大多数 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")
顺序调色板#
第二类主要颜色调色板称为“顺序”。这种映射适合数据从相对较低或不感兴趣的值到相对较高或感兴趣的值(反之亦然)的情况。正如我们上面所看到的,顺序调色板中主要的变异维度是亮度。当您映射数值数据时,一些 seaborn 函数将默认使用顺序调色板。(出于历史原因,分类和数值映射都使用 hue
参数在函数中指定,例如 relplot()
或 displot()
,即使数值映射使用色调变化相对较小的调色板)。
感知均匀调色板#
由于它们旨在表示数值,因此最佳的顺序调色板将是感知均匀的,这意味着两种颜色的相对可辨别性与相应数据值之间的差异成正比。Seaborn 包含四个感知均匀的顺序颜色映射:"rocket"
、"mako"
、"flare"
和 "crest"
。前两个具有非常宽的亮度范围,非常适合热图等应用,其中颜色填充它们被绘制到的空间。
sns.color_palette("rocket", as_cmap=True)
sns.color_palette("mako", as_cmap=True)
由于这些颜色映射的极值接近白色,因此它们不适合对线条或点等元素进行着色:很难区分白色或灰色背景上的重要值。“flare”和“crest”颜色映射更适合此类绘图。它们具有更受限的亮度变化范围,它们通过略微更明显的色调变化来弥补这一点。亮度斜坡的默认方向也被反转,因此较小的值具有较浅的颜色。
sns.color_palette("flare", as_cmap=True)
sns.color_palette("crest", as_cmap=True)
还可以使用 matplotlib 提供的感知均匀颜色映射,例如 "magma"
和 "viridis"
。
sns.color_palette("magma", as_cmap=True)
sns.color_palette("viridis", as_cmap=True)
与 matplotlib 中的约定一样,每个连续颜色映射都有一个反转版本,其后缀为 "_r"
。
sns.color_palette("rocket_r", as_cmap=True)
离散与连续映射#
需要注意的一点是,seaborn 可以从顺序颜色映射中生成离散值,并且在这样做时,它不会使用最极端的那些值。比较 "rocket"
的离散版本与上面显示的连续版本。
sns.color_palette("rocket")
在内部,seaborn 使用离散版本用于分类数据,使用连续版本用于数值映射模式。离散顺序颜色映射非常适合可视化具有内在排序的分类数据,尤其是如果存在一些色调变化。
顺序“cubehelix”调色板#
感知均匀颜色映射很难以编程方式生成,因为它们不是基于 RGB 颜色空间。这 cubehelix 系统提供了一种基于 RGB 的折衷方案:它生成具有线性亮度增加或减少以及一些连续色调变化的顺序调色板。虽然并非完全感知均匀,但生成的调色板具有许多良好的属性。重要的是,设计过程的许多方面都是可参数化的。
Matplotlib 具有内置的默认 cubehelix 版本。
sns.color_palette("cubehelix", as_cmap=True)
seaborn cubehelix_palette()
函数返回的默认调色板与 matplotlib 默认调色板略有不同,因为它不会在色轮上旋转那么远,也不会覆盖那么广泛的强度范围。它还反转了亮度斜坡。
sns.cubehelix_palette(as_cmap=True)
对 cubehelix_palette()
的其他参数控制调色板的外观。您将更改的两个主要内容是 start
(0 到 3 之间的值)和 rot
或旋转次数(任意值,但通常在 -1 和 1 之间)。
sns.cubehelix_palette(start=.5, rot=-.5, as_cmap=True)
您旋转的越多,您将看到更多的色调变化。
sns.cubehelix_palette(start=.5, rot=-.75, as_cmap=True)
您可以控制端点的暗度和亮度以及它们的顺序。
sns.cubehelix_palette(start=2, rot=0, dark=0, light=.95, reverse=True, as_cmap=True)
这 color_palette()
接受一个以 "ch:"
开头的字符串代码,用于生成任意 cubehelix 调色板。您可以在字符串中传递参数名称。
sns.color_palette("ch:start=.2,rot=-.3", as_cmap=True)
为了简洁,每个参数都可以使用其首字母指定。
sns.color_palette("ch:s=-.2,r=.6", as_cmap=True)
自定义顺序调色板#
对于自定义顺序调色板的更简单界面,您可以使用 light_palette()
或 dark_palette()
,它们都以单色为种子,并产生一个从浅色或深色不饱和值到该颜色的斜坡。
sns.light_palette("seagreen", as_cmap=True)
sns.dark_palette("#69d", reverse=True, as_cmap=True)
与 cubehelix 调色板一样,您也可以通过 color_palette()
或任何接受 palette
的地方指定浅色或深色调色板。
sns.color_palette("light:b", as_cmap=True)
通过添加 "_r"
来反转颜色映射。
sns.color_palette("dark:salmon_r", as_cmap=True)
顺序 Color Brewer 调色板#
Color Brewer 库还提供了一些用于顺序调色板的不错选项。它们包括包含一种主要色调的调色板。
sns.color_palette("Blues", as_cmap=True)
以及多色调选项。
sns.color_palette("YlOrBr", as_cmap=True)
发散调色板#
第三类颜色调色板称为“发散”。它们用于数据,其中较低值和较高值都很有趣,并且跨越一个应该被弱化的中间值(通常为 0)。选择好的发散调色板的规则类似于好的顺序调色板,除了现在颜色映射中应该有两个主要的色调,一个在(或接近)每个极点。同样重要的是,起始值具有相似的亮度和饱和度。
感知均匀发散调色板#
Seaborn 包含两个感知均匀的发散调色板:"vlag"
和 "icefire"
。它们都在它们的极点使用蓝色和红色,许多人直觉地将其处理为“冷”和“热”。
sns.color_palette("vlag", as_cmap=True)
sns.color_palette("icefire", as_cmap=True)
自定义发散调色板#
您也可以使用 seaborn 函数 diverging_palette()
为发散数据创建自定义颜色映射。此函数使用 husl
颜色系统创建发散调色板。您向它传递两个色调(以度为单位),以及可选的极端的亮度和饱和度值。使用 husl
意味着极值以及到中点的结果斜坡虽然并非完全感知均匀,但将是平衡的。
sns.diverging_palette(220, 20, as_cmap=True)
当您想偏离冷热方法的枯燥限制时,这很方便。
sns.diverging_palette(145, 300, s=60, as_cmap=True)
还可以创建一个调色板,其中中间点是暗色的,而不是浅色的。
sns.diverging_palette(250, 30, l=65, center="dark", as_cmap=True)
在这里,重要的是要强调,使用红色和绿色虽然直观,但 应该避免。
其他发散调色板#
matplotlib 中内置了一些其他不错的发散调色板,包括 Color Brewer 调色板。
sns.color_palette("Spectral", as_cmap=True)
以及 coolwarm
调色板,它在中间值和极值之间具有较低的对比度。
sns.color_palette("coolwarm", as_cmap=True)
如您所见,在可视化中使用颜色有很多选择。Seaborn 试图既使用良好的默认值,又提供很大的灵活性。
本讨论仅仅是开始,还有许多好的资源可以帮助您了解有关在可视化中使用颜色的技术的更多信息。一个很好的例子是来自 NASA 地球观测站的 一系列博客文章。matplotlib 文档中也有一个 不错的教程,它说明了它们颜色映射的一些感知属性。