在 matplotlib 中合并颜色图

fro*_*nts 4 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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

Imp*_*est 6

目的是创建一个颜色映射,它有几个预定义的值。颜色图的开始位置应为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)
Run Code Online (Sandbox Code Playgroud)

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]
Run Code Online (Sandbox Code Playgroud)

完整代码

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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述