Behavior of plt.show() When Using the Agg Backend
0 reputation · 28 Feb 2024, 01:05 UTC
0 reputation · 28 Feb 2024, 01:05 UTC
Determine whether invoking plt.show() after selecting the Agg backend blocks script execution or returns immediately, and what consequences this has for automated environments that rely on headless rendering.
The Agg backend is documented as providing a pure‑CPU raster buffer without a GUI event loop, which means interactive features are unavailable. However, the exact behavior of the show() function—whether it enters a blocking loop, returns instantly, or triggers any hidden side‑effects—is not explicitly defined in the current documentation, leaving room for interpretation when integrating matplotlib into CI pipelines or containerized workloads.
32775 reputation · 28 Feb 2024, 12:11 UTC
When the Agg backend is active, plt.show() returns immediately. It does not block script execution, open a window, or enter a GUI event loop. In practice it behaves as a no-op for display purposes.
The confirmed behavior is that show() is non-blocking under Agg. The architectural reason is that Agg is a non-interactive, pure-CPU raster backend: it has no GUI toolkit and therefore no event loop for show() to enter. Interactive backends such as TkAgg or QtAgg override the show path to block until the user closes the figure; Agg does not.
There are no hidden side effects from the call itself. No display server connection is made, no OS-level window resources are allocated, and no pending GUI events are queued. The only observable effect is that any figures already created remain in Matplotlib's internal registry.
Calling fig.canvas.start_event_loop() on an Agg canvas is a no-op inherited from FigureCanvasBase in matplotlib.backend_bases, not an exception. Interactive GUI backends override this method to block; Agg does not. If your code depends on this guarantee, inspect the installed backend_bases.py to confirm the base implementation.
Because figures are not destroyed by show(), scripts that generate many plots in a loop can accumulate memory. Explicitly close figures with plt.close(fig) or plt.close('all') when the rendered output has been saved or discarded.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 1], [0, 1])
plt.show()
print("show returned immediately")
The marker should print instantly with no window appearing.
python -c "import inspect; from matplotlib.backend_bases import FigureCanvasBase; print(inspect.getsource(FigureCanvasBase.start_event_loop))"
python -c "import matplotlib; matplotlib.use('Agg'); import matplotlib.pyplot as plt; print(plt.get_backend(), plt.isinteractive()); plt.show(); print(plt.get_backend(), plt.isinteractive())"
This description assumes Matplotlib 3.x, where Agg has long been the standard non-interactive backend. Depending on the exact release, a UserWarning about non-GUI backends may be emitted, but the warning text and presence vary; do not rely on stderr output to detect behavior. Also note that plt.ion() does not make Agg interactive—it only changes draw timing, not whether show() blocks.
If your CI pipeline observes blocking behavior, the Matplotlib version and any site-packages overrides or third-party style hooks are the first details to check, because stock Agg behavior is non-blocking.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.