有一些关于在色标上定义中点的问题和答案。尤其是this one,它现在也是matplotlib documentation 的一部分。
这个想法是继承matplotlib.colors.Normalize 并让它接受进一步的参数midpoint。然后可以使用这将中点两侧的两个范围线性内插到范围[0,0.5] 和[0.5,1]。
要在对数刻度上找到一个中点,原则上我们可以做同样的事情,只是我们将matplotlib.colors.LogNorm 子类化并取所有值的对数,然后在范围内插入这个对数[0,0.5] 和 [0.5,1]。
在下面的示例中,我们的数据介于 0.001 和 10 之间。使用通常的LogNorm,这会导致颜色图的中间(在 RdBu 颜色图的情况下为白色)位于0.1。如果我们想在1 处有白色,我们将1 指定为MidPointLogNorm 的中点。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
x,y = np.meshgrid(np.linspace(-3,0,19), np.arange(10))
f = lambda x,y : 10**x*(1+y)
z = f(x,y)
fig, (ax,ax2) = plt.subplots(ncols=2, figsize=(12,4.8))
im = ax.pcolormesh(x,y,z, cmap="RdBu_r", norm=LogNorm(vmin=z.min(), vmax=z.max()))
fig.colorbar(im, ax=ax)
ax.set_title("LogNorm")
class MidPointLogNorm(LogNorm):
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
LogNorm.__init__(self,vmin=vmin, vmax=vmax, clip=clip)
self.midpoint=midpoint
def __call__(self, value, clip=None):
# I'm ignoring masked values and all kinds of edge cases to make a
# simple example...
x, y = [np.log(self.vmin), np.log(self.midpoint), np.log(self.vmax)], [0, 0.5, 1]
return np.ma.masked_array(np.interp(np.log(value), x, y))
im2 = ax2.pcolormesh(x,y,z, cmap="RdBu_r",
norm=MidPointLogNorm(vmin=z.min(), vmax=z.max(), midpoint=1))
fig.colorbar(im2, ax=ax2)
ax2.set_title("MidPointLogNorm")
plt.show()
适用于 nan 值的更新解决方案:您需要将 nan 值替换为某个值(数组中值范围之外的最佳值),然后用这些数字屏蔽数组。在
MidPointLogNorm 内部,我们需要处理nan 值,如
this question 所示。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
x,y = np.meshgrid(np.linspace(-3,0,19), np.arange(10))
f = lambda x,y : 10**x*(1+y)
z = f(x,y)
z[1:3,1:3] = np.NaN
#since nan values cannot be used on a log scale, we need to change them to
# something other than nan,
replace = np.nanmax(z)+900
z = np.where(np.isnan(z), replace, z)
# now we can mask the array
z = np.ma.masked_where(z == replace, z)
fig, (ax,ax2) = plt.subplots(ncols=2, figsize=(12,4.8))
im = ax.pcolormesh(x,y,z, cmap="RdBu_r", norm=LogNorm(vmin=z.min(), vmax=z.max()))
fig.colorbar(im, ax=ax)
ax.set_title("LogNorm")
class MidPointLogNorm(LogNorm):
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
LogNorm.__init__(self,vmin=vmin, vmax=vmax, clip=clip)
self.midpoint=midpoint
def __call__(self, value, clip=None):
result, is_scalar = self.process_value(value)
x, y = [np.log(self.vmin), np.log(self.midpoint), np.log(self.vmax)], [0, 0.5, 1]
return np.ma.array(np.interp(np.log(value), x, y), mask=result.mask, copy=False)
im2 = ax2.pcolormesh(x,y,z, cmap="RdBu_r",
norm=MidPointLogNorm(vmin=z.min(), vmax=z.max(), midpoint=1))
fig.colorbar(im2, ax=ax2)
ax2.set_title("MidPointLogNorm")
plt.show()