Matplotlib有许多内置的颜色映射,可通过Matplotlib.colormaps访问。还有一些外部库,如palettable,具有许多额外的颜色映射。 然而,我们通常希望在Matplotlib中创建或操作颜色映射。这可以使用ListedColormap或LinearSegmentedColormap类来完成。从外部看,两个colormap类都将0和1之间的值映射为一组颜色。然而,也存在一些细微的差异,其中一些差异后续会讲到。
在手动创建或操作颜色映射之前,让我们先看看如何从现有的颜色映射类中获取颜色映射及其颜色。
获取颜色映射并访问其值 首先,可以调用Matplotlib.colormaps返回一个颜色映射对象来获得命名的颜色映射,其中大部分列在Matplotlib中的“选择颜色映射”中(Choosing Colormaps in Matplotlib)。内部用于定义颜色映射的颜色列表的长度可以通过Colormap.resampled进行调整。下面我们使用了一个适度的值8,因此没有太多的值可以查看。
·
·
·
·
·
·
import numpy as npimport matplotlib.pyplot as pltimport matplotlib as mplfrom matplotlib.colors import ListedColormap, LinearSegmentedColormap
viridis = mpl.colormaps['viridis'].resampled(8)
对象viridis是可调用的,当传递0和1之间的浮点值时,会从颜色映射返回RGBA值:
·
print(viridis(0.56))
输出:
·
(0.122312, 0.633153, 0.530398, 1.0)
列表颜色映射(ListedColormap) ListedColormaps将其颜色值存储在.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) LinearSegmentedColormaps没有.colors属性。然而,仍然可以用整数数组或0到1之间的浮点数组调用颜色映射。
·
·
·
·
copper = mpl.colormaps['copper'].resampled(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. ]]
创建列表颜色映射 创建颜色映射本质上与上面的操作相反,我们向ListedColormap提供颜色规格的列表或数组,以创建新的颜色映射。 在继续本教程之前,让我们定义一个辅助函数,该函数以一个或多个颜色映射作为输入,创建一些随机数据,并将颜色映射应用于该数据集的图像中。
·
·
·
·
·
·
·
·
·
·
·
·
·
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])
事实上,该列表可能包含任何有效的Matplotlib颜色规格(Matplotlib color specification)。Nx4 numpy数组对于创建自定义颜色映射特别有用。因为我们可以在这样的数组上进行各种各样的numpy操作,所以从现有的颜色映射中提取新的颜色映射变得非常简单。 例如,假设出于某种原因,我们想使256长度的“viridis”颜色图的前25个条目为粉红色:
·
·
·
·
·
·
·
viridis = mpl.colormaps['viridis'].resampled(256)newcolors = viridis(np.linspace(0, 1, 256))pink = np.array([248/256, 24/256, 148/256, 1])newcolors[:25, :] = pinknewcmp = ListedColormap(newcolors)
plot_examples([viridis, newcmp])
我们可以缩小颜色映射的动态范围;这里我们选择颜色图的中间部分。然而,请注意,由于viridis是一个列表颜色映射,我们最终会得到128个离散值,而不是原始颜色映射中的256个值。此方法不会在颜色空间中进行插值以添加新的颜色。
·
·
·
viridis_big = mpl.colormaps['viridis']newcmp = ListedColormap(viridis_big(np.linspace(0.25, 0.75, 128)))plot_examples([viridis, newcmp])
我们也可以很容易地连接两个颜色映射:
·
·
·
·
·
·
·
top = mpl.colormaps['Oranges_r'].resampled(128)bottom = mpl.colormaps['Blues'].resampled(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])
当然,我们不需要从命名的颜色映射开始,我们只需要创建Nx4数组来传递给ListedColormap。在这里,我们创建了一个从棕色(RGB:90,40,40)到白色(RGB:255,255,255)的颜色映射。
·
·
·
·
·
·
·
N = 256vals = 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])
创建线性分段颜色映射 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)
为了在锚点处形成不连续性,第三列与第二列不同。“红色”、“绿色”、“蓝色”和可选的“透明度”的矩阵设置为:
·
·
·
·
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。请注意,red[0, 1]和red[2, 2]对于插值来说都是多余的,因为red[0, 1](即yleft[0])是0左边的值,而red[2, 2](即yright[2])是1右边的值,它们在颜色映射域之外。
·
·
·
·
cdict['red'] = [[0.0, 0.0, 0.3], [0.5, 1.0, 0.9], [1.0, 1.0, 1.0]]plot_linearmap(cdict)
直接用列表创建分段颜色映射 上面描述的方法非常通用,但无可否认,实现起来有点麻烦。对于某些简单使用情景,使用LinearSegmentedColormap.from_list可能更容易。它采用提供的颜色列表来创建具有相等间距的分段颜色映射。
·
·
colors = ["darkorange", "gold", "lawngreen", "lightseagreen"]cmap1 = LinearSegmentedColormap.from_list("mycmap", colors)
如果需要,可以将颜色映射的节点指定为0到1之间的数字。例如,可以让红色部分在颜色映射中占据更多空间。
·
·
·
·
nodes = [0.0, 0.4, 0.8, 1.0]cmap2 = LinearSegmentedColormap.from_list("mycmap", list(zip(nodes, colors)))
plot_examples([cmap1, cmap2])
反转颜色映射 Colormap.reversed创建一个新的颜色映射,该颜色映射是原始颜色映射的反转版本。
·
·
·
·
·
·
colors = ["#ffffcc", "#a1dab4", "#41b6c4", "#2c7fb8", "#253494"]my_cmap = ListedColormap(colors, name="my_cmap")
my_cmap_r = my_cmap.reversed()
plot_examples([my_cmap, my_cmap_r])
如果没有传入名称,.reversed还会通过在原始颜色映射的名称后面附加“_r”来命名副本。
注册颜色映射 颜色映射可以添加到命名颜色映射matplotlib.colormaps列表中。这允许在绘图时按名称访问颜色映射:
·
·
·
·
·
·
·
·
·
·
·
·
# my_cmap, my_cmap_r from reversing a colormapmpl.colormaps.register(cmap=my_cmap)mpl.colormaps.register(cmap=my_cmap_r)
data = [[1, 2, 3, 4, 5]]
fig, (ax1, ax2) = plt.subplots(nrows=2)
ax1.imshow(data, cmap='my_cmap')ax2.imshow(data, cmap='my_cmap_r')
plt.show()
参考 以下函数、方法、类和模块的使用如本例所示:matplotlib.axes.Axes.pcolormeshhttps://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.pcolormesh.html#matplotlib.axes.Axes.pcolormeshmatplotlib.figure.Figure.colorbarhttps://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure.colorbarmatplotlib.colorshttps://matplotlib.org/stable/api/colors_api.html#module-matplotlib.colorsmatplotlib.colors.LinearSegmentedColormaphttps://matplotlib.org/stable/api/_as_gen/matplotlib.colors.LinearSegmentedColormap.html#matplotlib.colors.LinearSegmentedColormapmatplotlib.colors.ListedColormaphttps://matplotlib.org/stable/api/_as_gen/matplotlib.colors.ListedColormap.html#matplotlib.colors.ListedColormapmatplotlib.cmhttps://matplotlib.org/stable/api/cm_api.html#module-matplotlib.cm
matplotlib.colormaps
https://matplotlib.org/stable/api/matplotlib_configuration_api.html#matplotlib.colormaps
本文链接matplotlib.colormaps:
https://matplotlib.org/stable/api/matplotlib_configuration_api.html#matplotlib.colormaps
ListedColormap:
https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.ListedColormap.html#matplotlib.colors.ListedColormap
LinearSegmentedColormap:
https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.LinearSegmentedColormap.html#matplotlib.colors.LinearSegmentedColormap
Choosing Colormaps in Matplotlib:
https://matplotlib.org/stable/tutorials/colors/colormaps.html
Colormap.resampled:
https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.Colormap.html#matplotlib.colors.Colormap.resampled
LinearSegmentedColormap.from_list:
https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.LinearSegmentedColormap.html#matplotlib.colors.LinearSegmentedColormap.from_list
Colormap.reversed:
https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.Colormap.html#matplotlib.colors.Color