Fixing Blank or Corrupted Matplotlib Images in Headless Environments
Learn how to diagnose empty Matplotlib figures caused by wrong backend in headless servers and apply targeted fixes.
20 Oct 2026, 19:43 UTC

Problem: Blank or Corrupted Matplotlib Images
When a Python script that uses Matplotlib calls plt.show() or savefig() on a server without a display (no X server, no graphical terminal), the resulting image file is often empty or contains only a white rectangle. The file may be created with zero bytes, or it may appear as a blank canvas even though the script finishes without error.
What the symptom looks like
The figure never appears on screen, and the saved PNG/PDF file has a size of 0 KB or shows only a blank area. In console output you may see warnings such as “TkAgg” or “Qt5Agg” failing to open a window, indicating that an interactive backend was selected.
Typical cause
The default Matplotlib backend (e.g., TkAgg, Qt5Agg) expects an interactive graphical environment. In a headless environment these backends cannot create a window, so the canvas is never drawn and the output is empty. Changing the backend after importing pyplot can raise an ImportError, so the backend must be set before any Matplotlib import.
Diagnostic table
| Symptom | Likely Cause | Quick Check |
|---|---|---|
| Empty PNG/PDF file, size 0 KB | Interactive backend selected (TkAgg, Qt5Agg) | Run import matplotlib; print(matplotlib.get_backend()) |
| Figure appears but is blank/white | Missing image format library (e.g., Pillow for PNG) | Check pip show pillow |
| Figure size zero, no content | Figure dimensions or DPI set to zero | Inspect fig.get_size_inches() and fig.dpi |
Ordered checks
- Confirm the active backend
Run the commandpython - <<'PY' import matplotlib print("Backend:", matplotlib.get_backend()) PYon the same machine where the script runs. Expected output: a backend name such asAggorSVG. If the output showsTkAggorQt5Aggyou are using an interactive backend that cannot run headlessly. This step requires normal Python execution permissions; no special privileges are needed. - Switch to a non‑interactive backend before importing pyplot
Place the backend selection line at the very top of the script, before anyimport matplotlib.pyplot as pltorimport matplotlib. Example:
import matplotlib; matplotlib.use('Agg')Then import pyplot. This must be done on the server where the script executes. Risk: attempting to change the backend after imports will raise anImportError. - Verify required image libraries are present
For PNG output, Matplotlib relies on Pillow. Runpip show pillow
. If the command reports “Package not found”, install it withpip install --user pillow. After installation, re‑run the backend test. Risk: missing library leads to a file with zero bytes or a corrupted image. - Check figure size and DPI
Add a diagnostic line before saving:
print("Figure size:", fig.get_size_inches(), "DPI:", fig.dpi)The size should be non‑zero (e.g., (6.4, 4.8)) and DPI a positive integer (default 100). If either value is 0, the canvas has no area and the saved file will be empty. Ensure these calls occur after figure creation but beforesavefig(). Risk: zero dimensions cause an empty canvas. - Save a test figure and inspect the file
Create a minimal script:
import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt fig, ax = plt.subplots() ax.plot([0, 1, 2]) fig.savefig('test.png')Run the script on the server. Then check the file size:
ls -lh test.png– it should be >0 KB (e.g., 2.3K). Open the PNG with an image viewer to confirm content. If the file is still zero bytes, the problem lies in the backend or missing library. Risk: running the script requires write permission to the directory wheretest.pngis created.
Fixes tied to findings
- If the backend check shows an interactive backend, change the script to use
Agg(or another non‑interactive backend such asPDForSVG) before any import. This eliminates the need for a display server. - If Pillow is missing, install it with
pip install --user pillow. Verify withpython -c "import PIL; print(PIL.__version__)". After installation, rerun the test script. - If figure dimensions or DPI are zero, adjust the code:
fig.set_size_inches(6.4, 4.8)fig.set_dpi(100)Make sure these calls occur after figure creation but before saving. Risk: incorrect dimensions can produce a zero‑size canvas.
Escalation criteria
If after performing the above checks the image remains empty or corrupted, consider the following escalation path:
- Verify that the server’s environment variables do not force a specific backend (e.g.,
QT_QPA_PLATFORM=xcb). Remove or override them. - Upgrade Matplotlib to the latest stable release (≥3.8) and re‑run the backend test; newer releases may change default backends.
- If the problem persists on multiple servers, the issue may be system‑level (e.g., missing X11 libraries). Contact the infrastructure team to confirm that no X server is inadvertently available.
Summary checklist
- Set backend to
Aggbefore any import. - Confirm backend with
matplotlib.get_backend(). - Install Pillow if PNG output is required.
- Ensure figure size and DPI are non‑zero.
- Validate file size >0 KB after
savefig().
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.