The Figure & Axes object model

Most beginners learn Matplotlib through plt.plot() and plt.title(). That works for one quick chart, but the moment you need two panels, a shared axis or a custom tick, the "stateful" pyplot style becomes confusing. The fix is to understand the object model that sits underneath every chart.

Three layers: Figure, Axes, Artist

Object What it is Typical methods
Figure The whole canvas / image file fig.suptitle(), fig.savefig(), fig.colorbar()
Axes One plotting area with its own x and y axis ax.plot(), ax.bar(), ax.set_xlabel()
Axis The x or y axis inside an Axes (ticks, limits) ax.xaxis.set_major_formatter()
Artist Anything drawn: lines, text, patches, legends line.set_color(), text.set_fontsize()

Note the naming trap: Axes (plural-looking) is one plot panel, while Axis is a single x or y ruler.

Pyplot style vs object-oriented style

import matplotlib.pyplot as plt

months = ["Apr", "May", "Jun", "Jul"]
sales = [4.2, 5.1, 4.8, 6.3]   # lakh INR

# Implicit (pyplot) style: works on "the current axes"
plt.plot(months, sales)
plt.title("Monthly sales")

# Explicit (object-oriented) style: recommended
fig, ax = plt.subplots(figsize=(7, 4))
line, = ax.plot(months, sales, marker="o")
ax.set_title("Monthly sales - Jaipur store")
ax.set_ylabel("Sales (lakh INR)")
ax.set_ylim(0, 7)
line.set_linewidth(2.5)          # every plot call returns Artists you can tweak
fig.tight_layout()

With the explicit style you always know which panel a command affects. This matters once you write functions such as def plot_city(ax, df): that draw into an Axes passed from outside - the function becomes reusable in any layout.

Setting many properties at once

ax.set() accepts several properties in one call, which keeps chart code compact:

ax.set(title="Footfall by weekday", xlabel="Day", ylabel="Visitors", xlim=(0, 6))

Adding Axes by hand

plt.subplots() builds a regular grid, but you can also place Axes anywhere with figure-relative coordinates (0 to 1). This is handy for an inset chart:

fig, ax = plt.subplots()
ax.plot(range(12), [3, 4, 4, 5, 7, 9, 8, 7, 6, 5, 4, 3])
inset = fig.add_axes([0.62, 0.6, 0.25, 0.25])   # left, bottom, width, height
inset.bar(["Online", "Store"], [35, 65])
inset.set_title("Channel %", fontsize=8)

For uneven grids use plt.subplot_mosaic("AAB;CCB"), which returns a dictionary of Axes keyed by letter - very readable for report layouts.

Getting back to objects

If you inherit pyplot code, plt.gcf() returns the current Figure and plt.gca() the current Axes, so you can migrate gradually. Every Axes also knows its parent: ax.figure.

Common mistakes

  • Mixing styles: calling plt.title() after creating several Axes titles only the last one.
  • Forgetting the comma in line, = ax.plot(...) - plot returns a list of lines.
  • Creating figures in a loop without plt.close(fig), which slowly eats memory in scripts and Django views.
  • Confusing fig.suptitle (whole figure) with ax.set_title (one panel).

Practice

Write a function plot_branch(ax, name, values) that draws a line chart of 12 monthly values into the Axes it receives and sets a title and y-label. Then create a 2x2 grid with plt.subplots and call the function for four branches (Pune, Indore, Kochi, Lucknow) using random data. Add one fig.suptitle.

B

Written by Bablu Kumar Jha

Founder, BeeProton AI · Mumbai, Maharashtra, India