HOWTO · Matplotlib

Enregistrer un graphique en image sans l'afficher dans Matplotlib

Enregistrez une figure Matplotlib sans ouvrir de fenêtre grâce à un backend non interactif, savefig() et au bon ordre : enregistrer puis fermer.

Sur cette page

Pour enregistrer un graphique Matplotlib complet sous forme d’image sans ouvrir de fenêtre graphique, omettez show(), enregistrez la figure concernée avec savefig() et ne la fermez qu’après l’écriture du fichier. Dans un environnement véritablement sans interface graphique, sélectionnez le backend non interactif Agg avant d’importer pyplot.

Enregistrer un graphique Matplotlib sans l’afficher

Pour enregistrer une figure Matplotlib complète sans ouvrir de fenêtre graphique, omettez show(), appelez savefig() sur la figure concernée, puis n’utilisez close() qu’une fois le fichier écrit. Sur un serveur, dans une tâche d’intégration continue, un conteneur ou tout autre environnement qui exige explicitement un backend sans interface graphique, sélectionnez le backend statique Agg avant d’importer matplotlib.pyplot.

L’ordre essentiel est : sélectionner le backend, construire la figure, l’enregistrer, puis la fermer. Conserver la référence à l’objet Figure permet de désigner la cible sans ambiguïté et évite de dépendre de la figure que pyplot considère comme active.

La sélection explicite d’Agg est surtout utile lorsqu’un script doit se comporter de manière constante sur une machine dépourvue de serveur d’affichage. Elle n’est pas nécessaire au seul motif que le script enregistre un fichier : Matplotlib peut choisir automatiquement un backend non interactif approprié. Pour une commande qui ne peut pas être modifiée, utilisez aussi MPLBACKEND=Agg. Ne combinez pas plusieurs méthodes sans raison, car Matplotlib applique un ordre de priorité et la dernière configuration applicable l’emporte.

Enregistrer une figure avec le backend sans interface graphique Agg

L’exemple testé ci-dessous enregistre un graphique sinusoïdal sous le nom sine-wave.png sans appeler show(). Agg est un backend non interactif qui produit une sortie matricielle et ne nécessite donc pas de fenêtre à l’écran.

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)

La sortie vérifiée est la suivante :

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

Figure Matplotlib enregistrée représentant une onde sinusoïdale, avec des axes légendés et une grille.

L’image est écrite dans un chemin relatif au répertoire de travail courant du processus. Un Path absolu ou un chemin construit à partir d’un répertoire connu du projet est plus sûr lorsqu’un ordonnanceur ou un service est susceptible de lancer le script depuis un autre emplacement.

Les assertions rouvrent le PNG généré et confirment qu’il existe et contient des données d’image. Cette vérification détecte une sortie absente ou illisible, tandis que l’aperçu confirme la courbe, les libellés et la grille attendus. En production, choisissez une vérification tout aussi concrète si une exportation vide ou enregistrée au mauvais endroit risque d’être coûteuse.

Choisir un format d’image et les options de savefig()

Figure.savefig() déduit généralement le format de l’extension du nom de fichier. Utilisez PNG pour une sortie matricielle largement prise en charge, SVG pour des graphiques web redimensionnables et PDF pour un document vectoriel. Si le nom ne possède pas d’extension appropriée, transmettez explicitement format.

Pour les fichiers matriciels, dpi contrôle la résolution de sortie ; il n’améliore pas la netteté des tracés vectoriels dans un fichier SVG ou PDF. bbox_inches="tight" rogne l’espace superflu, tandis que transparent=True rend transparents les arrière-plans de la figure et des axes, sauf si leurs couleurs ont été remplacées. Ces options modifient le fichier exporté, pas l’ouverture d’une fenêtre. Les formats disponibles peuvent dépendre du backend installé et de bibliothèques facultatives.

Choisissez le format en fonction de son destinataire. PNG convient à un graphique intégré dans un document ou une page web ; SVG reste net lorsque le navigateur redimensionne les traits et le texte ; PDF est pratique pour l’impression. Une valeur dpi élevée augmente les dimensions matricielles et la taille du fichier : définissez-la selon les besoins réels.

Comprendre ioff(), show() et l’ordre d’enregistrement

plt.ioff() désactive le mode interactif de pyplot, mais ne constitue pas un interrupteur universel pour une exécution sans interface graphique. Les interfaces de notebook peuvent afficher automatiquement la dernière figure d’une cellule, même lorsque le mode interactif est désactivé. Utilisez Agg lorsqu’un moteur de rendu sans GUI est nécessaire et, dans un notebook, masquez aussi la dernière valeur de figure ou fermez la figure après son enregistrement.

À l’inverse, savefig() n’a besoin ni du mode interactif ni de show(). show() sert à présenter des figures au moyen d’un backend interactif ; son omission est normale dans un script réservé à l’exportation. La désactivation de l’interactivité et la sélection d’un backend produisant un fichier résolvent donc des problèmes proches, mais différents.

Enregistrez avant d’appeler close(fig). Si vous fermez d’abord la figure, pyplot supprime sa référence ; un appel ultérieur à plt.savefig(), fondé sur l’état, peut cibler une autre figure ou une figure nouvellement créée. La documentation de show() avertit également qu’un enregistrement après un appel bloquant à show() peut produire une figure vide. Enregistrez d’abord ou conservez l’objet figure et appelez sa méthode savefig().

Libérer les figures dans les boucles et enregistrer en mémoire

Pyplot conserve des références aux figures créées par son interface. Une tâche par lots qui produit de nombreux graphiques doit appeler close(fig) après chaque enregistrement réussi afin de libérer la figure et sa mémoire. Utilisez une structure try/finally si un traitement ultérieur risque d’échouer.

Lorsqu’une autre API attend les octets de l’image et qu’aucun fichier sur disque n’est nécessaire, transmettez un objet io.BytesIO à fig.savefig() plutôt qu’un chemin. Rembobinez le tampon avec seek(0) avant de le lire ou de le téléverser, et fermez toujours la figure après l’enregistrement.

Gérer l’absence du répertoire de sortie

savefig() crée le fichier image, mais pas les répertoires parents manquants. Cet exemple de cas limite vérifié intercepte l’erreur et ferme la figure dans tous les cas :

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().

Pour une véritable exportation, créez d’abord le répertoire avec output.parent.mkdir(parents=True, exist_ok=True). Vérifiez également que le processus est autorisé à y écrire.

Utiliser imsave() pour un tableau numérique

Utilisez matplotlib.pyplot.imsave() lorsque l’entrée est un tableau numérique 2D ou RGB(A), plutôt qu’une figure tracée avec des axes, des libellés, des légendes et d’autres éléments. Cette fonction associe les valeurs du tableau à des pixels et ne remplace pas Figure.savefig() pour enregistrer un graphique complet.

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