HOWTO · Matplotlib

Matplotlib-Plots als Bilddatei speichern, ohne sie anzuzeigen

Speichern Sie eine Matplotlib-Abbildung ohne Fenster mit einem nicht interaktiven Backend, savefig() und der richtigen Reihenfolge: erst speichern, dann schließen.

Auf dieser Seite

Um einen vollständigen Matplotlib-Plot als Bild zu speichern, ohne ein GUI-Fenster zu öffnen, lassen Sie show() weg, speichern Sie die konkrete Figure mit savefig() und schließen Sie sie erst nach dem Schreiben der Datei. Für wirklich fensterlose Umgebungen wählen Sie das nicht-interaktive Backend Agg, bevor Sie pyplot importieren.

Einen Matplotlib-Plot speichern, ohne ihn anzuzeigen

Um eine vollständige Matplotlib-Abbildung zu speichern, ohne ein GUI-Fenster zu öffnen, lassen Sie show() weg, rufen savefig() für die konkrete Abbildung auf und verwenden close() erst, nachdem die Datei geschrieben wurde. Wählen Sie auf einem Server, in einem CI-Job, einem Container oder einer anderen Umgebung, die ausdrücklich ein Headless-Backend benötigt, das statische Agg-Backend aus, bevor Sie matplotlib.pyplot importieren.

Die entscheidende Reihenfolge lautet: Backend auswählen, Abbildung erstellen, speichern und anschließend schließen. Durch die Referenz auf das Figure-Objekt ist das Ziel eindeutig; Sie sind nicht darauf angewiesen, welche Abbildung pyplot gerade als aktiv betrachtet.

Die explizite Auswahl von Agg ist besonders sinnvoll, wenn sich ein Skript auf einem Rechner ohne Display-Server zuverlässig gleich verhalten soll. Sie ist nicht allein deshalb erforderlich, weil das Skript eine Datei speichert: Matplotlib kann automatisch ein passendes nicht interaktives Backend auswählen. Für einen nicht editierbaren Befehl lässt sich das Backend alternativ über MPLBACKEND=Agg festlegen. Kombinieren Sie nicht ohne Grund mehrere Auswahlmethoden, da Matplotlib eine Rangfolge anwendet und die zuletzt wirksame Konfiguration gewinnt.

Eine Abbildung mit dem Headless-Backend Agg speichern

Das folgende getestete Beispiel speichert einen Sinus-Plot als sine-wave.png, ohne show() aufzurufen. Agg ist ein nicht interaktives Backend, das Rasterausgaben erzeugt und deshalb kein Bildschirmfenster benötigt.

from pathlib import Path

import matplotlib

matplotlib.use("Agg")

import matplotlib.pyplot as plt
import numpy as np

output = Path("sine-wave.png")
x = np.linspace(0, 2 * np.pi, 200)

fig, ax = plt.subplots(figsize=(6, 4))
ax.plot(x, np.sin(x), color="#2166ac", linewidth=2)
ax.set(title="Sine wave", xlabel="x", ylabel="sin(x)")
ax.grid(alpha=0.25)

fig.savefig(output, dpi=150, bbox_inches="tight")
plt.close(fig)

saved = plt.imread(output)
assert output.is_file() and saved.size > 0
print("backend:", matplotlib.get_backend())
print("saved:", output.name)
print("valid PNG:", True)

Die verifizierte Ausgabe lautet:

backend: Agg
saved: sine-wave.png
valid PNG: True

Gespeicherte Matplotlib-Sinuskurve mit beschrifteten Achsen und einem Raster.

Das Bild wird relativ zum aktuellen Arbeitsverzeichnis des Prozesses geschrieben. Ein absoluter Path oder ein aus einem bekannten Projektverzeichnis aufgebauter Pfad ist sicherer, wenn ein Scheduler oder Dienst das Skript möglicherweise in einem anderen Verzeichnis startet.

Die Assertions öffnen die erzeugte PNG-Datei erneut und bestätigen, dass sie vorhanden ist und Bilddaten enthält. Dadurch wird eine fehlende oder nicht lesbare Ausgabe erkannt; die gerenderte Vorschau bestätigt außerdem die erwartete Kurve, Beschriftungen und das Raster. Wählen Sie in Produktivsystemen eine ähnlich konkrete Prüfung, wenn ein leerer oder falsch abgelegter Export teuer wäre.

Bildformat und Optionen für savefig() auswählen

Figure.savefig() leitet das Format normalerweise von der Dateiendung ab. Verwenden Sie PNG für breit unterstützte Rasterausgaben, SVG für skalierbare Webgrafiken und PDF für ein Vektordokument. Besitzt der Dateiname keine passende Endung, geben Sie format ausdrücklich an.

Bei Rasterdateien steuert dpi die Ausgabeauflösung; Vektorpfade in SVG- oder PDF-Dateien werden dadurch nicht schärfer. bbox_inches="tight" schneidet überschüssigen Rand ab, während transparent=True den Hintergrund von Abbildung und Achsen transparent macht, sofern deren Farben nicht überschrieben wurden. Diese Optionen beeinflussen die exportierte Datei, nicht das Öffnen eines Fensters. Welche Formate verfügbar sind, kann vom installierten Backend und optionalen Bibliotheken abhängen.

Wählen Sie das Format nach dem späteren Einsatz. PNG eignet sich für Diagramme in Dokumenten oder Webseiten; SVG bleibt beim Skalieren von Liniengrafiken und Text scharf; PDF ist praktisch für druckorientierte Abläufe. Ein hoher dpi-Wert erhöht die Rasterabmessungen und Dateigröße. Legen Sie ihn anhand der beabsichtigten Anzeige- oder Druckgröße fest.

ioff(), show() und die Speicherreihenfolge verstehen

plt.ioff() deaktiviert den interaktiven Modus von pyplot, ist aber kein universeller Headless-Schalter. Notebook-Frontends können die letzte Abbildung einer Zelle automatisch darstellen, obwohl der interaktive Modus ausgeschaltet ist. Verwenden Sie Agg, wenn ein Renderer ohne GUI erforderlich ist, und unterdrücken Sie im Notebook zusätzlich den letzten Abbildungswert oder schließen Sie die Abbildung nach dem Speichern.

Umgekehrt benötigt savefig() weder den interaktiven Modus noch show(). show() stellt Abbildungen über ein interaktives Backend dar; für ein reines Exportskript ist es normal, den Aufruf wegzulassen. Das Deaktivieren der Interaktivität und die Auswahl eines dateibasierten Renderers lösen daher verwandte, aber unterschiedliche Probleme.

Speichern Sie vor close(fig). Wird die Abbildung zuerst geschlossen, entfernt pyplot seine Referenz darauf, sodass ein späteres zustandsbasiertes plt.savefig() eine andere oder neu erstellte Abbildung treffen kann. Auch die Dokumentation zu show() warnt davor, dass das Speichern nach einem blockierenden show() eine leere Abbildung erzeugen kann. Speichern Sie zuerst, oder behalten Sie das Abbildungsobjekt und rufen dessen savefig()-Methode auf.

Abbildungen in Schleifen freigeben und im Speicher speichern

Pyplot behält Referenzen auf Abbildungen, die über seine Schnittstelle erstellt wurden. Ein Batch-Job mit vielen Plots sollte nach jedem erfolgreichen Speichern close(fig) aufrufen, damit Abbildung und Speicher freigegeben werden. Verwenden Sie ein try/finally-Muster, wenn eine spätere Verarbeitung fehlschlagen kann.

Wenn eine andere API die Bildbytes benötigt und keine Datei auf dem Datenträger erforderlich ist, übergeben Sie an fig.savefig() statt eines Dateipfads ein io.BytesIO-Objekt. Setzen Sie den Puffer vor dem Lesen oder Hochladen mit seek(0) zurück, und schließen Sie die Abbildung nach dem Speichern.

Ein fehlendes Ausgabeverzeichnis behandeln

savefig() erstellt die Bilddatei, aber keine fehlenden übergeordneten Verzeichnisse. Dieses verifizierte Grenzfallbeispiel fängt den Fehler ab und schließt die Abbildung in jedem Fall:

from pathlib import Path

import matplotlib

matplotlib.use("Agg")

import matplotlib.pyplot as plt

output = Path("missing") / "plot.png"
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [2, 4, 3])

try:
    fig.savefig(output)
except FileNotFoundError:
    print("Create the parent directory before savefig().")
finally:
    plt.close(fig)
Create the parent directory before savefig().

Erstellen Sie für einen echten Export das Verzeichnis vorher mit output.parent.mkdir(parents=True, exist_ok=True). Prüfen Sie außerdem, ob der Prozess dort Schreibrechte besitzt.

imsave() für ein numerisches Array verwenden

Verwenden Sie matplotlib.pyplot.imsave(), wenn die Eingabe ein numerisches 2D- oder RGB(A)-Array ist und keine geplottete Abbildung mit Achsen, Beschriftungen, Legenden und anderen Elementen. Die Funktion bildet Array-Werte auf Bildpixel ab und ersetzt Figure.savefig() nicht, wenn ein vollständiger Plot gespeichert werden soll.

from pathlib import Path

import matplotlib

matplotlib.use("Agg")

import matplotlib.pyplot as plt
import numpy as np

pixels = np.array([[0.0, 0.5, 1.0], [1.0, 0.5, 0.0]])
output = Path("array-image.png")

plt.imsave(output, pixels, cmap="gray", vmin=0, vmax=1)

saved = plt.imread(output)
assert output.is_file() and saved.shape[:2] == pixels.shape
print("saved array:", output.name)
print("pixel grid:", saved.shape[0], "x", saved.shape[1])
saved array: array-image.png
pixel grid: 2 x 3