首页编程开发Matplotlib【数据可视化(Matplo...

【数据可视化(Matplotlib篇)】29.色彩映射图Colormaps

本系列文章配套代码获取有以下两种途径:

  • 通过百度网盘获取:
链接:https://pan.baidu.com/s/1jG-rGG4QMuZu0t0kEEl7SA?pwd=mnsj 提取码:mnsj
  • 前往GitHub获取
https://github.com/returu/Data_Visualization





色彩映射图(Colormap)是一个从数据区间(例如,0到1)到颜色空间的映射函数。在Matplotlib 中,它通常是一个包含一系列颜色的列表,这些颜色在特定的数据值上平滑地过渡。Matplotlib中,Colormap主要应用于热图、散点图、等高线图等需要表示数据强度的场景。
色彩映射图是数据可视化中至关重要的一环,它决定了如何将数据值映射到颜色,从而直观地传达数据的分布、大小和模式。一个合适的色彩映射可以使图表清晰易懂,而一个不合适的则可能导致误解或难以阅读。
01

使用示例


Matplotlib中,色彩映射过程只需通过cmap参数指定Colormap就能实现。

另外,当使用色彩映射图时,一般会增加色彩条Colorbar,其作用是把 colormap 的“数值↔颜色”对应关系可视化,作为图例放在图的旁边。

# 创建一些示例数据
data = np.random.randn(10, 10) # 10x10 的随机数据
x = np.random.rand(100)
y = np.random.rand(100)
z = np.random.rand(100) * 100  # 颜色值

# 创建子图
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))

# 示例 1: 使用 imshow 绘制二维数组
im = ax1.imshow(data, cmap='viridis')  # 通过cmap参数指定色彩映射为viridis
ax1.set_title('2D Array with Viridis Colormap')
fig.colorbar(im, ax=ax1)  # 添加颜色条,它从 im 获取 cmap 信息

# 示例 2: 使用 scatter 绘制散点图,点的大小颜色由 z 决定
sc = ax2.scatter(x, y, c=z, cmap='plasma', s=50, alpha=0.7)  # 通过cmap参数指定色彩映射为plasma
ax2.set_title('Scatter Plot with Plasma Colormap')
fig.colorbar(sc, ax=ax2)  # 为散点图添加颜色条

plt.tight_layout()
plt.show()
可视化结果如下图所示:


02

选择和获取Colormap


  • 查看所有可用的 Colormap:
Matplotlib 提供了大量内置的 colormap。可以通过 plt.colormaps() 查看所有名称。
# 获得全部可用的颜色映射表
plt.colormaps()
内置的色彩映射,按功能可分为以下四大类:
  • 连续型(Sequential)

用于表示从低到高有序的数据(如温度、海拔、密度)。颜色从亮到暗或从浅到深变化。例如 viridisplasmainfernomagmacividis

  • 发散型(Diverging)

用于表示具有一个明显中间值(如零)或临界值的数据,数据向两端发散(如温度异常、盈利与亏损)。中间通常是亮色,两端是两种对比鲜明的深色。例如 RdBuPiYGcoolwarmbwr

  • 循环型(Cyclic)

用于表示循环或周期性的数据(如角度、风向、相位)。起点和终点的颜色相同。例如 twilighthsv

  • 定性型(Qualitative)

用于表示分类或无序的数据。颜色之间变化明显,但没有亮度或色度的顺序。例如 tab10Set1Pastel1

绘图时需要根据多种因素选择合适的colormap,从而确保数据的分布和变化能够被清晰地感知。

因素

建议

数据性质

连续有序 → Sequential;带零点的偏差 → Diverging

直觉认知

水深用蓝、高温用红,符合读者预期

领域惯例

气象雷达常用 nipy_spectral,医学影像常用 gray

感知均匀

人眼对亮度变化最敏感,优先选亮度单调递增的 colormap(如 viridis)

内置色彩映射的更多内容可以查看官方文档:
https://matplotlib.org/stable/users/explain/colors/colormaps.html

  • 获取 Colormap 对象:
有以下两种方式获取一个colormap对象,它们都是LinearSegmentedColormapListedColormap对象
# 方法 1: 使用 plt.get_cmap(),推荐
plt.get_cmap('hsv')

# 方法 2: 使用 matplotlib.cm 模块
plt.cm.hsv
上述数值范围为0.0~1.0,相当于该色彩映射的最低值和最高值之间。因此将 colormap 视为一个函数,输入一个 0 到 1 之间的值,将会返回一个表示颜色信息的 RGBA 元组。这对于为自定义条形图或线条指定颜色非常有用。
x = np.linspace(0 , 3*np.pi , 500)
N = 20
# 循环绘制N条正弦曲线
for i in range(N):
    # 通过 c=plt.cm.hsv(i/N) 设置曲线颜色,使用HSV颜色映射,    
    # 随着i从0到N-1变化,i/N从0到1变化,实现颜色平滑过渡
    plt.plot(x , i*np.sin(x) , c=plt.cm.hsv(i/N)) 
    print(plt.cm.hsv(i/N))
plt.show()

# 输出:
# (1.0, 0.0, 0.0, 1.0)
# (1.0, 0.2779414544120426, 0.0, 1.0)
# ......
# (1.0, 0.0, 0.6727946966917553, 1.0)
# (1.0, 0.0, 0.37169145441204254, 1.0)
可视化结果如下图所示:
  • 反转 Colormap:

在任何 colormap 名称后加上 _r 即可获得其反转色彩版本,比如 “viridis_r” 会让原本的低值颜色对应高值。

x = np.linspace(0 , 3*np.pi , 500)
y1 = x
y2 = -x

plt.scatter(x , y1 , c=x , cmap='magma' , lw=10) 
plt.scatter(x , y2 , c=x , cmap='magma_r' , lw=10) # 反转 Colormap
plt.show()
可视化结果如下图所示:


03

裁剪Colormap范围


在 Matplotlib 中,我们可以使用多种方法来裁剪 Colormap 的范围,以便更好地可视化数据,只显示特定范围内的数据,其余颜色会被裁剪到边界值。这在可视化时非常有用,可以突出显示我们关心的数据范围。

  • 使用vminvmax参数:直接设置颜色映射的最小值和最大值,超出范围的数据会被裁剪或压缩到边界颜色。该方法是最直接的方法,在调用绘图函数时直接指定颜色范围。
  • 使用clim函数:与 vmin/vmax 功能相同,是 Axes 对象的方法,用于设置 colorbar 的显示范围。该方法适用于已经创建的图像对象,可以动态调整颜色范围。
  • 使用 plt.Normalize(vmin, vmax):创建一个归一化对象,用于将数据映射到 [0, 1] 区间,从而控制颜色映射的范围。该方法提供最大的灵活性,可以创建自定义的标准化对象。另外,plt.Normalizematplotlib.colors.Normalize 二者功能没有差异,只是调用方式不同。


import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import Normalize

# 创建示例数据
np.random.seed(42)
data = np.random.randn(10, 10) * 2 + 5  # 均值为5,标准差为2的正态分布数据

# 创建图形和子图
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
fig.suptitle('Colormap范围裁剪方法比较', fontsize=16)

# 1. 原始数据 - 无范围限制
im1 = axes[0, 0].imshow(data, cmap='viridis')
axes[0, 0].set_title('原始数据 (无范围限制)')
plt.colorbar(im1, ax=axes[0, 0])

# 2. 使用vmin/vmax参数
im2 = axes[0, 1].imshow(data, cmap='viridis', vmin=3, vmax=7)
axes[0, 1].set_title('使用vmin/vmax (3-7)')
plt.colorbar(im2, ax=axes[0, 1])

# 3. 使用clim()函数
im3 = axes[1, 0].imshow(data, cmap='viridis')
im3.set_clim(3, 7)  # 设置颜色范围
axes[1, 0].set_title('使用clim() (3-7)')
plt.colorbar(im3, ax=axes[1, 0])

# 4. 使用plt.Normalize
norm = Normalize(vmin=3, vmax=7)  # 创建标准化对象
im4 = axes[1, 1].imshow(data, cmap='viridis', norm=norm)
axes[1, 1].set_title('使用Normalize (3-7)')
plt.colorbar(im4, ax=axes[1, 1])

plt.tight_layout()
plt.show()
可视化结果如下图所示:


04

创建自定义Colormap


当预定义Colormap不能满足需求时,可以创建自定义Colormap
  • 使用LinearSegmentedColormap:

LinearSegmentedColormap 允许通过定义颜色在特定位置的值来创建自定义渐变。

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

# 1. 构造颜色字典
cdict = {
    'red':   [(0.0,  0.1, 0.1),   # 起点
              (0.35, 0.3, 0.3),   # 控制点 1
              (0.65, 0.9, 0.9),   # 控制点 2
              (1.0,  0.9, 0.9)],  # 终点

    'green': [(0.0,  0.2, 0.2),
              (0.35, 0.7, 0.7),
              (0.65, 0.7, 0.7),
              (1.0,  0.1, 0.1)],

    'blue':  [(0.0,  0.9, 0.9),
              (0.35, 0.9, 0.9),
              (0.65, 0.3, 0.3),
              (1.0,  0.1, 0.1)]
}
# 平滑度
n_bins = 100  
cmap = LinearSegmentedColormap('myBlueRed', cdict, N=n_bins)

# 2. 可视化
x = np.linspace(0, 1, 512).reshape(1, -1)
fig, ax = plt.subplots(figsize=(6, 1))
ax.imshow(x, aspect='auto', cmap=cmap)
ax.set_axis_off()
plt.show()

可视化结果如下图所示:


  • 使用ListedColormap

ListedColormap 适用于创建由特定颜色列表组成的离散 Colormap

# ---------- 自定义纯色离散 ----------
colors = ['#1f77b4''#ff7f0e''#2ca02c''#d62728''#9467bd''#8c564b''#e377c2']
cmap1 = ListedColormap(colors)

# ---------- 把连续 colormap 截断成离散 ----------
base = plt.cm.get_cmap('viridis', 256)
discrete = base(np.linspace(0, 1, 7))   # 只取 7 个节点
cmap2 = ListedColormap(discrete)

# ---------- 可视化 ----------
fig, ax = plt.subplots(1, 2, figsize=(8, 1.2))

# 可视化 cmap1
gradient1 = np.linspace(0, 1, 256).reshape(1, -1)
ax[0].imshow(gradient1, aspect='auto', cmap=cmap1)
ax[0].set_title('cmap1 (纯色离散)')
ax[0].set_axis_off()

# 可视化 cmap2
gradient2 = np.linspace(0, 1, 256).reshape(1, -1)
ax[1].imshow(gradient2, aspect='auto', cmap=cmap2)
ax[1].set_title('cmap2 (viridis 离散)')
ax[1].set_axis_off()

plt.tight_layout()
plt.show()

可视化结果如下图所示:


  • 两者嵌套使用:
LinearSegmentedColormapListedColormap互相嵌套、拼接,实现任意复杂效果
from matplotlib.colors import LinearSegmentedColormap, ListedColormap

# ---------- 第一段:LinearSegmentedColormap ----------
cdict_cold2green = {
    'red':   [(0.0, 0.0, 0.0),
              (1.0, 0.0, 0.0)],
    'green': [(0.0, 0.1, 0.1),
              (1.0, 0.8, 0.8)],
    'blue':  [(0.0, 0.8, 0.8),
              (1.0, 0.1, 0.1)]
}
cmap1 = LinearSegmentedColormap('cold2green', cdict_cold2green)

# ---------- 第二段:离散 ListedColormap ----------
disc_colors = plt.cm.get_cmap('tab10', 7)(np.linspace(0.3, 0.9, 7))
cmap2 = ListedColormap(disc_colors)

# ---------- 第三段:LinearSegmentedColormap----------
cdict_hot = {
    'red':   [(0.0, 0.5, 0.5), (1.0, 1.0, 1.0)],
    'green': [(0.0, 0.3, 0.3), (1.0, 0.2, 0.2)],
    'blue':  [(0.0, 0.0, 0.0), (1.0, 0.1, 0.1)]
}
cmap3 = LinearSegmentedColormap('hot_gamma', cdict_hot)

# ---------- 合并三段 ----------
# 每段各占比例 0.4, 0.3, 0.3
N1, N2, N3 = 256, 192, 192
colors = np.vstack([cmap1(np.linspace(0, 1, N1)),
                    cmap2(np.linspace(0, 1, N2)),
                    cmap3(np.linspace(0, 1, N3))])
cmap_final = ListedColormap(colors, name='triple')

# ---------- 可视化 ----------
gradient = np.linspace(0, 1, 640).reshape(1, -1)
fig, ax = plt.subplots(figsize=(8, 1.2))
ax.imshow(gradient, aspect='auto', cmap=cmap_final)
ax.set_axis_off()
plt.show()
可视化结果如下图所示:

更多内容可以前往官网查看

https://matplotlib.org/stable/


本篇文章来源于微信公众号: 码农设计师

RELATED ARTICLES

欢迎留下您的宝贵建议

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Recent Comments