I want to merge two colormaps for an imshow plot. I want to use 'RdBu' for the range -0.4 to 0.4, then from 0.4 to the maximum value (say 1.5) I want to use a gradient from the same blue to another color (say green for example).
How can I do that?
This is how far I got so far:
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()
The purpose is to create a colormapping, which has several predefined values. The start of colormap should be at vmin
, white (which is in the middle of the "RdBu" colormap) should be at 0
, another predefined point (0.4
) shall be the upper end of the RdBu
colormap and then the color shall fade towards some end color.
For this purpose we need two things. (a) a colormap that has all those colors in it and (b) a Normalization that allows to map the intermediate points to the respective colors.
(a) Creating the colormap
Colormaps range between 0 and 1. We may create the colormap such that the colors from the "RdBu" colormap extend over the first half of the desired colormap, such that 0 is red, 0.25 is white and 0.5 is blue. The second half of the colormap then ranges from 0.5 (the same blue) over some intermediate turquoise at 0.75 to green at 1. (The intermediate turquoise is chosen because a direct transition from blue to green would result in some smeared brownish blue in the middle, which is probably undesired.) Those steps are accomplished via the following code
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)
such that cmap
is the desired colormap.
(b) Creating the normalization
Unlike the MidpointNormalization, which has one intermediate point, we now need two intermediate points: one being the white color at 0 value and one being the end of the first half of the colormap. We can hence use two values in the custom normalization (here called low
and up
), such the interpolation ranges over 4 points in total and low
corresponds to the 0.25 value of the colormap and up
corresponds to the 0.5 value.
x, y = [self.vmin, self.low, self.up, self.vmax], [0, 0.25, 0.5, 1]
Complete code:
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With