matplotlib
python
data visualization
plt.subplots
coding tips

Why do many examples use fig, ax plt.subplots

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Many Matplotlib examples begin with fig, ax = plt.subplots() because that one line gives you explicit handles to the two main plotting objects. fig represents the whole figure, and ax represents one plotting area inside it. The pattern is popular not because it is stylistically trendy, but because it scales better than relying on the implicit global state in pyplot.

What fig and ax Actually Mean

A Matplotlib figure can contain many things: axes, titles, legends, colorbars, and layout settings. The axes object is the part that usually receives plotting commands such as lines, bars, labels, and limits.

python
1import matplotlib.pyplot as plt
2
3fig, ax = plt.subplots()
4ax.plot([1, 2, 3], [1, 4, 9])
5ax.set_title("Quadratic growth")
6ax.set_xlabel("x")
7ax.set_ylabel("y")
8
9plt.show()

In that example, ax.plot() draws on one specific axes. If the figure later had multiple subplots, the same pattern would still work cleanly because each axes object stays explicit.

Why Not Just Use plt.plot()

Matplotlib also offers a stateful style through pyplot.

python
1import matplotlib.pyplot as plt
2
3plt.plot([1, 2, 3], [1, 4, 9])
4plt.title("Quadratic growth")
5plt.show()

That is fine for a quick script or a one-cell notebook example. The problem is that pyplot keeps track of a current figure and a current axes behind the scenes. Once the code grows, hidden state becomes harder to reason about.

With fig, ax = plt.subplots(), the target of each call is explicit. That makes the code easier to compose, reuse, and review.

The Object-Oriented Style Scales Better

The biggest advantage appears when you have more than one subplot.

python
1import matplotlib.pyplot as plt
2
3fig, axes = plt.subplots(1, 2, figsize=(8, 3))
4
5axes[0].plot([1, 2, 3], [1, 4, 9])
6axes[0].set_title("Line plot")
7
8axes[1].bar(["A", "B", "C"], [3, 1, 2])
9axes[1].set_title("Bar plot")
10
11fig.tight_layout()
12plt.show()

This is much clearer than bouncing between plt.subplot(), plt.plot(), plt.title(), and whatever object pyplot happens to consider current at each step.

The style also makes layout concerns easier to separate. Figure-wide adjustments belong on fig, while data-specific settings belong on ax or axes.

It Works Better With Helper Functions

Reusable plotting functions are one of the strongest reasons to prefer the explicit object style. Instead of letting a helper reach into global plotting state, pass it the axes you want it to draw on.

python
1import matplotlib.pyplot as plt
2
3def draw_series(ax, x, y, title):
4    ax.plot(x, y, marker="o")
5    ax.set_title(title)
6
7fig, ax = plt.subplots()
8draw_series(ax, [1, 2, 3], [1, 4, 9], "Reusable plot")
9plt.show()

That function can now draw into a single plot, a subplot grid, or a figure produced somewhere else. It is a much cleaner API than assuming a global current axes exists.

plt.subplots() Is Convenient, Not Verbose

Another reason the pattern survives in so many examples is that it is compact. One call creates both the figure and the axes in the most common configuration.

It also scales nicely when you need more control:

python
fig, axes = plt.subplots(2, 2, figsize=(8, 6), sharex=True, sharey=True)

That single line creates a grid and returns the handles you need to work with it. You get the benefits of explicit objects without much setup cost.

One Subtlety: ax Might Be One Object or an Array

The return shape depends on how many subplots you ask for. A single subplot usually returns one axes object. Multiple subplots usually return an array of axes.

If you want fully predictable return shapes in utility code, squeeze=False can help.

python
1import matplotlib.pyplot as plt
2
3fig, axes = plt.subplots(1, 1, squeeze=False)
4axes[0, 0].plot([1, 2], [3, 4])
5plt.show()

This is a small detail, but it explains why some examples index axes[0] while others call methods directly on ax.

Common Pitfalls

  • Treating fig and ax as interchangeable even though they represent different layers of the plotting model.
  • Mixing explicit axes-based calls with lots of implicit plt state changes in the same function.
  • Forgetting that plt.subplots() may return a single axes or an array depending on the requested layout.
  • Writing helper functions that assume a global current axes instead of accepting one explicitly.
  • Putting figure-wide operations such as layout adjustments on ax instead of fig.

Summary

  • 'fig, ax = plt.subplots() creates explicit handles to the figure and the plotting area.'
  • The pattern avoids hidden pyplot state and scales better as code gets more complex.
  • It is especially useful for multi-axes layouts and reusable plotting helpers.
  • 'fig controls figure-level concerns, while ax controls a specific subplot.'
  • The pattern is common because it is both clearer and still concise.

Course illustration
Course illustration

All Rights Reserved.