7.1 Figures, Axes, and the Object-Oriented API
Chapter 6 turned cleaned observations into variables that are ready to compare. Visualization adds another transformation: values become positions, lengths, colors, shapes, and text. Before choosing a chart, you need to know where Matplotlib places those visual objects.
Read a Matplotlib figure as an object hierarchy
A Figure is the top-level container—the complete canvas that can be displayed or saved. An Axes is one plotting panel inside that Figure. Despite its name, one Axes is singular. A normal two-dimensional Axes contains an x-axis and y-axis, represented by Axis objects that manage scales, ticks, and tick labels.
Lines, points, bars, text, legends, images, and even the Axes itself are Artists: objects Matplotlib knows how to draw. The practical hierarchy is:
Figure
└── one or more Axes
├── xaxis and yaxis
├── data Artists: lines, collections, patches, images
└── explanatory Artists: title, labels, legend, annotationsCreate and retain the objects explicitly:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 4.5), layout="constrained")
line, = ax.plot(
daily["date"],
daily["revenue"],
marker="o",
)
ax.set(
title="Daily revenue",
xlabel="Date",
ylabel="Revenue (USD)",
)
fig.suptitle("Store operations")figsize is measured in inches. The Figure owns the overall title and layout; the Axes owns the data coordinate system and panel-level labels. ax.plot creates a Line2D Artist and adds it to that Axes. The trailing comma in line, = ... unpacks the one-element list returned by plot.
This style is often called the object-oriented API or, more precisely in current Matplotlib documentation, the explicit Axes interface. The alternative plt.plot(...) uses an implicit current Axes. That shortcut is convenient for one-off exploration, but hidden state becomes fragile when a notebook has several panels or helper functions.
Treat Artists as configurable, testable results
Plotting methods return the Artists they create. Keep those references when later code needs to configure or verify them:
actual_line, = ax.plot(x, actual, label="Actual", zorder=3)
target_line, = ax.plot(
x,
target,
label="Target",
linestyle="--",
zorder=2,
)
band = ax.fill_between(
x,
target * 0.95,
target * 1.05,
alpha=0.15,
label="Target ±5%",
zorder=1,
)zorder controls drawing order: larger values appear above smaller ones. A contextual band usually belongs behind the primary data line. Transparency helps, but it does not replace sensible layer order.
A reusable drawing function should receive an Axes instead of creating a Figure or calling plt.gca():
def plot_target(ax, x, actual, target):
band = ax.fill_between(
x, target * 0.95, target * 1.05,
alpha=0.15, label="Target ±5%", zorder=1,
)
actual_line, = ax.plot(
x, actual, marker="o", label="Actual", zorder=3,
)
target_line, = ax.plot(
x, target, linestyle="--", label="Target", zorder=2,
)
return {
"band": band,
"actual": actual_line,
"target": target_line,
}This separation gives the caller control over layout, legend placement, saving, and display. It also supports structural tests:
artists = plot_target(ax, weeks, actual, target)
assert artists["actual"].axes is ax
assert artists["band"].get_zorder() < artists["actual"].get_zorder()Avoid tests that compare every output pixel unless exact rendering is the requirement. Fonts and rasterization can differ across backends and operating systems. Prefer testing bound data, labels, limits, scales, Artist count, and ownership; add a small number of visual regression tests only where appearance itself is the contract.
Control the Figure lifecycle
In a notebook, the last expression may display a Figure automatically. A script usually calls plt.show() for an interactive window or fig.savefig(...) for an artifact. When generating many figures in a loop or service, close each Figure after saving:
fig.savefig("daily-revenue.svg", bbox_inches="tight")
plt.close(fig)Closing releases GUI and renderer resources; it does not delete the saved file. The next section uses this object model to choose and construct line, bar, scatter, and distribution plots based on the analytical question.