为了获得所需的标准,在负片上设置与正片相同数量的颜色。
或者,您可以使用未修改的规范,并创建一个特殊的颜色图。这样的颜色图将具有 1/3rd 的蓝色到白色和 2/3rd 白色到红色的颜色。一个好处是颜色条看起来更好。这种方法只有在负数和正数之间的平衡不太极端的情况下才有效。
这是带有生成数据的演示代码。 zz 被选为围绕中心旋转的正弦曲线,并缩放为从 -2 到 4,因此围绕 1 对称。左侧的图像显示了修改后的颜色图。在右侧,范数更改为强制白色为零。
由于所有正值都是红色的,因此红色带比蓝色更宽。在没有改变规范或颜色图的图像中,条带将具有相等的宽度。颜色条表示零为白色。
import numpy as np
import matplotlib.colors as colors
from matplotlib import pyplot as plt
x = np.linspace(-20, 20, 500)
y = np.linspace(-20, 20, 500)
xx, yy = np.meshgrid(x, y)
zz = np.sin(np.sqrt(xx * xx + yy * yy)) * 3 + 1
negatives = -2.0
positives = 4.0
bounds_min = np.linspace(negatives, 0, 129)
bounds_max = np.linspace(0, positives, 129)[1:]
# the zero is only needed once
# in total there will be 257 bounds, so 256 bins
bounds = np.concatenate((bounds_min, bounds_max), axis=None)
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
num_neg_colors = int(256 / (positives - negatives) * (-negatives))
num_pos_colors = 256 - num_neg_colors
cmap_BuRd = plt.cm.RdBu_r
colors_2neg_4pos = [cmap_BuRd(0.5*c/num_neg_colors) for c in range(num_neg_colors)] +\
[cmap_BuRd(1-0.5*c/num_pos_colors) for c in range(num_pos_colors)][::-1]
cmap_2neg_4pos = colors.LinearSegmentedColormap.from_list('cmap_2neg_4pos', colors_2neg_4pos, N=256)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
mesh1 = ax1.pcolormesh(xx, yy, zz, cmap=cmap_2neg_4pos)
ax1.set_aspect('equal')
ax1.set_title('using a modified cmap')
fig.colorbar(mesh1, ax=ax1)
mesh2 = ax2.pcolormesh(xx, yy, zz, norm=norm, cmap='RdBu_r')
ax2.set_aspect('equal')
ax2.set_title('using a special norm')
ticks = np.append(np.arange(-2.0, 0, 0.25), np.arange(0, 4.001, 0.5))
fig.colorbar(mesh2, ax=ax2, ticks=ticks)
plt.show()
以下代码绘制了范数,看起来像一个阶梯函数。只有 257 个边界,这个阶跃函数在任何地方都有正确的形状(在 -2、0 和 4 处缩放到 x)。
nx = np.linspace(-3,5,10000)
plt.plot(nx, norm(nx))
PS:有一个alternative method 可以创建类似的颜色图。但是尝试一下,很明显RdBu 颜色图经过了微调,可以生成更好看的图。
norm_2neg_4pos = mcolors.Normalize(negatives, positives)
colors_2neg_4pos = [[0, 'blue'],
[norm_2neg_4pos(0.0), "white"],
[1, 'red']]
cmap_2neg_4pos = mcolors.LinearSegmentedColormap.from_list("", colors_2neg_4pos)
还有一个简单的解决方案是在 -4 和 4 之间重新调整所有内容。但是,这会丢失较深的蓝色。 'RdBu_r' 的替代方案是 'seismic',它以不同的方式从红色到白色再到蓝色。
ax.pcolormesh(xx, yy, zz, vmin=-positives, vmax=positives, cmap='RdBu_r')