选择调色板

优质
小牛编辑
149浏览
2023-12-01

颜色在图像风格中比起其他元素显得更为重要。当合理有效地使用颜色时,数据模式会被凸显出来;反之,则会被掩盖。这里有很多数据可视化中关于颜色使用的优秀资源,我推荐阅读这些 Rob Simmon 的博客文章以及这篇更加学术性的论文。 此外,matplotlib 文档也提供了一篇很好的教程来说明一些内置Colormap的感知属性。

seaborn让您在选择与您处理的数据类型和可视化过程中搭配的配色方案变得简单。

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
sns.set()

创建调色板

使用离散调色板过程中最重要函数是color_palette()。这个函数为许多(但不是全部)可以在seaborn中生成颜色的方式提供了一个接口,并且在任何具有palette参数的函数的内部都可以使用(以及某些需要多种颜色时具有color参数的情况)。

color_palette() 会接受所有的seaborn调色板或者matplotlib Colormap (除了 jet, 您永远都不应该使用它). 它还可以获取以任何有效matplotlib格式(RGB元组、十六进制颜色代码或HTML颜色名字)指定的颜色列表。返回值始终是RGB元组的列表。

最后,在没有参数的情况下调用color_palette()函数将会返回当前默认的颜色循环。

函数set_palette()接受相同的参数,并将为所有图像设置默认的颜色循环。您也可以在with语句中调用color_palette()来临时改变调色板。(参见)

在不了解数据特征的情况下,通常也不可能知道哪种调色板或Colormap最适合一组数据。接下来,我们将通过三种常见的调色板 定性调色板, 顺序调色板, 和 发散调色板 来拆分介绍color_palette()函数的使用方法以及其他seaborn函数。

定性调色板

当您想要区分不具有内在顺序的离散数据块时,定性(分类)调色板是最佳方案。

导入seaborn的同时,会引入默认的颜色循环,由6种颜色构成。并将调用标准matplotlib颜色循环,看起来也更加赏心悦目。

current_palette = sns.color_palette()
sns.palplot(current_palette)

http://seaborn.pydata.org/_images/color_palettes_6_0.png

默认主题有六种变体,分别为deep, muted, pastel, bright, dark, and colorblind

http://seaborn.pydata.org/_images/color_palettes_8_0.png

使用循环颜色系统

当您要区分任意数量的类别而不强调任何类别时,最简单的方法是在循环颜色空间中绘制间距相等的颜色(在此颜色空间中,色调会发生变化,同时保持亮度和饱和度不变)。这是大多数seaborn函数在处理当需要区分的数据集超过颜色循环中的6种颜色时时所使用的默认方法。

最为常用的方法是使用hls颜色空间——一种简单的RGB值变体。

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

http://seaborn.pydata.org/_images/color_palettes_10_0.png

hls_palette()函数允许您控制颜色的亮度(lightness)和饱和度(saturation)。

sns.palplot(sns.hls_palette(8, l=.3, s=.8))

http://seaborn.pydata.org/_images/color_palettes_12_0.png

然而,由于人类视觉系统的工作方式,RGB强度很高的颜色也不一定看起来同样强烈。我们认为黄色和绿色是相对较亮的,蓝色是相对较暗的,当目标是与hls系统保持一致性时可能会带来一些问题。

为了解决这一问题,seaborn提供了一个husl系统(后来更名为HSLuv)的接口,这也使选择间隔均匀的色调变得容易,同时使亮度和饱和度都更加均匀。

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

http://seaborn.pydata.org/_images/color_palettes_14_0.png

类似地,husl_palette()函数也为这个系统提供了一个更灵活的接口。

使用Color Brewer调色板

Color Brewer为定性调色板提供了另一种美观的配色方案(同样包含顺序调色板包括和发散调色板,详情见下文)。这些也作为matplotlib Colormap存在,但并没有得到很好的处理。在seaborn中,当您需要定性(qualitative)的Color Brewer方案时,你总是会得到离散的颜色,但这意味着在某些情况下颜色会循环重复。

Color Brewer的一个很好的特点是它对色盲比较友好。色盲有很多种,最为常见的是红绿色盲。通常,对于需要根据颜色进行元素区分时,应该尽量避免使用这两种颜色。

sns.palplot(sns.color_palette("Paired"))

http://seaborn.pydata.org/_images/color_palettes_16_0.png

sns.palplot(sns.color_palette("Set2"))

http://seaborn.pydata.org/_images/color_palettes_17_0.png

为了帮助您从Color Brewer库中选取配色方案,seaborn提供了choose_colorbrewer_palette()函数。这个函数能够启动交互式组件来帮助您浏览各种选项,修改不同的参数。但是只能在Jupyter notebook中使用。

当然,您可能只希望手动指定一组您喜欢的颜色。color_palette()函数会接受一个颜色列表,操作起来也很简单。

flatui = ["#9b59b6", "#3498db", "#95a5a6", "#e74c3c", "#34495e", "#2ecc71"]
sns.palplot(sns.color_palette(flatui))

http://seaborn.pydata.org/_images/color_palettes_19_0.png

使用来自xkcd color survey的颜色名字

不久前,xkcd开展了一项众包工作来为随机RGB颜色命名。产生了954个颜色名字,您现在可以在seaborn中使用xkcd_rgb字典来引用它们:

plt.plot([0, 1], [0, 1], sns.xkcd_rgb["pale red"], lw=3)
plt.plot([0, 1], [0, 2], sns.xkcd_rgb["medium green"], lw=3)
plt.plot([0, 1], [0, 3], sns.xkcd_rgb["denim blue"], lw=3);

http://seaborn.pydata.org/_images/color_palettes_21_0.png

除了从xkcd_rgb字典中提取单一颜色外,您也可以向xkcd_palette()函数传递一个颜色名字列表。

colors = ["windows blue", "amber", "greyish", "faded green", "dusty purple"]
sns.palplot(sns.xkcd_palette(colors))

http://seaborn.pydata.org/_images/color_palettes_23_0.png

顺序调色板

第二类主要的调色板被称为“顺序调色板”(sequential),当数据集的范围从相对低值(不感兴趣)到相对高值(很感兴趣)时,最好使用顺序调色板,尽管在某些情况下您可能需要顺序调色板中的离散颜色。在kdeplot()heatmap()函数中使用它们来作为Colormap则更为常见(以及类似的matplotlib函数)。

在这种情况下使用jet(或其他彩虹调色板)等Colormap是很常见的,因为色调范围给人的印象是提供有关数据的额外信息。然而,具有较大色调变化的Colormap往往会引入数据中不存在的不连续性,并且我们的视觉系统无法自然地将彩虹光谱映射到诸如“高”或“低”的定量区分。导致来这些可视化的结果更加令人困惑,因为它们掩盖了数据中的模式,而不是揭示它们。jet 调色板使用了最亮的颜色(黄色和青色)的中间数据值,导致效果是强调无趣的(和任意的)值,而不是强调极端的值。

对于连续性的数据,最好使用色调变化幅度较小,而亮度和饱和度变化幅度较大的配色方案。这种方法会很自然地吸引人们注意数据中相对重要的部分。

Color Brewer库有大量这样的配色方案,它们以调色板中主要的一种或多种颜色命名。

sns.palplot(sns.color_palette("Blues"))

http://seaborn.pydata.org/_images/color_palettes_25_0.png

与matplotlib类似,您可以通过添加加后缀_r来倒置顺序调色板的顺序。

sns.palplot(sns.color_palette("BuGn_r"))

http://seaborn.pydata.org/_images/color_palettes_27_0.png

seaborn同样添加了一个小窍门来帮助您创建“深色”调色板,它没有一个很宽的动态范围。在当您需要按顺序映射直线或点时这可能会很有用,因为颜色较亮的线条会比较难以区分。

sns.palplot(sns.color_palette("GnBu_d"))

http://seaborn.pydata.org/_images/color_palettes_29_0.png

您可能想要使用choose_colorbrewer_palette()函数来尝试多种选项,当您希望传递给seaborn或者matplotlib的返回值为Colormap对象时,您可以将as_cmap对象设置为True

顺序 “cubehelix” 调色板

cubehelix调色板系统使顺序调色板的亮度产生线性变化,色调也会产生一些变化。这意味着您的Colormap在转换为黑白模式时(用于打印)的信息将得到保留,且对色盲友好。

Matplotlib内置了默认的cubehelix版本:

sns.palplot(sns.color_palette("cubehelix", 8))

http://seaborn.pydata.org/_images/color_palettes_32_0.png

Seborn为cubehelix系统提供了一个接口,以便您可以制作各种调色板,这些调色板都具有良好的线性亮度渐变。

由seborn cubehelix_palette() 函数返回的默认调色板与matplotlib的默认值稍有不同,因为它不会围绕色轮旋转很远,也不会覆盖很宽的强度范围。它还反转顺序,以便让更重要的值的颜色更暗:

sns.palplot(sns.cubehelix_palette(8))

http://seaborn.pydata.org/_images/color_palettes_34_0.png

cubehelix_palette() 函数的其他参数控制调色板的外观。您将更改的两个主要参数为 start (介于0到3之间的值)和 rot —— 旋转次数(任意值,但可能在-1和1之间)。

sns.palplot(sns.cubehelix_palette(8, start=.5, rot=-.75))

http://seaborn.pydata.org/_images/color_palettes_36_0.png

您还可以控制端点的亮度,甚至反转渐变:

sns.palplot(sns.cubehelix_palette(8, start=2, rot=0, dark=0, light=.95, reverse=True))

http://seaborn.pydata.org/_images/color_palettes_38_0.png

如同其他seaborn函数,您将默认得到一个颜色列表。但您也可以通过修改 as_cmap=True 将调色板作为Colormap对象的返回值来传递给seaborn或matplotlib函数。

x, y = np.random.multivariate_normal([0, 0], [[1, -.5], [-.5, 1]], size=300).T
cmap = sns.cubehelix_palette(light=1, as_cmap=True)
sns.kdeplot(x, y, cmap=cmap, shade=True);

http://seaborn.pydata.org/_images/color_palettes_40_0.png

为了帮助您选择更好的调色板或者Colormap,您可以在Jupyter notebook中使用 choose_cubehelix_palette() 函数来启动互动界面帮助您测试、修改不同的参数。如果您希望函数返回一个Colormap(而不是列表),则在例如像 hexbin 这样的函数中设置 as_Cmap=True

自定义调色板

为了更简单地生成自定义顺序调色板,您可以使用 light_palette()dark_palette() 函数。它们都是以某个颜色为种子,从明向暗或从暗向明渐变,产生顺序调色板。与这些函数相搭配的还有 choose_light_palette()choose_dark_palette() 来提供交互式组件便于创建调色板。

sns.palplot(sns.light_palette("green"))

http://seaborn.pydata.org/_images/color_palettes_43_0.png

sns.palplot(sns.dark_palette("purple"))

http://seaborn.pydata.org/_images/color_palettes_44_0.png

这些调色板同样可以被反转。

sns.palplot(sns.light_palette("navy", reverse=True))

http://seaborn.pydata.org/_images/color_palettes_46_0.png

这些调色板同样可以被用来创建Colormap对象而不是颜色列表。

pal = sns.dark_palette("palegreen", as_cmap=True)
sns.kdeplot(x, y, cmap=pal);

http://seaborn.pydata.org/_images/color_palettes_48_0.png

默认情况下,输入可以是任何有效的matplotlib颜色。替代解释由 input 参数控制。现在,您可以在 hlshusl 空间中提供元组以及默认的 rgb,您也可以使用任何有效的 xkcd 颜色来生成调色板。

sns.palplot(sns.light_palette((210, 90, 60), input="husl"))

http://seaborn.pydata.org/_images/color_palettes_50_0.png

sns.palplot(sns.dark_palette("muted purple", input="xkcd"))

http://seaborn.pydata.org/_images/color_palettes_51_0.png

注意,交互式调色板小部件的默认输入空间是 husl,它不同于函数本身的默认设置,但是在这种情况下更有用。

发散调色板

第三类调色板称为“发散调色板”(diverging)。当数据集的低值和高值都很重要,且数据集中有明确定义的中点时,这会是您的最佳选择。例如,绘制温度相对于基准时间点的变化图时,最好使用发散Colormap来同时显示温度相对于基准值的上升和下降

选择良好分散调色板的规则类似于良好的顺序调色板。不过在这种情况时需要注意两端颜色向中间颜色渐变时中间点的颜色不应该喧宾夺主,两端的颜色也应该具有相似的亮度和饱和度。

这里还需要强调的是,应该避免使用红色和绿色,因为需要考虑到红绿色盲患者的观感。

不出所料,Color Brewer库也同样提供了一些精心挑选的发散调色板。

sns.palplot(sns.color_palette("BrBG", 7))

http://seaborn.pydata.org/_images/color_palettes_54_0.png

sns.palplot(sns.color_palette("RdBu_r", 7))

http://seaborn.pydata.org/_images/color_palettes_55_0.png

matplotlib库中内置的 coolwarm 调色板也是一个很好的选择。请注意,这个Colormap的中间值和极值之间的对比度较小。

sns.palplot(sns.color_palette("coolwarm", 7))

http://seaborn.pydata.org/_images/color_palettes_57_0.png

自定义发散调色板

您可以使用seaborn的diverging_palette()函数来创建自定义colormap来描述发散数据(搭配有交互式组件choose_diverging_palette())。此函数使用 husl 颜色系统来创建发散调色板,您需要在函数中设置两个色调参数(用度表示),也可以选择设置两端颜色的亮度和饱和度。 使用 husl 意味着两端到中间点的色调变化将是平衡的。

sns.palplot(sns.diverging_palette(220, 20, n=7))

http://seaborn.pydata.org/_images/color_palettes_59_0.png

sns.palplot(sns.diverging_palette(145, 280, s=85, l=25, n=7))

http://seaborn.pydata.org/_images/color_palettes_60_0.png

sep 参数控制两端到中间点色调变化的间隔。

sns.palplot(sns.diverging_palette(10, 220, sep=80, n=7))

http://seaborn.pydata.org/_images/color_palettes_62_0.png

也可以将中间点的颜色设置成暗色而非亮色。

sns.palplot(sns.diverging_palette(255, 133, l=60, n=7, center="dark"))

http://seaborn.pydata.org/_images/color_palettes_64_0.png

设置默认调色板

color_palette()函数相伴随的有set_palette()。 两者之间的关系与set_palette()函数和color_palette()函数接受相同参数的关系相类似。但它会更改默认的matplotlib参数,以便调色板应用于所有图像。

def sinplot(flip=1):
    x = np.linspace(0, 14, 100)
    for i in range(1, 7):
        plt.plot(x, np.sin(x + i * .5) * (7 - i) * flip)

sns.set_palette("husl")
sinplot()

http://seaborn.pydata.org/_images/color_palettes_67_0.png

您可以在 with 语句中通过 color_palette() 函数来临时改变调色板。

with sns.color_palette("PuBuGn_d"):
    sinplot()

http://seaborn.pydata.org/_images/color_palettes_69_0.png