Matplotlib Custom Colormaps and Normalizations
This article provides a practical guide on configuring custom
colormaps and data normalizations using Python's
matplotlib.colors module. You will learn how to create
discrete and continuous colormaps using ListedColormap and
LinearSegmentedColormap, as well as how to control the
mapping of numerical values to these colors using classes such as
Normalize, LogNorm, TwoSlopeNorm,
and BoundaryNorm.
Creating Custom Colormaps
Matplotlib maps scalar data to colors using colormaps. The
matplotlib.colors module offers two primary classes for
building custom palettes: ListedColormap for discrete steps
and LinearSegmentedColormap for smooth gradients.
1. Discrete Palettes
with ListedColormap
ListedColormap defines a colormap from an explicit list
of color names, hex codes, or RGBA tuples.
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
# Define a discrete list of colors
colors = ["#264653", "#2a9d8f", "#e9c46a", "#f4a261", "#e76f51"]
custom_listed = ListedColormap(colors, name="custom_desert")2.
Continuous Gradients with LinearSegmentedColormap
LinearSegmentedColormap calculates smooth transitions
between specified color stops.
From a List of Colors
The simplest approach is from_list(), which evenly
spaces the colors across the range:
from matplotlib.colors import LinearSegmentedColormap
# Smooth gradient from dark blue to white to dark red
custom_gradient = LinearSegmentedColormap.from_list(
"blue_white_red", ["#00008b", "#ffffff", "#8b0000"]
)From a Channel Dictionary
For exact control over where transitions occur along the \([0, 1]\) interval, specify anchor points for red, green, and blue channels:
cdict = {
"red": [(0.0, 0.0, 0.0),
(0.5, 1.0, 1.0),
(1.0, 1.0, 1.0)],
"green": [(0.0, 0.0, 0.0),
(1.0, 0.0, 0.0)],
"blue": [(0.0, 1.0, 1.0),
(0.5, 1.0, 1.0),
(1.0, 0.0, 0.0)]
}
custom_segmented = LinearSegmentedColormap("custom_diverging", cdict)Configuring Color Normalizations
Normalization is the process of mapping arbitrary data values onto the interval \([0.0, 1.0]\) before passing them to a colormap.
1. Linear Normalization
(Normalize)
Normalize scales data linearly between a specified
minimum (vmin) and maximum (vmax):
from matplotlib.colors import Normalize
norm = Normalize(vmin=0, vmax=100)2. Logarithmic
Normalization (LogNorm)
LogNorm is suitable for data spanning multiple orders of
magnitude. vmin must be strictly positive:
from matplotlib.colors import LogNorm
norm = LogNorm(vmin=1e-2, vmax=1e4)3. Diverging
Data with a Fixed Center (TwoSlopeNorm)
TwoSlopeNorm (formerly DivergingNorm)
scales values on either side of a chosen midpoint (vcenter)
with different linear slopes. This is ideal for data centered around
zero or a baseline average:
from matplotlib.colors import TwoSlopeNorm
# Negative values map from -50 to 0; positive values map from 0 to 200
norm = TwoSlopeNorm(vmin=-50, vcenter=0, vmax=200)4. Binning Values
(BoundaryNorm)
BoundaryNorm groups continuous data into discrete bins,
mapping each bin directly to a color index in a
ListedColormap:
from matplotlib.colors import BoundaryNorm
bounds = [0, 10, 25, 50, 100]
norm = BoundaryNorm(boundaries=bounds, ncolors=custom_listed.N)Applied Example
To apply both a custom colormap and normalization, pass them via the
cmap and norm arguments in plotting functions
such as imshow, scatter, or
pcolormesh:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, TwoSlopeNorm
# Generate sample diverging data
data = np.random.randn(20, 20) * 10
# Configure colormap and normalization
cmap = LinearSegmentedColormap.from_list("cool_warm", ["#1f77b4", "#f7f7f7", "#d62728"])
norm = TwoSlopeNorm(vmin=-20, vcenter=0, vmax=30)
# Plot
fig, ax = plt.subplots()
cax = ax.imshow(data, cmap=cmap, norm=norm)
fig.colorbar(cax, ax=ax)
plt.show()