Backends, interactive mode and notebooks

Matplotlib · Advanced · 12 min

Blank windows, frozen scripts and 'cannot connect to display' errors all come from backend choices you can control.

A backend is the part of Matplotlib that turns a Figure into pixels or a file and, optionally, shows it in a window. There are two kinds:

  • Non-interactive (renderers only): Agg for PNG, plus pdf, svg, ps. Use these on servers, in CI and in batch jobs.
  • Interactive: GUI backends such as QtAgg, TkAgg, MacOSX and GTK4Agg, which open windows with pan and zoom; and notebook backends: inline (static PNGs, the default in Jupyter) and ipympl's widget backend (interactive figures inside the notebook, enabled with %matplotlib widget).

Matplotlib picks a default automatically and falls back to Agg when no display is available. Override with matplotlib.use("Agg") before creating figures, the MPLBACKEND environment variable, or the backend rcParam. matplotlib.get_backend() reports the current one.

plt.show() in a script blocks until all windows are closed. In an interactive session, plt.ion() turns on interactive mode: figures appear immediately and update on each pyplot call, and show does not block. plt.pause(0.1) runs the GUI event loop briefly, the simplest way to update a live plot in a loop.

pyplot keeps a reference to every figure it created until you close it. In long-running programs that generate many charts, call plt.close(fig); otherwise memory grows and Matplotlib warns once more than 20 figures are open. Alternatively, create figures with matplotlib.figure.Figure() directly, which pyplot never tracks.

Example

import matplotlib
matplotlib.use("Agg")                 # must be before any figure is shown
import matplotlib.pyplot as plt
from matplotlib.figure import Figure

print(matplotlib.get_backend())       # Agg

for i in range(30):                   # batch job: always close
    fig, ax = plt.subplots()
    ax.plot([0, i])
    fig.savefig(f"chart_{i}.png")
    plt.close(fig)
print(len(plt.get_fignums()))         # 0: nothing kept alive

# A Figure created directly is never tracked by pyplot
fig = Figure(figsize=(3, 2))
ax = fig.subplots()
ax.bar(["a", "b"], [1, 3])
fig.savefig("untracked.png")
print(len(plt.get_fignums()))         # 0

Remember

  • Agg and other non-interactive backends render to files; GUI and notebook backends display
  • Select a backend with matplotlib.use, MPLBACKEND or rcParams
  • Close figures in loops, or use Figure() directly in servers

Watch out for

  • Using pyplot in a web server without closing figures, leaking memory on every request.

Check yourself

  1. A Flask endpoint renders a PNG chart per request using pyplot and memory keeps growing. What is the most likely fix?

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/backends.html