Description
I have been using a different approach to achieve what #12419 tries to address (DivergingNorm
).
The limitation of using something like DivergingNorm
is that it doesn't allow for using color range proportional to the extent of the vmax, vmin w.r.t. vcenter
(please see the example below). I have been using the following hackish approach to get over this limitation. This approach also allows for using colorbar extensions with the ability to specify different colors for data > vmax
and/or data < vmin
[based on my understanding, this won't be possible if DivergingNorm
is used].
Would this be a useful addition to the gallery? Does it look like a functionality that I should think of adding to Matplotlib? (Also, please let me know if there is an easier way of achieving the same result).
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import copy
def div_proportional_colormap(cmap='coolwarm', vmin=-1., vmax=1.,
vcenter=0., cmap_name='my_cmap'):
""" Given a diverging colormap, this returns a diverging
colormap with color ranges on either side proportional to
the extent of vmax, vmin w.r.t. vcenter i.e. vmax-vcenter, vcenter-vmin
"""
if isinstance(cmap, str):
cmap = cm.get_cmap(cmap)
max_delta_v= max(vcenter-vmin, vmax-vcenter)
cmap_min = 0.5-0.5*(vcenter-vmin)/max_delta_v
cmap_max = 0.5+0.5*(vmax-vcenter)/max_delta_v
my_colors = cmap(np.linspace(cmap_min, cmap_max, 512))
my_cmap = mcolors.LinearSegmentedColormap.from_list(cmap_name, my_colors)
return my_cmap
x = np.linspace(-2, 7)
y = np.linspace(-1*np.pi, np.pi)
X, Y = np.meshgrid(x, y)
Z = x * np.sin(Y)**2
fig, (ax1, ax2) = plt.subplots(ncols=2)
my_cmap1 = div_proportional_colormap(cmap=plt.cm.coolwarm,
vmin=-2., vmax=6., vcenter=0.,
cmap_name='my_cmap1')
my_cmap2 = copy.copy(my_cmap1)
my_cmap2.set_over('orange')
img1 = ax1.pcolormesh(Z, cmap=my_cmap1, vmin=-2, vmax=6)
cbar1 = fig.colorbar(img1, ax=ax1)
img2 = ax2.pcolormesh(Z, cmap=my_cmap2, vmin=-2, vmax=6)
cbar2 = fig.colorbar(img2, ax=ax2, extend='max')
plt.show()