Matplotlib Multiple Plots On Same Figure

9 min read

Creating effective data visualizations often requires comparing different datasets or showing multiple aspects of the same data within a single view. Mastering the art of placing matplotlib multiple plots on same figure is a fundamental skill for any data scientist or analyst using Python. This capability transforms isolated charts into cohesive analytical dashboards, allowing viewers to spot correlations, discrepancies, and trends instantly. Whether you are comparing stock performance over time, overlaying a regression line on a scatter plot, or building a complex grid of subplots for a report, understanding the underlying architecture of Matplotlib’s object-oriented interface is essential.

Understanding the Figure and Axes Hierarchy

Before diving into specific plotting commands, it is crucial to grasp the core objects that Matplotlib manipulates. Many beginners confuse the Figure with the Axes, leading to frustration when plots overlap unexpectedly or fail to appear.

The Figure is the top-level container—the entire window or image file. But inside this canvas, you place one or more Axes objects. Plus, an Axes object is what we typically think of as "a plot": it contains the x-axis, y-axis, data lines, markers, labels, and title. Think of it as the canvas. A single Figure can host multiple Axes arranged in a grid, or it can host overlapping Axes for layered visualizations.

When you call plt.And plot() using the pyplot (state-machine) interface, Matplotlib implicitly creates a Figure and an Axes if they don't exist, and draws on the "current" Axes. Even so, for professional, reproducible, and complex layouts, the object-oriented (OO) approach is vastly superior. It gives you explicit handles (fig, ax) to manipulate every element precisely That's the part that actually makes a difference..

Method 1: Layering Plots on a Single Axes (Overlaying)

The simplest interpretation of multiple plots on one figure is drawing several data series on the exact same coordinate system—sharing the same x and y axes. This is ideal for direct comparison, such as plotting actual values versus predicted values, or comparing the temperature trends of two cities.

Using the OO interface, you instantiate the figure and axes once, then call plotting methods on that specific ax object repeatedly.

import matplotlib.pyplot as plt
import numpy as np

# Generate sample data
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)

# Create Figure and Axes explicitly
fig, ax = plt.subplots(figsize=(8, 5))

# Plot first series
ax.plot(x, y1, label='Sine Wave', color='steelblue', linewidth=2)

# Plot second series on the SAME axes
ax.plot(x, y2, label='Cosine Wave', color='coral', linestyle='--', linewidth=2)

# Customize the shared axes
ax.set_title('Trigonometric Functions Comparison', fontsize=14, fontweight='bold')
ax.set_xlabel('Angle (radians)')
ax.set_ylabel('Amplitude')
ax.legend(loc='upper right')
ax.grid(True, alpha=0.3)

plt.show()

In this example, both ax.Practically speaking, plot() calls target the same ax object. They automatically share the x and y limits, ticks, and labels. This approach is memory efficient and visually clean when the data shares a common scale and unit Not complicated — just consistent..

Handling Different Scales: Twin Axes

What happens when you need to plot two variables with vastly different magnitudes or units on the same x-axis? Here's a good example: plotting GDP (trillions) and Unemployment Rate (percentage) over the same years. If you force them onto one y-axis, the smaller series becomes a flat line Which is the point..

Matplotlib solves this with ax.twiny() (for a shared y-axis, separate x-axis). twinx()(for a shared x-axis, separate y-axis) andax.twinx() creates a second Axes object (ax2) that shares the x-axis but has an independent y-axis on the right side.

fig, ax1 = plt.subplots(figsize=(8, 5))

years = np.array([9.6, 8.1, 7.9, 3.4, 3.But 3, 4. arange(2010, 2021)
gdp = np.9, 8.9, 4.Plus, 4, 6. That's why array([15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]) # Trillions
unemployment = np. Still, 2, 5. 7, 8.

color1 = 'tab:blue'
ax1.Even so, set_xlabel('Year')
ax1. Still, set_ylabel('GDP (Trillions $)', color=color1)
ax1. plot(years, gdp, color=color1, marker='o', label='GDP')
ax1.

# Create twin axes sharing x-axis
ax2 = ax1.twinx()
color2 = 'tab:red'
ax2.set_ylabel('Unemployment Rate (%)', color=color2)
ax2.plot(years, unemployment, color=color2, marker='s', linestyle='--', label='Unemployment')
ax2.tick_params(axis='y', labelcolor=color2)

# Combine legends from both axes
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper center')

fig.tight_layout() # Prevents label clipping
plt.show()

This technique is powerful but should be used judiciously. Dual-axis charts can be misleading if the viewer assumes the scales are related. Always use distinct colors and clear labels to differentiate the axes Which is the point..

Method 2: Creating Subplot Grids (Side-by-Side Comparisons)

When variables do not share an axis scale, or when you want to show different perspectives (e., a time series next to its histogram), you need a grid of subplots. Matplotlib offers two primary modern ways to achieve this: plt.subplots() for regular grids and plt.g.subplot_mosaic() for complex, custom layouts That's the part that actually makes a difference..

Regular Grids with plt.subplots()

The plt.Because of that, subplots(nrows, ncols) function returns a Figure and a NumPy array of Axes objects. And that's what lets you iterate through the axes or index them directly.

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8))
# axes is a 2x2 array: axes[0,0], axes[0,1], axes[1,0], axes[1,1]

# Flatten the array for easy iteration
for i, ax in enumerate(axes.flat):
    x = np.random.randn(100)
    ax.hist(x, bins=20, alpha=0.7, color=f'C{i}')
    ax.set_title(f'Distribution {i+1}')
    ax.grid(True, alpha=0.3)

fig.suptitle('Four Independent Histograms', fontsize=16)
plt.tight_layout()
plt.show()

Pro Tip: Always use fig.tight_layout() or plt.tight_layout() after creating subplots. It automatically adjusts subplot parameters (padding, spacing) so that titles, tick labels, and axis labels do not overlap.

Sharing Axes for Cleaner Grids

When subplots represent the same scale (e.Still, g. , faceting data by category), redundant tick labels clutter the figure. Use the sharex and sharey parameters in subplots() to link axes It's one of those things that adds up..

# sharex='col' shares

sharex='col' shares the x-axis across columns, while sharey='row' shares the y-axis across rows. This automatically removes duplicate tick labels, resulting in cleaner, more professional plots.

```python
categories = ['A', 'B', 'C']
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(12, 4), sharey=True)

for i, cat in enumerate(categories):
    data = np.random.Because of that, randn(50) + i
    axes[i]. hist(data, bins=15, alpha=0.7, color=f'C{i}')
    axes[i].set_title(f'Category {cat}')
    axes[i].

axes[0].set_ylabel('Frequency')  # Only set once since y-axis is shared
fig.suptitle('Faceted Distribution by Category', fontsize=14)
plt.tight_layout()
plt.

### Custom Layouts with `plt.subplot_mosaic()`

For more complex arrangements, `plt.subplot_mosaic()` lets you define a layout using a simple string-based grid. Each unique character represents a subplot, and you can span multiple cells by repeating characters.

```python
mosaic = """
AA
BC
"""
fig, ax_dict = plt.subplots(
    subplot_mosaic=mosaic,
    figsize=(10, 6)
)

# Access axes by their keys
ax_dict['A'].plot(years, gdp, marker='o')
ax_dict['A'].set_title('GDP Over Time')
ax_dict['B'].bar(['Q1', 'Q2', 'Q3', 'Q4'], [10, 15, 12, 18])
ax_dict['B'].set_title('Quarterly Sales')
ax_dict['C'].scatter(np.random.rand(30), np.random.rand(30))
ax_dict['C'].set_title('Random Scatter')

fig.suptitle('Custom Mosaic Layout', fontsize=16)
plt.tight_layout()
plt.show()

This approach is especially useful for dashboards or comparative reports where different chart types need to coexist in a single figure.

Conclusion

Matplotlib's flexibility in handling multiple axes and subplots empowers you to create publication-quality visualizations made for your data's story. Whether overlaying related metrics with dual axes, arranging independent views in a grid, or crafting custom layouts with mosaic patterns, the key principles remain consistent:

This changes depending on context. Keep that in mind Easy to understand, harder to ignore..

  1. Choose the right method for your data relationship—dual axes for correlated metrics, subplots for independent comparisons.
  2. Prioritize clarity through color coding, labeling, and layout spacing.
  3. apply modern APIs like plt.subplots() and plt.subplot_mosaic() for cleaner, more maintainable code.
  4. Always refine your figures with tight_layout() and descriptive titles to ensure they communicate effectively.

By mastering these techniques, you transform raw data into compelling visual narratives that drive insight and understanding.

Beyond the Basics: Performance and Interactivity

As your visualizations grow in complexity—handling larger datasets or requiring real-time updates—performance considerations become essential. g.Still, matplotlib’s object-oriented API is not just about syntax; it enables efficient rendering cycles. Day to day, when animating or updating plots in a loop (e. , monitoring live sensor data), avoid clearing and redrawing the entire figure.

No fluff here — just what actually works.

# Efficient animation pattern
line, = ax.plot(initial_x, initial_y)

def update(frame):
    new_y = compute_new_data(frame)
    line.set_ydata(new_y)  # Modify artist data in-place
    return line,

ani = FuncAnimation(fig, update, frames=100, blit=True)

The blit=True argument instructs Matplotlib to only re-draw the parts of the figure that have changed (the "dirty" artists), dramatically increasing frame rates compared to a full plt.cla() and re-plot cycle.

For static publications targeting high-resolution output, vector formats (PDF, SVG) preserve infinite scalability for text and lines, while raster formats (PNG) with a high dpi (300+) are better suited for dense scatter plots or heatmaps where vector file sizes become unwieldy. Always set bbox_inches='tight' when saving to eliminate excessive whitespace:

fig.savefig('publication_figure.pdf', format='pdf', bbox_inches='tight', dpi=300)

Integrating with the Broader Ecosystem

Matplotlib serves as the foundational rendering engine for higher-level libraries like Seaborn, Pandas, and Plotly Express. Understanding the underlying Figure and Axes objects allows you to "drop down" to Matplotlib when these wrappers hit their limits. To give you an idea, you might use Seaborn for its statistical semantics and color palettes, then access the returned Axes object to apply custom annotations, inset axes, or the dual-axis techniques covered earlier:

import seaborn as sns

ax = sns.regplot(x='horsepower', y='mpg', data=cars_df)
# Custom Matplotlib refinement on top of Seaborn
ax.axvline(cars_df['horsepower'].mean(), color='red', linestyle='--', label='Mean HP')
ax.

This hybrid workflow—leveraging high-level APIs for speed and low-level Matplotlib for precision—is the hallmark of an efficient visualization practitioner.

## Final Thoughts

Mastering multi-axes layouts is more than memorizing syntax; it is developing an intuition for visual hierarchy and cognitive load. Worth adding: a well-structured figure guides the viewer’s eye from the high-level summary (the suptitle) to the contextual axes labels, and finally into the data marks themselves. Whether you are aligning scales for honest comparison, stacking mosaics for dashboard density, or twinning axes for correlation hunting, the goal remains singular: **reduce the time between the viewer's glance and their insight.

With the tools in this guide—`subplots`, `twinx`, `subplot_mosaic`, and the discipline of the object-oriented interface—you possess the complete toolkit to construct virtually any static analytical figure required in scientific research, business intelligence, or data journalism. The canvas is yours; plot with intention.
Keep Going

Freshly Written

You Might Like

While You're Here

Thank you for reading about Matplotlib Multiple Plots On Same Figure. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home