Back to Blog
Python

Python Matplotlib Multiple Plots and Subplots

python matplotlib multiple plots and subplots: Learn how to create multiple plots and subplots in Python Matplotlib using plt.subplots(), manage figure layout, share a...

matplotlibdata visualizationsubplotsfigure layoutplotting
Diagram showing a matplotlib figure with multiple subplots arranged in a grid.

python matplotlib multiple plots and subplots requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

When you need to present multiple plots in a single figure, Python's Matplotlib provides the subplots() function as the primary entry point. This article covers how to create multiple plots and subplots, control their layout, share axes, and avoid common mistakes that appear when working with real data.

The subplots() Function as the Core Tool

The plt.subplots() function creates a figure and a grid of axes in one call. It returns a tuple containing a Figure object and either a single Axes object or a NumPy array of Axes objects, depending on the number of rows and columns you request.

import matplotlib.pyplot as plt fig, ax = plt.subplots(2, 2)

This creates a 2×2 grid of four axes. The variable ax is a 2D array of Axes objects. You can access each subplot using standard indexing:

ax[0, 0].plot([1, 2, 3], [4, 5, 6]) ax[0, 0].set_title('Top Left')

When you request a single subplot, ax is a single Axes object, not an array. This asymmetry is a common source of bugs when writing generic code that handles both cases. The next section shows how to handle that consistently.

Creating Multiple Separate Figures

Sometimes you need multiple independent figures rather than subplots within one figure. Use plt.figure() to create a new figure, then add axes with add_subplot() or add_axes().

import matplotlib.pyplot as plt fig1 = plt.figure() ax1 = fig1.add_subplot(1, 1, 1) ax1.plot([1, 2, 3], [1, 4, 9]) fig2 = plt.figure() ax2 = fig2.add_subplot(1, 1, 1) ax2.plot([1, 2, 3], [10,, 20, 30])

Each figure() call creates a new figure that will be shown when you call plt.show(). This approach is useful when you want to save each plot to a separate file or display them in separate windows during interactive exploration. For a single figure with multiple panels, subplots() is usually more concise.

Controlling Subplot Layout and Sizing

The default layout often leaves too much whitespace or clips labels. You can control the figure size with the figsize parameter and adjust spacing with tight_layout() or constrained_layout.

fig, ax = plt.subplots(2, 2, figsize=(10, 8)) fig.tight_layout()

tight_layout() automatically adjusts subplot parameters so that that the axes fit within the figure. It works well for simple grids but can be unpredictable when you use colorbars or shared axis labels. An alternative is to enable constrained_layout when creating the figure:

fig, ax = plt.subplots(2, 2, constrained_layout=True)

nThis uses a constraint solver to position axes and decorations without overlapping. It is generally the recommended approach for complex layouts because it handles colorbars and nested gridspecs more reliably.

For finer control, use gridspec.GridSpec to define the grid and specify row and column spans:

import matplotlib.gridspec as gridspec fig = plt.figure() gs = gridspec.GridSpec(2, 2, width_ratios=[1, 2], height_ratios=[2, 1]) ax1 = fig.add_subplot(gs[0, 0]) ax2 = fig.add_subplot(gs[0, 1]) ax3 = fig.add_subplot(gs[1, :])

Here ax3 spans the entire bottom row. width_ratios and height_ratios let you allocate different sizes to each row or column. This is useful when one subplot needs more space because it contains more data or a colorbar.

Sharing Axes Across Subplots

When subplots share the same x or y range, you can synchronize their axis limits by passing sharex or sharey to subplots(). This avoids duplicated axis labels and makes comparisons easier.

fig, ax = plt.subplots(2, 2, sharex=True, sharey=True)

Now all four subplots share the same x and y limits. If you zoom or pan in one subplot, the others update accordingly. You can also share only one axis:

fig, ax = plt.subplots(2, 1, sharex=True)

When you share axes, the tick labels are automatically hidden on all but the bottom row (for sharex) and the left column (for sharey). You can override this with tick_params(labelbottom=True) if you need labels on every subplot.

Sharing axes is not the same as linking data. Each subplot still has its own data and can be styled independently. The sharing only affects the axis limits and tick behavior.

Working with the Axes Array

When subplots() returns an array, you often need to flatten it to iterate over all axes in a linear fashion. This is especially common when you want to apply the same formatting to every subplot.

fig, ax = plt.subplots(2, 3) for a in ax.flat: a.set_xlabel('Time (s)') a.set_ylabel('Amplitude')

The .flat attribute is a NumPy flat iterator that yields each Axes object in row-major order. If you need to know the subplot's grid position, you can iterate over the array directly with enumerate:

for i, row in enumerate(ax): for j, a in enumerate(row): a.set_title(f'Subplot {i+1}, {j+1}')

When you have a single subplot, ax is not an array. To write code that works for both, you can use np.atleast_1d or check the type. A cleaner pattern is to force a 2D array using np.array(ax).reshape(-1):

import numpy as np fig, ax = plt.subplots(2, 2) axes = np.array(ax).reshape(-1) for a in axes: a.grid(True)

This works for a single subplot as well because np.array(ax) with a single Axes object produces a 0D array, and .reshape(-1) turns it into a 1-element array.

Common Pitfalls and How to Avoid Them

Mixing the pyplot interface with the object-oriented interface is a frequent source of confusion. For example, calling plt.xlabel() after creating subplots affects only the last active axes, which may not be what you intend. Prefer using the Axes methods directly:

ax[0, 0].set_xlabel('X')

Another pitfall is forgetting to call plt.show() when running a script. In interactive environments like Jupyter, plots render automatically, but in a plain Python script you need plt.show() to display the figure. If you save the figure with fig.savefig(), you do not need plt.show().

When you create multiple figures, calling plt.show() at the end will display all of them. If you want to save each figure separately, call fig.savefig() before plt.show() to avoid blank files.

A third issue is using subplots() without unpacking the return value correctly. If you write fig, ax = plt.subplots(2, 2) and then try to call ax.plot(), you get an error because ax is an array. Always check the shape of ax or use a consistent flattening approach.

Performance and Memory Considerations

Creating a large number of subplots can consume significant memory and slow down rendering. Each Axes object holds its own data, ticks, labels, and patches. For a grid with hundreds of subplots, the overhead becomes noticeable.

If you only need to display a grid of similar plots, consider using a single Axes and drawing multiple lines or images instead. For example, a heatmap with imshow() can replace dozens of subplots when the data is a matrix.

When you must use many subplots, reuse the figure and axes where possible. Creating a new figure for each plot in a loop is expensive. Instead, create the grid once and update the data with set_data() or set_ydata().

Also be aware of the default backend. The default Agg backend is fine for saving files, but interactive backends like TkAgg or QtAgg add event handling overhead. If you are generating many figures for a report, use Agg and save directly to files without displaying.

For memory, call plt.close(fig) after saving a figure to release the figure's resources. This is particularly important in long-running scripts that generate hundreds of figures. Without closing, the figures accumulate in memory and can eventually exhaust available RAM.

Finally, use constrained_layout instead of manually adjusting subplots_adjust() when you have many subplots. The constraint solver handles spacing automatically and avoids the trial-and-error of manual margins, which is especially error-prone when the figure size changes between runs.

python matplotlib multiple plots and subplots: Practical Usa | RYUSLOG DEV