HOWTO · Matplotlib

使用 Python Matplotlib 自定义颜色图

本文讨论了我们如何在 Python 中使用 Matplotlib 创建自定义颜色图。它将展示两种使用 ListedColormap 类和 LinearSegmentedColormap 类在 Python 中使用 Matplotlib 创建自定义颜色图的方法。

本页内容

每个类别都需要专属颜色时使用 ListedColormap;数值需要沿渐变过渡时使用 LinearSegmentedColormap。这两种都是 Matplotlib 颜色映射类,可通过 cmap 参数传给绘图函数。本指南还介绍如何检查内置颜色映射表并获取其 RGBA 值。

在 Python 中使用 Matplotlib 创建自定义颜色映射表

颜色映射表会将数值映射为颜色。对于类别编码或少量固定颜色,可以定义 ListedColormap;对于颜色需要平滑混合的测量值,可以定义 LinearSegmentedColormap。应用任一种映射表时,都应使用与待着色数值范围相匹配的归一化方法,否则图中颜色可能无法准确表示预期的数据范围。

在 Python 中使用 Matplotlib 的 get_cmap() 函数访问颜色映射表及其取值

get_cmap() 函数用于获取指定名称的内置颜色映射表。颜色映射表可以像函数一样调用:传入 0 到 1 之间的数值即可得到一个 RGBA 元组,其中最后一个分量表示不透明度。若要检查采样得到的多个颜色,则传入一组数值。下面的示例会打印一个采样颜色:

import matplotlib.pyplot as plt

viridis = plt.get_cmap("viridis")
print(viridis(0.56))
(np.float64(0.120081), np.float64(0.622161), np.float64(0.534946), np.float64(1.0))

若要创建有限大小的查找表,可使用 viridis.resampled(8) 对映射表重新采样。ListedColormap 可通过 colors 属性提供其条目;对于 LinearSegmentedColormap 这样的连续映射表,则可传入数值调用它来进行采样。

在 Python 中使用 ListedColormap 的 colors 属性创建自定义离散颜色映射表

ListedColormap 接受颜色名称或数值形式的 RGBA 条目。RGBA 通道值通常位于 0 到 1 之间。当映射表以列表形式表示时,其 colors 属性包含这些离散条目。下面的独立示例展示这两种构造方式,并将颜色名称映射表应用于散点图中的类别编码。请根据自己的数据调整 categories 和归一化设置。

import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap, Normalize

named_map = ListedColormap(["darkorange", "gold", "lightseagreen"], name="groups")
rgba_map = ListedColormap([
    (0.58, 0.41, 0.27, 1.0),
    (0.00, 0.41, 0.27, 1.0),
    (0.58, 0.00, 0.27, 1.0),
], name="rgba_groups")

x = [1, 2, 3, 4, 5, 6]
y = [1, 4, 2, 5, 3, 6]
categories = [0, 0, 1, 1, 2, 2]
plt.scatter(x, y, c=categories, cmap=named_map, norm=Normalize(0, 2))
plt.colorbar(ticks=[0, 1, 2])
plt.show()

Normalize(0, 2) 会将类别编码映射到这三个颜色条目,颜色条刻度则标出对应的编码。使用 rgba_map.colors 可以检查明确指定的 RGBA 列表。如果颜色数量与类别编码数量不同,请调整映射表或归一化设置,确保每个类别都按预期分配颜色。

如何在 Python 中创建自定义线性分段颜色映射表?

LinearSegmentedColormap 会在指定位置之间插值颜色通道,从而生成渐变。它的 cdict(颜色字典)包含 red、green 和 blue 等通道键。每个通道中的行格式为 [x, yleft, yright]:x 是 0 到 1 之间的位置,另外两个值分别表示该位置左侧和右侧的通道值。位置应从 0 到 1 递增。锚点处左右值相同表示颜色连续过渡;左右值不同则表示颜色发生跳变。

下面的独立示例创建一个由锚点定义的渐变,以及另一个通过 from_list() 创建的渐变,并将它们分别显示在示例数据上。图中标题“Anchors”和“Color list”保留为英文:“Anchors”对应锚点渐变,“Color list”对应通过 from_list() 创建的渐变。渲染出的图形未经目视检查。

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap

cdict = {
    "red": [(0.0, 0.0, 0.0), (0.5, 0.1, 0.1), (1.0, 1.0, 1.0)],
    "green": [(0.0, 0.0, 0.0), (0.5, 0.8, 0.8), (1.0, 0.2, 0.2)],
    "blue": [(0.0, 0.4, 0.4), (0.5, 0.1, 0.1), (1.0, 0.0, 0.0)],
}
anchor_map = LinearSegmentedColormap("anchor_gradient", cdict, N=256)
list_map = LinearSegmentedColormap.from_list(
    "list_gradient", ["navy", "gold", "crimson"], N=256
)

values = np.arange(36).reshape(6, 6)
fig, axes = plt.subplots(1, 2)
for ax, cmap, title in zip(axes, [anchor_map, list_map], ["Anchors", "Color list"]):
    image = ax.imshow(values, cmap=cmap)
    ax.set_title(title)
    fig.colorbar(image, ax=ax)
plt.tight_layout()
plt.show()

需要精细控制通道值或明确指定锚点时,使用字典构造方式。若要通过一组命名颜色创建简单的渐变,可使用 LinearSegmentedColormap.from_list();这些颜色会在整个映射表范围内插值。N 设置查找表的大小,gamma 控制输入位置的缩放。

总结

对于需要明确分配颜色的离散类别,选择 ListedColormap。对于连续渐变,选择 LinearSegmentedColormap,并使用 cdict 锚点或 from_list() 颜色列表来定义渐变。使用 get_cmap() 获取内置映射表,检查采样得到的 RGBA 值,再配合适当的归一化方法将所选映射表传给绘图函数。