如何在不均匀的色带上将 0 设置为白色?
How to set 0 to white at a uneven color ramp?
我的色带不均匀,我希望 0 为白色。所有的负色都必须是蓝色的,所有的正色都必须是红色的。
我目前的尝试显示 0 蓝色和 0.7 白色。
有办法把0设置成白色吗?
import numpy as np
import matplotlib.colors as colors
from matplotlib import pyplot as m
bounds_min = np.arange(-2, 0, 0.1)
bounds_max = np.arange(0, 4.1, 0.1)
bounds = np.concatenate((bounds_min, bounds_max), axis=None)
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256) # I found this on the internet and thought this would solve my problem. But it doesn't...
m.pcolormesh(xx, yy, interpolated_grid_values, norm=norm, cmap='RdBu_r')
为了获得所需的范数,将负片的颜色数设置为与正片相同。
或者,您可以使用未修改的范数,并创建一个特殊的颜色图。这样的颜色图将具有 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: 有一个来创建一个类似的颜色图。但是尝试一下,很明显 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')
另一个答案使它比需要的复杂一点。为了使颜色图的中间点为 0,请使用 DivergingNorm
和 vcenter=0
。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import DivergingNorm
x, y = np.meshgrid(np.linspace(0,50,51), np.linspace(0,50,51))
z = np.linspace(-2,4,50*50).reshape(50,50)
norm = DivergingNorm(vmin=z.min(), vcenter=0, vmax=z.max())
pc = plt.pcolormesh(x,y,z, norm=norm, cmap="RdBu_r")
plt.colorbar(pc)
plt.show()
注意:从matplotlib 3.2开始DivergingNorm
将重命名为TwoSlopeNorm
我的色带不均匀,我希望 0 为白色。所有的负色都必须是蓝色的,所有的正色都必须是红色的。 我目前的尝试显示 0 蓝色和 0.7 白色。
有办法把0设置成白色吗?
import numpy as np
import matplotlib.colors as colors
from matplotlib import pyplot as m
bounds_min = np.arange(-2, 0, 0.1)
bounds_max = np.arange(0, 4.1, 0.1)
bounds = np.concatenate((bounds_min, bounds_max), axis=None)
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256) # I found this on the internet and thought this would solve my problem. But it doesn't...
m.pcolormesh(xx, yy, interpolated_grid_values, norm=norm, cmap='RdBu_r')
为了获得所需的范数,将负片的颜色数设置为与正片相同。
或者,您可以使用未修改的范数,并创建一个特殊的颜色图。这样的颜色图将具有 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: 有一个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')
另一个答案使它比需要的复杂一点。为了使颜色图的中间点为 0,请使用 DivergingNorm
和 vcenter=0
。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import DivergingNorm
x, y = np.meshgrid(np.linspace(0,50,51), np.linspace(0,50,51))
z = np.linspace(-2,4,50*50).reshape(50,50)
norm = DivergingNorm(vmin=z.min(), vcenter=0, vmax=z.max())
pc = plt.pcolormesh(x,y,z, norm=norm, cmap="RdBu_r")
plt.colorbar(pc)
plt.show()
注意:从matplotlib 3.2开始DivergingNorm
将重命名为TwoSlopeNorm