pyplot vs the object-oriented API

Matplotlib · Practical · 10 min

Most confusing Matplotlib bugs come from mixing the two interfaces; knowing both lets you read any example online.

Matplotlib has two interfaces that draw the same things.

The implicit pyplot interface keeps hidden global state: a current Figure and a current Axes. plt.plot, plt.title, plt.xlabel all act on whichever Axes is current, and plt.subplot(2, 1, 2) changes which one that is. It is short and fine for a quick look in a notebook.

The explicit object-oriented interface creates objects and calls methods on them: fig, ax = plt.subplots() then ax.plot, ax.set_title, ax.set_xlabel. Nothing depends on what was created last, so it scales to multiple panels and to reusable functions. The official guidance is to prefer it for anything beyond throwaway code.

Names differ slightly between the two: plt.title is ax.set_title, plt.xlim is ax.set_xlim, plt.xticks is ax.set_xticks. The pyplot versions are thin wrappers that call plt.gca() (get current Axes) and then the method.

A good pattern for reusable plotting code is a function that accepts an Axes:

def plot_series(ax, x, y, **kw):
    return ax.plot(x, y, **kw)

The caller decides where the plot goes, so the same function works in a one-off chart or one panel of a grid. This is exactly how pandas and seaborn accept ax=.

Still use pyplot for figure creation (plt.subplots, plt.figure), plt.show() and plt.close(): those manage windows and memory.

Example

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

# Implicit: acts on the "current" Axes
plt.figure()
plt.plot([1, 2, 3])
plt.title("implicit")
print(plt.gca().get_title())          # implicit

# Explicit: methods on objects you hold
def plot_series(ax, ys, **kw):
    ax.plot(ys, **kw)
    ax.set_title(kw.get("label", ""))
    return ax

fig, (a, b) = plt.subplots(1, 2)
plot_series(a, [3, 1, 2], label="left")
plot_series(b, [1, 1, 4], label="right")
print([ax.get_title() for ax in fig.axes])  # ['left', 'right']
print(plt.gca() is b)                 # True: last Axes created is "current"
plt.close("all")

Remember

  • pyplot functions act on the current Axes; OO methods act on the object you hold
  • Prefer fig, ax = plt.subplots() and ax. methods in real code
  • Write plotting helpers that take an ax argument

Watch out for

  • Calling plt.title() in a multi-panel figure and titling the wrong panel.

Check yourself

  1. Which explicit-API call is equivalent to `plt.xlim(0, 10)`?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: matplotlib.org/stable/users/explain/figure/api_interfaces.html