Skip to content

How to share a colorbar across subplots in Matplotlib (with Code)

The Short Answer (TL;DR)

Give every subplot the same Normalize object and colormap, then pass the subplot axes to fig.colorbar. A shared colorbar is meaningful only when every panel uses the same mapping from numbers to colors.

import numpy as np, matplotlib.pyplot as plt; from matplotlib.colors import Normalize
fig, axes = plt.subplots(1, 2, layout="constrained"); norm = Normalize(vmin=0, vmax=10)
images = [ax.imshow(np.array([[0, 2], [5, 10]]), norm=norm, cmap="viridis") for ax in axes]; fig.colorbar(images[0], ax=axes, label="Value")

Detailed Implementation

This example uses synthetic data and does not need a network connection. Install the recorded package versions in a separate Python environment before running it.

python -m pip install numpy==2.5.4 pandas==3.0.6 matplotlib==3.11.2 seaborn==0.13.2
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize

panels = [np.array([[0, 1], [2, 3]]), np.array([[6, 7], [8, 10]])]
all_values = np.concatenate([panel.ravel() for panel in panels])
norm = Normalize(vmin=all_values.min(), vmax=all_values.max())
fig, axes = plt.subplots(1, 2, figsize=(6.8, 3.2), layout="constrained")
images = []
for index, (ax, panel) in enumerate(zip(axes, panels), start=1):
    image = ax.imshow(panel, norm=norm, cmap="viridis", interpolation="nearest")
    images.append(image)
    ax.set_title(f"Panel {index}")
    ax.set_xticks([0, 1])
    ax.set_yticks([0, 1])
fig.colorbar(images[0], ax=axes, label="Synthetic value", shrink=0.85)
fig.savefig("shared-colorbar.png", dpi=160)
plt.show()

The output contains two image panels and one colorbar. Both panels use limits 0 and 10; the first panel therefore occupies the low end of the shared scale.

Why must normalization be shared?

If each image chooses its own minimum and maximum, the same color can represent a different value in each panel. One colorbar would then describe only one image correctly. Reusing both norm and cmap makes the mapping consistent.

Which axes belong in fig.colorbar?

The ax argument identifies the axes from which the colorbar takes layout space; it can receive the complete axes array. layout="constrained" helps keep the images aligned. Call fig.colorbar once for a shared bar, rather than once inside the loop.

What if the data have outliers or a zero midpoint?

Choose limits using the question and units, and state any clipped range. Diverging data may require a common TwoSlopeNorm with a meaningful center instead of Normalize. LogNorm requires positive values and represents a different numerical mapping.

Mathematical Context

Linear normalization maps a value v to u = (v − vmin) / (vmax − vmin). Here vmin = 0 and vmax = 10, so a value of 5 maps to 0.5 in both panels. The formula assumes distinct limits; constant data need an explicit display range if a useful gradient is required.

\[ u=\frac{v-v_{\min}}{v_{\max}-v_{\min}} \]

Reproducibility

Executed with Python 3.12.14; numpy 2.5.4, pandas 3.0.6, matplotlib 3.11.2, seaborn 0.13.2. Automated checks confirm the stated output properties.

Primary documentation

Related guides