我正在尝试在散点图中绘制不对称的颜色范围。我希望颜色能够使用diverging color map正确地表示强度。我在更改颜色条来表示这一点时遇到麻烦。
例如,我想在散点图中绘制范围为[-2,10]的xy数据,以便色条仅显示-2到10,中性色为0,而“强度”为- 2和2相同。
我尝试使用ColorMap Normalization和truncating the color map,但似乎我需要将我无法弄清楚的两者结合起来。
MCV示例
x = np.arange( 0, 1, 1e-1 )
xlen = x.shape[ 0 ]
z = np.random.random( xlen**2 )*12 - 2
splt = plt.scatter(
np.repeat( x, xlen ),
np.tile( x, xlen ),
c = z, cmap = 'seismic',
s = 400
)
plt.colorbar( splt )
通过使用MidpointNormalize
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))
x = np.arange( 0, 1, 1e-1 )
xlen = x.shape[ 0 ]
z = np.random.random( xlen**2 )*12 - 2
norm = MidpointNormalize( midpoint = 0 )
splt = plt.scatter(
np.repeat( x, xlen ),
np.tile( x, xlen ),
c = z, cmap = 'seismic', s = 400,
norm = norm
)
plt.colorbar( splt )
我可以使颜色条居中于0,但是强度不公平。即-2处的强度要比+2处的强度暗得多。
截断颜色图时遇到的问题是我不知道截断颜色图的正确位置。
答案 0 :(得分:2)
如果我正确理解,那么当前的问题是,以中点为中心的贴图会将颜色均匀从-2缩放到0(蓝色),类似地(红色)从0缩放到10。
您应该在[self.vmin, self.midpoint, self.vmax] = [-2, 0, 10]
之间重新缩放,而不是缩放[-v_ext, self.midpoint, v_ext] = [-10, 0, 10]
,其中:
v_ext = np.max( [ np.abs(self.vmin), np.abs(self.vmax) ] ) ## = np.max( [ 2, 10 ] )
完整的代码如下:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
x = np.arange( 0, 1, 1e-1 )
xlen = x.shape[ 0 ]
z = np.random.random( xlen**2 )*12 - 2
class MidpointNormalize(mcolors.Normalize):
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
self.midpoint = midpoint
mcolors.Normalize.__init__(self, vmin, vmax, clip)
def __call__(self, value, clip=None):
v_ext = np.max( [ np.abs(self.vmin), np.abs(self.vmax) ] )
x, y = [-v_ext, self.midpoint, v_ext], [0, 0.5, 1]
return np.ma.masked_array(np.interp(value, x, y))
x = np.arange( 0, 1, 1e-1 )
xlen = x.shape[ 0 ]
z = np.random.random( xlen**2 )*12 - 2
norm = MidpointNormalize( midpoint = 0 )
splt = plt.scatter(
np.repeat( x, xlen ),
np.tile( x, xlen ),
c = z, cmap = 'seismic', s = 400,
norm = norm
)
plt.colorbar( splt )
plt.show()
答案 1 :(得分:0)
基于@Asmus的答案,我创建了一个MidpointNormalizeFair
类,该类基于数据进行缩放。
class MidpointNormalizeFair(mpl.colors.Normalize):
""" From: https://matplotlib.org/users/colormapnorms.html"""
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
self.midpoint = midpoint
mpl.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...
result, is_scalar = self.process_value(value)
self.autoscale_None(result)
vlargest = max( abs( self.vmax - self.midpoint ), abs( self.vmin - self.midpoint ) )
x, y = [ self.midpoint - vlargest, self.midpoint, self.midpoint + vlargest], [0, 0.5, 1]
return np.ma.masked_array(np.interp(value, x, y))