确保 matplotlib colorbar 在多个图中看起来相同
Ensure matplotlib colorbar looks the same across multiple figure
考虑以下代码
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
def make_Z(X,Y, offset=0.):
return np.sin(X) + np.cos(Y) + offset
class MidpointNormalize(colors.Normalize):
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
self.midpoint = midpoint
colors.Normalize.__init__(self, vmin, vmax, clip)
def __call__(self, value, clip=None):
# I'm ignoring masked values and all kinds of edge cases to make a
# simple example...
x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
return np.ma.masked_array(np.interp(value, x, y), np.isnan(value))
################################################################################
x,y = np.linspace(-10, 10, 100), np.linspace(-10, 10, 100)
X, Y = np.meshgrid(x,y)
Z = make_Z(X,Y, offset=0.8)#; print(Z.shape)
tens = np.logspace(0., 3.0, num=4); print(tens)
Zs = [Z/i for i in tens]#; print(len(Zs))
min_Z = np.min(Zs)
max_Z = np.max(Zs)
norm = MidpointNormalize(vmin=min_Z, vmax=max_Z, midpoint=0.)
for Z in Zs:
print("min, max: %f, %f"%(np.min(Z), np.max(Z)))
fig, ax = plt.subplots()
Z_plot = ax.contourf(X,Y,Z, levels=100, norm=norm, cmap='seismic', vmin=min_Z, vmax=max_Z)
plt.colorbar(Z_plot, ax=ax)
plt.show()
print("-"*70)
这会产生以下输出:
说明:我根据X和Y坐标做一个Z值,然后把每个图中的Z值除以十的幂(100, 101, 102, 103), 因此地块越往下越弱。
基本上,一切都符合预期。但是,我希望将相同的颜色条应用于所有图形。目前看起来应用了相同的颜色图(它应该是),但我想要完整的“蓝色底部红色上方” - 所有图形中的颜色条,即使是那些看起来全是白色的颜色条。我有点自信,我尝试了 contourf
和 colorbar
的所有参数,包括 vmin
和 vmax
参数,但无法显示完整范围的颜色条在所有数字上。有什么提示吗?
编辑:
我想也许可以调整颜色条的 ylim
属性,因为它毕竟只是一个常规轴。然而,将颜色条定义为 cbar
然后执行 cbar.ax.set_ylim(min_Z, max_Z)
会导致乱码。
选项 1
我不知道这是否适合你,但你可以将 contourf
替换为 imshow
:
Z_plot = ax.imshow(Z, norm=norm, cmap='seismic', vmin=min_Z, vmax=max_Z, interpolation = 'bilinear')
选项 2
matplotlib.pyplot.colorbar
链接到您作为第一个参数传递的可映射对象。一个技巧可以是传递给 colorbar
非缩放 contour
.
试试这个代码是否适合你:
for Z, ten in zip(Zs, tens):
print("min, max: %f, %f"%(np.min(Z), np.max(Z)))
fig, ax = plt.subplots()
plt.colorbar(ax.contourf(X,Y,Z*ten, levels=100, norm=norm, cmap='seismic', vmin=min_Z, vmax=max_Z), ax=ax)
Z_plot = ax.contourf(X, Y, Z, levels = 100, norm = norm, cmap = 'seismic', vmin = min_Z, vmax = max_Z)
plt.show()
print("-"*70)
选项 3
与上面相同的概念,但这次我将可映射对象设置为以更简洁的方式传递给 colorbar
。
for Z in Zs:
print("min, max: %f, %f"%(np.min(Z), np.max(Z)))
fig, ax = plt.subplots()
Z_plot = ax.contourf(X, Y, Z, levels = 100, norm = norm, cmap = 'seismic', vmin = min_Z, vmax = max_Z)
m = cm.ScalarMappable(cmap = cm.seismic, norm = colors.TwoSlopeNorm(vmin = np.min(Z), vcenter = 0, vmax = np.max(Z)))
m.set_array(Z)
m.set_clim(np.min(Z), np.max(Z))
cbar = plt.colorbar(m, boundaries = np.linspace(np.min(Z), np.max(Z), 100))
ticks = np.append(0, np.linspace(np.min(Z), np.max(Z), 9))
ticks.sort()
cbar.set_ticks(ticks)
plt.show()
print("-"*70)
这个答案完全归功于 Zephyr 上面的答案,我接受了第三个代码块,我在下面对其进行了改编,以便在我提供的 MWE 和我的实际代码中使用:
x,y = np.linspace(-10, 10, 100), np.linspace(-10, 10, 100)
X, Y = np.meshgrid(x,y)
Z = make_Z(X,Y, offset=0.8)#; print(Z.shape)
tens = np.logspace(0., 3.0, num=4); print(tens)
Zs = [Z/i for i in tens]#; print(len(Zs))
min_Z = np.min(Zs)
max_Z = np.max(Zs)
for Z in Zs:
print("min, max: %f, %f"%(np.min(Z), np.max(Z)))
fig, ax = plt.subplots()
Z_plot = ax.contourf(X,Y,Z, levels=100, norm=norm, cmap='seismic', vmin=min_Z, vmax=max_Z)
m = cm.ScalarMappable(cmap = 'seismic', norm = norm)
cbar = plt.colorbar(m, boundaries = np.linspace(min_Z, max_Z, 100))
plt.show()
print("-"*70)
与 Zephyr 答案的差异:
- 我从他的回答中唯一接手的部分是包含
ScalarMappable
的那一行,我在其中将范数设置为与 contourf
[=23= 中使用的范数相同]
- 关于刻度线的所有内容我都删除了,因为对我来说自动刻度线就足够了。
set_array
和 set_clim
功能我已经删除了,因为它们对我没有任何改变,坦率地说,我不知道它们有什么用。
考虑以下代码
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
def make_Z(X,Y, offset=0.):
return np.sin(X) + np.cos(Y) + offset
class MidpointNormalize(colors.Normalize):
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
self.midpoint = midpoint
colors.Normalize.__init__(self, vmin, vmax, clip)
def __call__(self, value, clip=None):
# I'm ignoring masked values and all kinds of edge cases to make a
# simple example...
x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
return np.ma.masked_array(np.interp(value, x, y), np.isnan(value))
################################################################################
x,y = np.linspace(-10, 10, 100), np.linspace(-10, 10, 100)
X, Y = np.meshgrid(x,y)
Z = make_Z(X,Y, offset=0.8)#; print(Z.shape)
tens = np.logspace(0., 3.0, num=4); print(tens)
Zs = [Z/i for i in tens]#; print(len(Zs))
min_Z = np.min(Zs)
max_Z = np.max(Zs)
norm = MidpointNormalize(vmin=min_Z, vmax=max_Z, midpoint=0.)
for Z in Zs:
print("min, max: %f, %f"%(np.min(Z), np.max(Z)))
fig, ax = plt.subplots()
Z_plot = ax.contourf(X,Y,Z, levels=100, norm=norm, cmap='seismic', vmin=min_Z, vmax=max_Z)
plt.colorbar(Z_plot, ax=ax)
plt.show()
print("-"*70)
这会产生以下输出:
说明:我根据X和Y坐标做一个Z值,然后把每个图中的Z值除以十的幂(100, 101, 102, 103), 因此地块越往下越弱。
基本上,一切都符合预期。但是,我希望将相同的颜色条应用于所有图形。目前看起来应用了相同的颜色图(它应该是),但我想要完整的“蓝色底部红色上方” - 所有图形中的颜色条,即使是那些看起来全是白色的颜色条。我有点自信,我尝试了 contourf
和 colorbar
的所有参数,包括 vmin
和 vmax
参数,但无法显示完整范围的颜色条在所有数字上。有什么提示吗?
编辑:
我想也许可以调整颜色条的 ylim
属性,因为它毕竟只是一个常规轴。然而,将颜色条定义为 cbar
然后执行 cbar.ax.set_ylim(min_Z, max_Z)
会导致乱码。
选项 1
我不知道这是否适合你,但你可以将 contourf
替换为 imshow
:
Z_plot = ax.imshow(Z, norm=norm, cmap='seismic', vmin=min_Z, vmax=max_Z, interpolation = 'bilinear')
选项 2
matplotlib.pyplot.colorbar
链接到您作为第一个参数传递的可映射对象。一个技巧可以是传递给 colorbar
非缩放 contour
.
试试这个代码是否适合你:
for Z, ten in zip(Zs, tens):
print("min, max: %f, %f"%(np.min(Z), np.max(Z)))
fig, ax = plt.subplots()
plt.colorbar(ax.contourf(X,Y,Z*ten, levels=100, norm=norm, cmap='seismic', vmin=min_Z, vmax=max_Z), ax=ax)
Z_plot = ax.contourf(X, Y, Z, levels = 100, norm = norm, cmap = 'seismic', vmin = min_Z, vmax = max_Z)
plt.show()
print("-"*70)
选项 3
与上面相同的概念,但这次我将可映射对象设置为以更简洁的方式传递给 colorbar
。
for Z in Zs:
print("min, max: %f, %f"%(np.min(Z), np.max(Z)))
fig, ax = plt.subplots()
Z_plot = ax.contourf(X, Y, Z, levels = 100, norm = norm, cmap = 'seismic', vmin = min_Z, vmax = max_Z)
m = cm.ScalarMappable(cmap = cm.seismic, norm = colors.TwoSlopeNorm(vmin = np.min(Z), vcenter = 0, vmax = np.max(Z)))
m.set_array(Z)
m.set_clim(np.min(Z), np.max(Z))
cbar = plt.colorbar(m, boundaries = np.linspace(np.min(Z), np.max(Z), 100))
ticks = np.append(0, np.linspace(np.min(Z), np.max(Z), 9))
ticks.sort()
cbar.set_ticks(ticks)
plt.show()
print("-"*70)
这个答案完全归功于 Zephyr 上面的答案,我接受了第三个代码块,我在下面对其进行了改编,以便在我提供的 MWE 和我的实际代码中使用:
x,y = np.linspace(-10, 10, 100), np.linspace(-10, 10, 100)
X, Y = np.meshgrid(x,y)
Z = make_Z(X,Y, offset=0.8)#; print(Z.shape)
tens = np.logspace(0., 3.0, num=4); print(tens)
Zs = [Z/i for i in tens]#; print(len(Zs))
min_Z = np.min(Zs)
max_Z = np.max(Zs)
for Z in Zs:
print("min, max: %f, %f"%(np.min(Z), np.max(Z)))
fig, ax = plt.subplots()
Z_plot = ax.contourf(X,Y,Z, levels=100, norm=norm, cmap='seismic', vmin=min_Z, vmax=max_Z)
m = cm.ScalarMappable(cmap = 'seismic', norm = norm)
cbar = plt.colorbar(m, boundaries = np.linspace(min_Z, max_Z, 100))
plt.show()
print("-"*70)
与 Zephyr 答案的差异:
- 我从他的回答中唯一接手的部分是包含
ScalarMappable
的那一行,我在其中将范数设置为与contourf
[=23= 中使用的范数相同] - 关于刻度线的所有内容我都删除了,因为对我来说自动刻度线就足够了。
set_array
和set_clim
功能我已经删除了,因为它们对我没有任何改变,坦率地说,我不知道它们有什么用。