2017-08-20 221 views
1

我想为一个imshow图合并两个颜色映射。我想使用'RdBu'范围为-0.4到0.4,然后从0.4到最大值(比如说1.5),我想使用从相同的蓝色到另一种颜色(例如绿色)的渐变。在matplotlib中合并颜色映射

我该怎么做?

这是多远我走到这一步:

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.colors as colors 
from matplotlib.mlab import bivariate_normal 

N = 100 
''' 
Custom Norm: An example with a customized normalization. This one 
uses the example above, and normalizes the negative data differently 
from the positive. 
''' 
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)] 
Z1 = (bivariate_normal(X, Y, 1., 1., 1.0, 1.0))**2 \ 
    - 0.4 * (bivariate_normal(X, Y, 1.0, 1.0, -1.0, 0.0))**2 
Z1 = Z1/0.03 

# Example of making your own norm. Also see matplotlib.colors. 
# From Joe Kington: This one gives two different linear ramps: 

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)) 

fig, ax = plt.subplots(1, 1) 

minValue = Z1.min() 
maxValue = 0.4 

pcm = ax.imshow(Z1, 
       norm=MidpointNormalize(midpoint=0.), 
       vmin=minValue, vmax=maxValue, 
       cmap='RdBu', 
       origin='lower', 
       aspect=1.0, 
       interpolation='none') 
cbar = fig.colorbar(pcm, ax=ax, extend='both', ticks=[minValue, 0.0, maxValue]) 

fig.tight_layout() 

plt.show() 

enter image description here

回答

1

的目的是为了创造一个colormapping,其中有几个预定义值。颜色映射的开始位置应为vmin,白色(位于“RdBu”颜色映射的中间)应为0,另一个预定义点(0.4)应为颜色映射的上端,然后颜色应淡入一些最终的颜色。

为此,我们需要两样东西。 的(a)具有在它和(b)所有这些颜色归一化,其允许所述中间点映射到相应的颜色的颜色表。

(a)建立颜色表

色彩映射表的范围在0和1之间,我们可能会创建颜色映射,使得来自“RdBu”的颜色的颜色表在期望的颜色表的前半部分延伸,以使得0是红色,0.25是白色,0.5是蓝色。然后,颜色映射的后半部分从0.5(相同的蓝色)到0.75的某个中间绿松石到1的绿色。(选择中间绿松石是因为从蓝色到绿色的直接过渡会导致中间有一些模糊的棕色蓝色,这是不希望的可能)。这些步骤是通过下面的代码

colors = plt.cm.RdBu(np.linspace(0,1.,128)) 
colors = zip(np.linspace(0,0.5,128),colors) 
colors += [ (0.75,"#1fa187"),(1., "#76d154")] 
cmap = matplotlib.colors.LinearSegmentedColormap.from_list('mycmap', colors) 

使得cmap是所期望的颜色表来完成的。

(b)中创建的正常化

不同于MidpointNormalization,它具有一个中间点,我们现在需要两个中间点:一个是白色,在0值和一个为所述第一半部的端部的色彩地图。我们所用的归一化的自定义(这里称为lowup),因此使用两个值,例如内插范围超过4个总和low对应于颜色表的0.25值和up对应于0.5的值。

x, y = [self.vmin, self.low, self.up, self.vmax], [0, 0.25, 0.5, 1] 

完整代码

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.colors 
from matplotlib.mlab import bivariate_normal 

N = 100 
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)] 
Z1 = (bivariate_normal(X, Y, 1., 1., 1.0, 1.0))**2 \ 
    - 0.4 * (bivariate_normal(X, Y, 1.0, 1.0, -1.0, 0.0))**2 
Z1 = Z1/0.03 


class TwoInnerPointsNormalize(matplotlib.colors.Normalize): 
    def __init__(self, vmin=None, vmax=None, low=None, up=None, clip=False): 
     self.low = low 
     self.up = up 
     matplotlib.colors.Normalize.__init__(self, vmin, vmax, clip) 

    def __call__(self, value, clip=None): 
     x, y = [self.vmin, self.low, self.up, self.vmax], [0, 0.25, 0.5, 1] 
     return np.ma.masked_array(np.interp(value, x, y)) 

colors = plt.cm.RdBu(np.linspace(0,1.,128)) 
colors = zip(np.linspace(0,0.5,128),colors) 
colors += [ (0.75,"#1fa187"),(1., "#76d154")] 
cmap = matplotlib.colors.LinearSegmentedColormap.from_list('mycmap', colors) 


fig, ax = plt.subplots(1, 1) 

norm = TwoInnerPointsNormalize(vmin=-0.4, vmax=1.5, low=0., up=0.4) 
pcm = ax.imshow(Z1, norm=norm, cmap=cmap, 
       origin='lower', aspect=1.0, interpolation='none') 
cbar = fig.colorbar(pcm, ax=ax, ticks=[-0.4,0.0, 0.4,1.5]) 

fig.tight_layout() 
plt.show() 

enter image description here

+0

这解决了我的问题。我喜欢这个解决方案,因为它很容易通用,可以合并任何颜色映射,也可以在颜色映射中添加任意数量的段。谢谢! – fromGiants