Matplotlib 简明教程

Matplotlib - Colormap Normalization

术语 normalization 指将实值重新缩放至公共范围(例如介于 0 和 1 之间)。它通常用作数据处理和分析中的预处理技术。

Colormap Normalization in Matplotlib

在此上下文中,归一化是将数据值映射到颜色的过程。Matplotlib 库提供了各种归一化技术,包括:

  1. Logarithmic

  2. Centered

  3. Symmetric logarithmic

  4. Power-law

  5. Discrete bounds

  6. Two-slope

  7. Custom normalization

Linear Normalization

Matplotlib 中的默认行为是根据指定范围内的数值对颜色进行线性映射。此范围通常由 matplotlib.colors.Normalize() 实例参数的最小值 (vmin) 和最大值 (vmax) 定义。

此映射分为两步,首先将输入数据归一化为 [0, 1] 范围,然后映射到颜色图中的索引。

此示例使用 matplotlib.colors 模块中的 Normalize() 类演示了 Matplotlib 的线性归一化过程。

import matplotlib as mpl
from matplotlib.colors import Normalize

# Creates a Normalize object with a specified range
norm = Normalize(vmin=-1, vmax=1)

# Normalizing a value
normalized_value = norm(0)

# Display the normalized value
print('Normalized Value', normalized_value)

执行上述代码,我们将得到以下输出 −

Normalized Value: 0.5

虽然线性归一化是默认的且通常很合适,但仍有非线性映射在某些场景中可以提供更多信息或在视觉上更具吸引力。

Logarithmic Normalization

这是常见的转换,它取数据的对数(以 10 为底)。当跨不同刻度显示更改时,这很有用。colors.LogNorm() 类用于此标准化。

在此示例中,创建两个子图来演示对数和线性标准化转换之间的差异。

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

# Sample Data
X, Y = np.meshgrid(np.linspace(-3, 3, 128), np.linspace(-3, 3, 128))
Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2)

# Create subplots
fig, ax = plt.subplots(1, 2, figsize=(7,4), layout='constrained')

# Logarithmic Normalization
pc = ax[0].imshow(Z**2 * 100, cmap='plasma',
   norm=colors.LogNorm(vmin=0.01, vmax=100))
fig.colorbar(pc, ax=ax[0], extend='both')
ax[0].set_title('Logarithmic Normalization')

# Linear Normalization
pc = ax[1].imshow(Z**2 * 100, cmap='plasma',
   norm=colors.Normalize(vmin=0.01, vmax=100))
fig.colorbar(pc, ax=ax[1], extend='both')
ax[1].set_title('Linear Normalization')
plt.show()

执行上述代码,我们将得到以下输出 −

colormap normalization ex1

Centered Normalization

当数据围绕一个中心对称(例如,围绕 0 的正负异常),可以使用 colors.CenteredNorm() 类。它会自动将中心映射到 0.5,并根据其值将与中心偏差最大的点映射到 1.0 或 0.0。

此示例比较了对数据集使用 coolwarm 颜色图的默认线性标准化和居中标准化 ( CenteredNorm() ) 的效果。

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

X, Y = np.meshgrid(np.linspace(-3, 3, 128), np.linspace(-3, 3, 128))
Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2)

# select a divergent colormap
cmap = cm.coolwarm

# Create subplots
fig, ax = plt.subplots(1, 2, figsize=(7,4), layout='constrained')

# Default Linear Normalization
pc = ax[0].pcolormesh(Z, cmap=cmap)
fig.colorbar(pc, ax=ax[0])
ax[0].set_title('Normalize')

# Centered Normalization
pc = ax[1].pcolormesh(Z, norm=colors.CenteredNorm(), cmap=cmap)
fig.colorbar(pc, ax=ax[1])
ax[1].set_title('CenteredNorm()')

plt.show()

执行上述代码,我们将得到以下输出 −

colormap normalization ex2

Symmetric Logarithmic Normalization

如果数据可能包含正值和负值,并且两者都希望进行对数缩放。Matplotlib 中的 colors.SymLogNorm() 类专为这种情况而设计。这种标准化将负数按对数映射到较小的值,并将正数映射到较大的值。

这里有一个示例,使用 colors.SymLogNorm() 类转换数据。

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

X, Y = np.mgrid[-3:3:complex(0, 128), -2:2:complex(0, 128)]
Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2)

# Create subplots
fig, ax = plt.subplots(1, 2, figsize=(7, 4), layout='constrained')

# Symmetric Logarithmic Normalization
pcm = ax[0].pcolormesh(X, Y, Z,
   norm=colors.SymLogNorm(linthresh=0.03, linscale=0.03,vmin=-1.0, vmax=1.0, base=10),
   cmap='plasma', shading='auto')
fig.colorbar(pcm, ax=ax[0])
ax[0].set_title('SymLogNorm()')

# Default Linear Normalization
pcm = ax[1].pcolormesh(X, Y, Z, cmap='plasma', vmin=-np.max(Z), shading='auto')
fig.colorbar(pcm, ax=ax[1])
ax[1].set_title('Normalize')

plt.show()

执行上述代码,我们将得到以下输出 −

colormap normalization ex3

Power-law Normalization

此标准化可用于使用 colors.PowerNorm() 类将颜色重新映射到幂律关系上。

这里有一个示例,它比较了幂律 ( colors.PowerNorm() ) 和线性标准化。

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

X, Y = np.meshgrid(np.linspace(-3, 3, 128), np.linspace(-3, 3, 128))
Z = (1 + np.sin(Y * 10.)) * X**2

# Create subplots
fig, ax = plt.subplots(1, 2, figsize=(7, 4), layout='constrained')

# Power-law Normalization
pcm = ax[0].pcolormesh(X, Y, Z, norm=colors.PowerNorm(gamma=0.5),
   cmap='PuBu_r', shading='auto')
fig.colorbar(pcm, ax=ax[0])
ax[0].set_title('PowerNorm()')

# Default Linear Normalization
pcm = ax[1].pcolormesh(X, Y, Z, cmap='PuBu_r', shading='auto')
fig.colorbar(pcm, ax=ax[1])
ax[1].set_title('Normalize')

plt.show()

执行上述代码,我们将得到以下输出 −

colormap normalization ex4

Discrete Bounds Normalization

Matplotlib 提供的另一种标准化是 colors.BoundaryNorm 。当需要使用线性分布颜色将数据映射到指定边界时,它特别有用。

此示例演示了使用 BoundaryNorm() 类进行离散边界标准化,以便在显示 colormesh 图时创建不同的视觉效果。

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

X, Y = np.meshgrid(np.linspace(-3, 3, 128), np.linspace(-3, 3, 128))
Z = (1 + np.sin(Y * 10.)) * X**2

fig, ax = plt.subplots(2, 2, figsize=(7, 6), layout='constrained')
ax = ax.flatten()

# Default norm:
pcm = ax[0].pcolormesh(X, Y, Z, cmap='RdBu_r')
fig.colorbar(pcm, ax=ax[0], orientation='vertical')
ax[0].set_title('Default norm')

# Even bounds give a contour-like effect:
bounds = np.linspace(-1.5, 1.5, 7)
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
pcm = ax[1].pcolormesh(X, Y, Z, norm=norm, cmap='RdBu_r')
fig.colorbar(pcm, ax=ax[1], extend='both', orientation='vertical')
ax[1].set_title('BoundaryNorm: 7 boundaries')

# Bounds may be unevenly spaced:
bounds = np.array([-0.2, -0.1, 0, 0.5, 1])
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
pcm = ax[2].pcolormesh(X, Y, Z, norm=norm, cmap='RdBu_r')
fig.colorbar(pcm, ax=ax[2], extend='both', orientation='vertical')
ax[2].set_title('BoundaryNorm: nonuniform')

# With out-of-bounds colors:
bounds = np.linspace(-1.5, 1.5, 7)
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256, extend='both')
pcm = ax[3].pcolormesh(X, Y, Z, norm=norm, cmap='RdBu_r')
# The colorbar inherits the "extend" argument from BoundaryNorm.
fig.colorbar(pcm, ax=ax[3], orientation='vertical')
ax[3].set_title('BoundaryNorm: extend="both"')

plt.show()

执行上述代码,我们将得到以下输出 −

colormap normalization ex5

当在概念中心点两侧使用不同的颜色图时,使用 TwoSlopeNorm 标准化,它通常用于陆地和海洋具有不同海拔和深度范围的地形图等场景中。

当内置规范不足时, FuncNorm 能够使用任意函数进行自定义规范化。

此外,Matplotlib 支持制作自订标准化,如 MidpointNormalize ,这对定义专业的可视化中的映射很有用。

这些工具在调整颜色表示以适应不同的数据和可视化需求方面提供了灵活性。