Subplots and Multi-Panel Figures

Why Multi-Panel Figures Matter

Journal papers typically allow 6-8 figures. Packing multiple related plots into a single figure β€” BER on the left, constellation on the right, spectrum below β€” communicates more per figure. GridSpec and insets give you pixel-level control over panel placement.

Definition:

plt.subplots β€” Quick Regular Grids

plt.subplots(nrows, ncols, **kwargs) creates a Figure with a regular grid of Axes:

fig, axes = plt.subplots(2, 3, figsize=(12, 6),
                          sharex=True, sharey='row')
axes[0, 0].plot(x, y)       # top-left panel
axes[1, 2].scatter(a, b)    # bottom-right panel

sharex / sharey link axes for consistent scales across panels.

When nrows=ncols=1, axes is a single Axes, not an array. Use fig, ax = plt.subplots() in that case.

Definition:

GridSpec β€” Flexible Panel Layouts

matplotlib.gridspec.GridSpec creates layouts where panels span multiple rows or columns:

from matplotlib.gridspec import GridSpec

fig = plt.figure(figsize=(10, 6))
gs = GridSpec(2, 3, figure=fig, hspace=0.3, wspace=0.3)

ax_big   = fig.add_subplot(gs[0, :])      # top row, full width
ax_left  = fig.add_subplot(gs[1, 0:2])    # bottom left 2/3
ax_right = fig.add_subplot(gs[1, 2])       # bottom right 1/3

Definition:

Inset Axes for Zoom and Detail Views

ax.inset_axes([x, y, width, height]) creates a small Axes inside an existing one, useful for zoom panels:

axins = ax.inset_axes([0.55, 0.55, 0.4, 0.4])
axins.plot(x_zoom, y_zoom)
ax.indicate_inset_zoom(axins, edgecolor='red')

Coordinates are in axes-relative units: [0, 0] is bottom-left, [1, 1] is top-right.

Theorem: Constrained Layout vs. Tight Layout

fig.set_layout_engine('constrained') (or layout='constrained') uses a constraint solver to prevent overlapping labels and titles. It handles colorbars, legends, and suptitles better than the older fig.tight_layout().

fig, axes = plt.subplots(2, 2, layout='constrained')

Use constrained for all new code. Fall back to tight_layout() only when constrained layout fails with certain artist combinations.

tight_layout adjusts subplot params heuristically; constrained solves a proper constraint system.

Example: Publication-Quality Multi-Panel with GridSpec

Create a figure with a wide spectrum plot on top and two smaller panels (time domain and constellation) below.

Example: Inset Zoom on a BER Curve

Add a zoom panel showing the BER curve near the waterfall region (10-14 dB) within the main plot.

Subplot Layout Explorer

Experiment with different numbers of rows and columns and see how constrained layout adjusts spacing automatically.

Parameters

Subplot Creation Methods

MethodUse CaseSpanning Panels?Ease
plt.subplots(n, m)Regular gridsNoSimplest
GridSpecIrregular layouts, spanningYesModerate
subplot_mosaicNamed layouts via ASCII artYesModerate
inset_axesZoom panels, mini-plotsN/AEasy
add_axes([l,b,w,h])Exact pixel placementN/AManual

Quick Check

What does sharex=True do in plt.subplots(2, 2, sharex=True)?

All panels share the same x-axis range and tick labels

All panels have the same title

All panels use the same colormap

All panels are forced to square aspect ratio

GridSpec

A Matplotlib class for creating flexible subplot layouts where panels can span multiple rows or columns.

Inset Axes

A small Axes embedded inside a larger one, typically used for zoom views or mini-plots.