2025, Nov 24 11:00
Align Matplotlib pcolor and line plots: consistent axes, square pixels, and tidy colorbars with layout='compressed'
Struggling with mixed pcolor and line plots in Matplotlib? Use layout='compressed' to keep square pixels, consistent axes, and aligned colorbars across the grid.
When you mix Matplotlib pcolor images with regular line plots in the same grid, getting consistent axes sizes and aspect ratios can be frustrating. Even with constrained_layout turned on, line plots may appear either too wide or too tall, and their heights may end up tied to adjacent colorbars instead of the color plots themselves. The goal is simple: all axes should share the same footprint, pcolor pixels should stay square, and colorbars should align cleanly without breaking the grid.
Reproducing the issue
The following snippet builds a 6×2 grid with mixed content. Pcolor axes use a fixed aspect ratio to maintain square pixels, and line plots are expected to match that aspect, but constrained_layout ends up producing inconsistent widths and heights.
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
# Synthetic data
img_w, img_h = 265, 200
heat_img = np.random.rand(img_h, img_w)
series_vals = np.random.rand(40)
# Grid with constrained_layout
fig, axs = plt.subplots(6, 2, figsize=(8, 11), constrained_layout=True)
[[slot1, slot2], [slot3, slot4], [slot5, slot6], [slot7, slot8], [slot9, slot10], [slot11, slot12]] = axs
for pane in [slot1, slot2, slot3, slot5, slot7, slot9, slot11]:
pic = pane.pcolor(heat_img, vmin=0, vmax=1)
plt.colorbar(pic, ax=pane, label='z', fraction=0.046, pad=0.04)
pane.grid(False)
pane.set_aspect(img_h / img_w)
pane.set_xlabel('x')
pane.set_ylabel('y')
pane.invert_yaxis()
for pane in [slot4, slot6, slot8, slot10, slot12]:
pane.plot(np.arange(len(series_vals)), series_vals, color='blue', linewidth=2)
pane.set_xlabel('index')
pane.set_ylabel('value')
What is actually going on
Pcolor axes enforce a fixed aspect ratio so that image pixels render square. In this mixed grid, constrained_layout tries to reconcile size requirements across axes and their colorbars. The outcome depends heavily on the figure size: some line plots become wider than their corresponding pcolor neighbors, and their heights can align with colorbars rather than with the pcolor images. In practice, the grid looks uneven, and adjusting figsize changes the result without guaranteeing uniformity.
Your pcolor plots have a fixed aspect ratio. Use layout='compressed' to deal with this.
The fix
Switch to the compressed layout mode. It is designed to handle grids containing fixed-aspect-ratio axes, which is exactly the case when mixing pcolor and line plots while preserving square pixels. With layout='compressed', Matplotlib lays out axes and colorbars so they share consistent dimensions and keep the requested aspect ratio intact.
import matplotlib.pyplot as plt
import numpy as np
# Synthetic data
img_w, img_h = 265, 200
heat_img = np.random.rand(img_h, img_w)
series_vals = np.random.rand(40)
# Grid with layout='compressed'
fig, axs = plt.subplots(6, 2, figsize=(8, 11), layout='compressed')
[[cell1, cell2], [cell3, cell4], [cell5, cell6], [cell7, cell8], [cell9, cell10], [cell11, cell12]] = axs
for axis in [cell1, cell2, cell3, cell5, cell7, cell9, cell11]:
im = axis.pcolor(heat_img, vmin=0, vmax=1)
plt.colorbar(im, ax=axis, label='z', fraction=0.046, pad=0.04)
axis.grid(False)
axis.set_aspect(img_h / img_w)
axis.set_xlabel('x')
axis.set_ylabel('y')
axis.invert_yaxis()
for axis in [cell4, cell6, cell8, cell10, cell12]:
axis.plot(np.arange(len(series_vals)), series_vals, color='blue', linewidth=2)
axis.set_xlabel('index')
axis.set_ylabel('value')
plt.show()
Why this matters
When building dashboards, reports, or publication figures, consistency across subplots matters as much as the data itself. Mixed content is common, and pcolor images often define the visual rhythm of the page. Ensuring that everything lines up, colorbars included, helps readability and prevents misleading comparisons caused by uneven axes sizes.
Takeaways
If your grid contains pcolor images with square pixels and you want regular plots to match that footprint, use layout='compressed'. Keep set_aspect based on your image dimensions to preserve the pixel geometry. With this combination, the grid remains neat, the colorbars align to their axes appropriately, and figure size changes no longer lead to erratic axes proportions.