在Matplotlib中创建颜色映射

Matplotlib有许多内置的颜色映射,可通过 matplotlib.cm.get_cmap . 还有一些外部库,比如 palettable 有很多额外的彩色地图。

但是,我们经常希望在Matplotlib中创建或操作颜色映射。这可以用类来完成 ListedColormapLinearSegmentedColormap . 从外部看,colormap类都将0到1之间的值映射到一组颜色。不过,有一些细微差别,如下所示。

在手动创建或操作colormaps之前,让我们先看看如何从现有的colormap类获取colormaps及其颜色。

获取颜色映射并访问其值

首先,获取一个命名的颜色映射,其中大部分列在 在Matplotlib中选择颜色映射 ,可以使用 matplotlib.cm.get_cmap ,返回colormap对象。第二个参数给出了用于定义colormap的颜色列表的大小,在下面我们使用一个适中的值8,因此没有太多的值可以查看。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap

viridis = cm.get_cmap('viridis', 8)

客体 viridis 是可调用的,当传递介于0和1之间的浮点值时,将从颜色映射返回rgba值:

print(viridis(0.56))

出:

(0.122312, 0.633153, 0.530398, 1.0)

ListedColormap

ListedColormap 将颜色值存储在 .colors 属性。可以使用 colors 属性,或者可以通过调用 viridis 与颜色映射的长度匹配的值数组。请注意,返回的列表以rgba nx4数组的形式出现,其中n是颜色映射的长度。

print('viridis.colors', viridis.colors)
print('viridis(range(8))', viridis(range(8)))
print('viridis(np.linspace(0, 1, 8))', viridis(np.linspace(0, 1, 8)))

出:

viridis.colors [[0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]
viridis(range(8)) [[0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]
viridis(np.linspace(0, 1, 8)) [[0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]

颜色映射是一个查找表,因此“过采样”颜色映射将返回最近的邻居插值(请注意下面列表中重复的颜色)

print('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12)))

出:

viridis(np.linspace(0, 1, 12)) [[0.267004 0.004874 0.329415 1.      ]
 [0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]

LinearSegmentedColormap

LinearSegmentedColormap s没有 .colors 属性。但是,仍然可以使用整数数组或0到1之间的浮点数组调用colormap。

copper = cm.get_cmap('copper', 8)

print('copper(range(8))', copper(range(8)))
print('copper(np.linspace(0, 1, 8))', copper(np.linspace(0, 1, 8)))

出:

copper(range(8)) [[0.         0.         0.         1.        ]
 [0.17647055 0.1116     0.07107143 1.        ]
 [0.35294109 0.2232     0.14214286 1.        ]
 [0.52941164 0.3348     0.21321429 1.        ]
 [0.70588219 0.4464     0.28428571 1.        ]
 [0.88235273 0.558      0.35535714 1.        ]
 [1.         0.6696     0.42642857 1.        ]
 [1.         0.7812     0.4975     1.        ]]
copper(np.linspace(0, 1, 8)) [[0.         0.         0.         1.        ]
 [0.17647055 0.1116     0.07107143 1.        ]
 [0.35294109 0.2232     0.14214286 1.        ]
 [0.52941164 0.3348     0.21321429 1.        ]
 [0.70588219 0.4464     0.28428571 1.        ]
 [0.88235273 0.558      0.35535714 1.        ]
 [1.         0.6696     0.42642857 1.        ]
 [1.         0.7812     0.4975     1.        ]]

创建列出的颜色映射

创建一个colormap本质上是上述操作的逆操作,我们向 ListedColormap 做一个新的颜色图。

在继续学习本教程之前,让我们定义一个helper函数,该函数以多个colormaps中的一个作为输入,创建一些随机数据,并将colormap应用于该数据集的图像绘图。

def plot_examples(colormaps):
    """
    Helper function to plot data with associated colormap.
    """
    np.random.seed(19680801)
    data = np.random.randn(30, 30)
    n = len(colormaps)
    fig, axs = plt.subplots(1, n, figsize=(n * 2 + 2, 3),
                            constrained_layout=True, squeeze=False)
    for [ax, cmap] in zip(axs.flat, colormaps):
        psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4)
        fig.colorbar(psm, ax=ax)
    plt.show()

在最简单的情况下,我们可以输入一个颜色名称列表,从中创建一个颜色映射。

cmap = ListedColormap(["darkorange", "gold", "lawngreen", "lightseagreen"])
plot_examples([cmap])
colormap manipulation

事实上,该列表可能包含任何有效的 matplotlib color specification . Nx4 numpy数组对于创建自定义颜色映射特别有用。因为我们可以在这样一个数组上执行各种numpy操作,所以从现有的颜色贴图中制作新的颜色贴图变得非常简单。

例如,假设出于某种原因,我们要将256长度的“viridis”颜色贴图的前25个条目设为粉红色:

viridis = cm.get_cmap('viridis', 256)
newcolors = viridis(np.linspace(0, 1, 256))
pink = np.array([248/256, 24/256, 148/256, 1])
newcolors[:25, :] = pink
newcmp = ListedColormap(newcolors)

plot_examples([viridis, newcmp])
colormap manipulation

我们可以很容易地减小颜色映射的动态范围;这里我们选择颜色映射的中间0.5。但是,我们需要从较大的颜色映射中插入,否则新的颜色映射将具有重复的值。

viridis_big = cm.get_cmap('viridis', 512)
newcmp = ListedColormap(viridis_big(np.linspace(0.25, 0.75, 256)))
plot_examples([viridis, newcmp])
colormap manipulation

我们可以很容易地连接两个颜色映射:

top = cm.get_cmap('Oranges_r', 128)
bottom = cm.get_cmap('Blues', 128)

newcolors = np.vstack((top(np.linspace(0, 1, 128)),
                       bottom(np.linspace(0, 1, 128))))
newcmp = ListedColormap(newcolors, name='OrangeBlue')
plot_examples([viridis, newcmp])
colormap manipulation

当然,我们不需要从一个命名的颜色映射开始,我们只需要创建一个nx4数组来传递给 ListedColormap . 这里我们创建一个从棕色(RGB:90,40,40)到白色(RGB:255,255,255)的颜色映射。

N = 256
vals = np.ones((N, 4))
vals[:, 0] = np.linspace(90/256, 1, N)
vals[:, 1] = np.linspace(40/256, 1, N)
vals[:, 2] = np.linspace(40/256, 1, N)
newcmp = ListedColormap(vals)
plot_examples([viridis, newcmp])
colormap manipulation

创建线性分段颜色映射

LinearSegmentedColormap 类使用定位点指定颜色映射,在定位点之间插入RGB(A)值。

指定这些颜色映射的格式允许在定位点处出现不连续。每个定位点在表格的矩阵中指定为一行。 [x[i] yleft[i] yright[i]] 在哪里 x[i] 是锚,和 yleft[i]yright[i] 是定位点任一侧的颜色值。

如果没有间断,那么 yleft[i]=yright[i]

cdict = {'red':   [[0.0,  0.0, 0.0],
                   [0.5,  1.0, 1.0],
                   [1.0,  1.0, 1.0]],
         'green': [[0.0,  0.0, 0.0],
                   [0.25, 0.0, 0.0],
                   [0.75, 1.0, 1.0],
                   [1.0,  1.0, 1.0]],
         'blue':  [[0.0,  0.0, 0.0],
                   [0.5,  0.0, 0.0],
                   [1.0,  1.0, 1.0]]}


def plot_linearmap(cdict):
    newcmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256)
    rgba = newcmp(np.linspace(0, 1, 256))
    fig, ax = plt.subplots(figsize=(4, 3), constrained_layout=True)
    col = ['r', 'g', 'b']
    for xx in [0.25, 0.5, 0.75]:
        ax.axvline(xx, color='0.7', linestyle='--')
    for i in range(3):
        ax.plot(np.arange(256)/256, rgba[:, i], color=col[i])
    ax.set_xlabel('index')
    ax.set_ylabel('RGB')
    plt.show()

plot_linearmap(cdict)
colormap manipulation

为了在锚定点处形成不连续性,第三列不同于第二列。“红”、“绿”、“蓝”和可选的“α”中的每一个的矩阵设置为:

cdict['red'] = [...
                [x[i]      yleft[i]     yright[i]],
                [x[i+1]    yleft[i+1]   yright[i+1]],
               ...]

对于传递到颜色映射的值, x[i]x[i+1] ,插值介于 yright[i]yleft[i+1] .

在下面的示例中,0.5处出现红色不连续。0和0.5之间的插值从0.3变为1,0.5和1之间的插值从0.9变为1。注意红色 [0, 1] 和红色 [2, 2] 都是多余的插值,因为红色 [0, 1] 是0左边的值,红色 [2, 2] 是1.0右边的值。

cdict['red'] = [[0.0,  0.0, 0.3],
                [0.5,  1.0, 0.9],
                [1.0,  1.0, 1.0]]
plot_linearmap(cdict)
colormap manipulation

从列表直接创建分段颜色映射

上面描述的是一种非常通用的方法,但是必须承认实现起来有点麻烦。对于一些基本情况 LinearSegmentedColormap.from_list 可能更容易。这将从提供的颜色列表中创建间隔相等的分段颜色贴图。

colors = ["darkorange", "gold", "lawngreen", "lightseagreen"]
cmap1 = LinearSegmentedColormap.from_list("mycmap", colors)

如果需要,可以将colormap的节点指定为0到1之间的数字。E、 你可以让红色部分在彩色地图上占据更多的空间。

nodes = [0.0, 0.4, 0.8, 1.0]
cmap2 = LinearSegmentedColormap.from_list("mycmap", list(zip(nodes, colors)))

plot_examples([cmap1, cmap2])
colormap manipulation

工具书类

以下函数、方法、类和模块的使用如本例所示:

出:

<function get_cmap at 0x7faa1673c8c8>

脚本的总运行时间: (0分3.616秒)

关键词:matplotlib代码示例,codex,python plot,pyplot Gallery generated by Sphinx-Gallery