幂映射 有时,将颜色重新映射到幂关系上是有用的(例如:y=x^γ,γ是常数指数)。为此,我们使用colors.PowerNorm。它将gamma作为参数(当gamma==1.0只会产生默认的线性映射): 注意:使用这种类型的转换绘制数据图表可能有充分的理由。但技术观察者们习惯于线性和对数图表域(axes)以及基于这两种方法的数据转换。幂映射规范不太常见,观察者们应该明确地知道它们被使用了。
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
import numpy as npimport matplotlib.pyplot as pltimport matplotlib.colors as colors
N = 100X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)]Z1 = (1 + np.sin(Y * 10.)) * X**2
fig, ax = plt.subplots(2, 1, constrained_layout=True)
pcm = ax[0].pcolormesh(X, Y, Z1, norm=colors.PowerNorm(gamma=0.5), cmap='PuBu_r', shading='auto')fig.colorbar(pcm, ax=ax[0], extend='max')ax[0].set_title('PowerNorm()')
pcm = ax[1].pcolormesh(X, Y, Z1, cmap='PuBu_r', shading='auto')fig.colorbar(pcm, ax=ax[1], extend='max')ax[1].set_title('Normalize()')plt.show()
离散边界 Matplotlib自带的另一个规范化是colors.BoundaryNorm。除了vmin和vmax之外,它还将要映射数据的边界作为参数。然后,颜色在这些“边界”之间线性分布。它还可以使用扩展参数将上限值和/或下限值添加到颜色分布的范围中。例如:
·
·
·
·
·
import matplotlib.colors as colorsbounds = np.array([-0.25, -0.125, 0, 0.5, 1])norm = colors.BoundaryNorm(boundaries=bounds, ncolors=4)print(norm([-0.2, -0.15, -0.02, 0.3, 0.8, 0.99]))[0 0 1 2 3 3]
注意:与其他规范化不一样,这个规范化返回的值是0到ncolors-1。
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
import numpy as npimport matplotlib.pyplot as pltimport matplotlib.colors as colors
N = 100X, Y = np.meshgrid(np.linspace(-3, 3, N), np.linspace(-2, 2, N))Z1 = np.exp(-X**2 - Y**2)Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)Z = ((Z1 - Z2) * 2)[:-1, :-1]
fig, ax = plt.subplots(2, 2, figsize=(8, 6), constrained_layout=True)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()
TwoSlopeNorm:中心两侧不同映射 有时,我们希望在观念中心点的两侧有不同的颜色映射,我们希望这两个颜色映射具有不同的线性比例。一个例子是地形图,其中陆地和海洋的中心为零(海平面),但陆地的高度范围通常大于水的深度范围,并且它们通常由不同的颜色映射表示。
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
import numpy as npimport matplotlib.pyplot as pltimport matplotlib.colors as colorsfrom matplotlib import cbook
dem = cbook.get_sample_data('topobathy.npz', np_load=True)topo = dem['topo']longitude = dem['longitude']latitude = dem['latitude']
fig, ax = plt.subplots()# make a colormap that has land and ocean clearly delineated and of the# same length (256 + 256)colors_undersea = plt.cm.terrain(np.linspace(0, 0.17, 256))colors_land = plt.cm.terrain(np.linspace(0.25, 1, 256))all_colors = np.vstack((colors_undersea, colors_land))terrain_map = colors.LinearSegmentedColormap.from_list( 'terrain_map', all_colors)
# make the norm: Note the center is offset so that the land has more# dynamic range:divnorm = colors.TwoSlopeNorm(vmin=-500., vcenter=0, vmax=4000)
pcm = ax.pcolormesh(longitude, latitude, topo, rasterized=True, norm=divnorm, cmap=terrain_map, shading='auto')# Simple geographic plot, set aspect ratio because distance between lines of# longitude depends on latitude.ax.set_aspect(1 / np.cos(np.deg2rad(49)))ax.set_title('TwoSlopeNorm(x)')cb = fig.colorbar(pcm, shrink=0.6)cb.set_ticks([-500, 0, 1000, 2000, 3000, 4000])plt.show()
FuncNorm:任意函数映射 如果以上规范没有提供您想要的规范化,您可以使用FuncNorm来义自己的规范化。请注意,下面的示例与指数为0.5的PowerNorm相同:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
import numpy as npimport matplotlib.pyplot as pltimport matplotlib.colors as colors
def _forward(x): return np.sqrt(x)
def _inverse(x): return x**2
N = 100X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)]Z1 = (1 + np.sin(Y * 10.)) * X**2fig, ax = plt.subplots()
norm = colors.FuncNorm((_forward, _inverse), vmin=0, vmax=20)pcm = ax.pcolormesh(X, Y, Z1, norm=norm, cmap='PuBu_r', shading='auto')ax.set_title('FuncNorm(x)')fig.colorbar(pcm, shrink=0.6)plt.show()
自定义映射:手动实现两个线性范围 上面描述的TwoSlopeNorm为定义自己的规范提供了一个有用的例子。请注意,要使色条工作,必须为规范定义一个反向映射:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
import numpy as npimport matplotlib.pyplot as pltimport matplotlib.colors as colorsfrom matplotlib import cbookdem = cbook.get_sample_data('topobathy.npz', np_load=True)topo = dem['topo']longitude = dem['longitude']latitude = dem['latitude']
class MidpointNormalize(colors.Normalize): def __init__(self, vmin=None, vmax=None, vcenter=None, clip=False): self.vcenter = vcenter super().__init__(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... # Note also that we must extrapolate beyond vmin/vmax x, y = [self.vmin, self.vcenter, self.vmax], [0, 0.5, 1.] return np.ma.masked_array(np.interp(value, x, y, left=-np.inf, right=np.inf))
def inverse(self, value): y, x = [self.vmin, self.vcenter, self.vmax], [0, 0.5, 1] return np.interp(value, x, y, left=-np.inf, right=np.inf)
fig, ax = plt.subplots()midnorm = MidpointNormalize(vmin=-500., vcenter=0, vmax=4000)# make a colormap that has land and ocean clearly delineated and of the# same length (256 + 256)colors_undersea = plt.cm.terrain(np.linspace(0, 0.17, 256))colors_land = plt.cm.terrain(np.linspace(0.25, 1, 256))all_colors = np.vstack((colors_undersea, colors_land))terrain_map = colors.LinearSegmentedColormap.from_list( 'terrain_map', all_colors)pcm = ax.pcolormesh(longitude, latitude, topo, rasterized=True, norm=midnorm, cmap=terrain_map, shading='auto')ax.set_aspect(1 / np.cos(np.deg2rad(49)))ax.set_title('Custom norm')cb = fig.colorbar(pcm, shrink=0.6, extend='both')cb.set_ticks([-500, 0, 1000, 2000, 3000, 4000])
plt.show()
本文链接:
colors.PowerNorm:
https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.PowerNorm.html#matplotlib.colors.PowerNorm
colors.BoundaryNorm:
https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.BoundaryNorm.html#matplotlib.colors.BoundaryNorm
FuncNorm:
https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.FuncNorm.html#matplotlib.colors.FuncNorm
TwoSlopeNorm:
https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.TwoSlopeNorm.html#matplotlib.colors.TwoSlopeNorm