合并matplotlib中的色彩映射

时间:2017-08-20 16:17:32

标签: python matplotlib

我想合并两个色图来制作一个imshow情节。我想使用' RdBu'对于范围-0.4到0.4,然后从0.4到最大值(比如1.5)我想使用从相同蓝色到另一种颜色的渐变(例如绿色)。

我该怎么做?

到目前为止,我已经走了多远:

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 个答案:

答案 0 :(得分:2)

目的是创建一个具有多个预定义值的颜色映射。色图的起点应该是vmin,白色(位于“RdBu”色图的中间)应该是0,另一个预定义的点(0.4)应该是上层RdBu色彩图的结尾,然后颜色会逐渐淡出某种颜色。

为此,我们需要两件事。 (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