Is it possible to define a matplitlib colormap which logarithmically interpolates between two given colors?
Background: When plotting arrays in matplotlib via the imshow(...) command, colormaps are used to assign a color to each data value. Often, predefined colormaps are used from matplotlib.cm but also more enhanced colormaps can be created using matplotlib.colors.LinearSegmentedColormap.
Typically, in these colormaps the color value linearly changes with the data value.
Hint: My question is not, how to plot an array logarithmically. This is usually done, by keeping the linear colormap and some tricks (either by plotting log(array) and replacing the labels x on the colorbar by 10^x, or by explicitly changing the normalization behavior of the plot command). Here, I explicitly need the colormap instance.
You can provide a fake Colormap that applies your desired normalisation, before passing it to the real colormap. Here is such a colormap implementation:
import matplotlib as mpl
class ReNormColormapAdaptor(mpl.colors.Colormap):
""" Colormap adaptor that uses another Normalize instance
for the colormap than applied to the mappable. """
def __init__(self,base,cmap_norm,orig_norm=None):
if orig_norm is None:
if isinstance(base,mpl.cm.ScalarMappable):
orig_norm = base.norm
base = base.cmap
else:
orig_norm = mpl.colors.Normalize(0,1)
self._base = base
if (
isinstance(cmap_norm,type(mpl.colors.Normalize))
and issubclass(cmap_norm,mpl.colors.Normalize)
):
# a class was provided instead of an instance. create an instance
# with the same limits.
cmap_norm = cmap_norm(orig_norm.vmin,orig_norm.vmax)
self._cmap_norm = cmap_norm
self._orig_norm = orig_norm
def __call__(self, X, **kwargs):
""" Re-normalise the values before applying the colormap. """
return self._base(self._cmap_norm(self._orig_norm.inverse(X)),**kwargs)
def __getattr__(self,attr):
""" Any other attribute, we simply dispatch to the underlying cmap. """
return getattr(self._base,attr)
Since the values it gets will already be normalised to [0,1), it needs to know that previous normalisation to undo it (given as orig_norm). Leave it empty if you want to apply the colormap to unnormalised values:
cmap = ReNormColormapAdaptor(mpl.cm.jet,mpl.colors.LogNorm(vmin,vmax))
If you already have a ScalarMappable, then you can pass it in stead of the colormap, from where both the colormap, the previous normalisation and the new normalisation limits will be taken:
import matplotlib.pyplot as plt
scalar_mappable = plt.imshow(C);
scalar_mappable.set_cmap(ReNormColormapAdaptor(
scalar_mappable,
mpl.colors.LogNorm
))
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