Légende Matplotlib hors du graphique : aide-mémoire bbox_to_anchor
Publié le
Mis à jour le

Par défaut, les légendes sont à l'intérieur des axes et masquent souvent les données. Pour la sortir, associez loc (quel coin de la boîte de légende sert d'ancre) et bbox_to_anchor (où cette ancre se place en coordonnées d'axes).
Correction rapide
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 200)
fig, ax = plt.subplots()
ax.plot(x, np.sin(x), label="sin(x)")
ax.plot(x, np.cos(x), label="cos(x)")
# Outside, upper-right of the axes
ax.legend(bbox_to_anchor=(1.02, 1), loc="upper left", borderaxespad=0)
plt.tight_layout()
plt.show()| Emplacement | Appel typique |
|---|---|
| À droite des axes | legend(bbox_to_anchor=(1.02, 1), loc="upper left") |
| À droite, centré verticalement | legend(loc="center left", bbox_to_anchor=(1.02, 0.5)) |
| En dessous, horizontal | legend(loc="upper center", bbox_to_anchor=(0.5, -0.12), ncol=n) |
| Au-dessus | legend(loc="lower center", bbox_to_anchor=(0.5, 1.02), ncol=n) |
| Export sans rognage | savefig(..., bbox_inches="tight") ou tight_layout() / constrained_layout=True |
Coordonnées d'axes : (0, 0) est le coin bas-gauche des axes, (1, 1) le coin haut-droit. Des valeurs légèrement au-dessus de 1 ou en dessous de 0 se placent juste hors du cadre du tracé.
- Runcell Science : l'alternative open source à Claude Science pour la recherche
- Empêcher un Mac de se mettre en veille : capot fermé, Codex et Claude Code
- OpenClaw vs ZeroClaw vs Pi Agent vs Nanobot : quelle stack d’agents IA choisir en 2026 ?
- Comment Claude Code analyse un notebook Jupyter en Data Science : capacités réelles et limites
- Claude Code routines : triggers, cron jobs et automatisation d’agents IA
- Claude Code Desktop : activer le mode Bypass permissions
- Comment Créer Deux Agents Python avec le Protocole A2A de Google - Tutoriel Étape par Étape
- Top 10 bibliothèques de visualisation de données en Python en pleine croissance en 2025
Le problème : la légende au-dessus des données
fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x, np.sin(x), label="sin(x)", lw=2)
ax.plot(x, np.cos(x), label="cos(x)", lw=2)
ax.legend(loc="best") # still inside the axes
ax.set_title("Default legend (often overlaps data)")
plt.show()
loc="best" ne choisit que le coin intérieur le moins mauvais. Il ne sort jamais la légende dans la marge de la figure.
Comment bbox_to_anchor et loc fonctionnent ensemble
bbox_to_anchor=(x, y)— point en coordonnées fractionnaires des axes (par défaut).loc="upper left"(etc.) — quel point de la boîte de légende est épinglé à cette ancre.borderaxespad— marge entre les axes et la légende ; mettez0pour un placement serré à l'extérieur.
Modèle mental : point d'ancrage sur le tracé + quel coin de la légende s'y fixe.
Placer la légende à droite
fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x, np.sin(x), label="sin(x)", lw=2)
ax.plot(x, np.cos(x), label="cos(x)", lw=2)
ax.legend(bbox_to_anchor=(1.02, 1), loc="upper left", borderaxespad=0)
ax.set_title("Legend outside: upper right of axes")
fig.tight_layout()
plt.show()
Si la fenêtre rogne encore la légende, appelez tight_layout() / utilisez constrained_layout=True dans subplots, ou réservez de l'espace en réduisant les axes (section suivante).
Réduire les axes, puis amarrer la légende
Avec de nombreuses séries, donnez au tracé une colonne dédiée à la légende :
x = np.arange(10)
fig = plt.figure(figsize=(7.2, 4.2))
ax = fig.add_subplot(111)
for i in range(5):
ax.plot(x, i * x, label=f"y = {i}x", lw=2)
# Leave ~22% of the figure width for the legend
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.78, box.height])
ax.legend(loc="center left", bbox_to_anchor=(1.02, 0.5), borderaxespad=0)
ax.set_title("Shrink axes, legend to the right")
plt.show()
Alternative moderne : créer la figure avec des moteurs de layout qui coopèrent mieux avec les artistes hors axes :
fig, ax = plt.subplots(layout="constrained")
# ... plot ...
ax.legend(bbox_to_anchor=(1.02, 1), loc="upper left")Légende sous le graphique (horizontale)
Utilisez ncol pour aligner les entrées sur une rangée sous le graphique — pratique pour les slides et les tableaux de bord larges :
x = np.arange(10)
fig = plt.figure(figsize=(7.2, 4.4))
ax = fig.add_subplot(111)
for i in range(5):
ax.plot(x, i * x, label=f"y = {i}x", lw=2)
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * 0.12, box.width, box.height * 0.88])
ax.legend(loc="upper center", bbox_to_anchor=(0.5, -0.12), ncol=5)
ax.set_title("Horizontal legend below the plot")
plt.show()
Guide de décision
| Situation | Préférer |
|---|---|
| 2–4 séries, graphique en lignes simple | bbox_to_anchor=(1.02, 1), loc="upper left" + tight_layout() |
| Beaucoup de séries, layout stable | Réduire les axes / layout="constrained" + légende à droite |
| Figure large / présentation | Légende en bas avec ncol |
| Carte ou image où toute boîte gêne | Légende intérieure semi-transparente : framealpha=0.3 (compromis) |
| Sauvegarde PNG/PDF pour articles | Toujours tester bbox_inches="tight" (ci-dessous) |
Piège d'export : la légende extérieure disparaît dans le fichier
Les fenêtres interactives peuvent afficher la légende alors que savefig la coupe. La correction habituelle :
fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x, np.sin(x), label="sin(x)", lw=2)
ax.plot(x, np.cos(x), label="cos(x)", lw=2)
ax.legend(bbox_to_anchor=(1.02, 1), loc="upper left", borderaxespad=0)
ax.set_title("Outside legend kept with bbox_inches='tight'")
fig.savefig("legend-outside.png", dpi=150, bbox_inches="tight", facecolor="white")
Approfondissement lié : savefig coupe les libellés. Si les libellés se chevauchent encore, augmentez la taille de figure avant de micro-ajuster les ancres.
Contrôles supplémentaires (sans déplacer la boîte)
ax.legend(
bbox_to_anchor=(1.02, 1),
loc="upper left",
borderaxespad=0,
frameon=True,
fancybox=False,
framealpha=0.95,
fontsize=9, # or prop={"size": 9}
title="Series",
alignment="left",
)ncol— légende multi-colonnesframealpha— transparence quand vous devez garder une légende sur les donnéestitle— libellé de groupe pour les graphiques multi-séries
Pour le style de légende en général (pas seulement la position), voir légende Matplotlib.
Pièges courants
| Piège | Ce que vous voyez | Correction |
|---|---|---|
Ne régler que loc="right" | Légende toujours à l'intérieur | Il faut bbox_to_anchor au-delà de 1.0 |
| Légende visible dans le GUI, absente du PNG | Export rogné | bbox_inches="tight" ou layout contraint |
bbox_to_anchor en coords de données par erreur | Légende qui s'envole | Par défaut : coords d'axes ; passez un 2-tuple, pas un Bbox sauf intention |
| Police de légende énorme | Domine la figure | fontsize=8–10, ou moins de colonnes |
| Chevauchement avec colorbar | Marge écrasée | Réserver de l'espace pour les deux, ou mettre la légende en bas |
FAQ
Conclusion
Les légendes extérieures sont un problème de layout, pas une API mystérieuse : épinglez un coin de légende avec loc, placez cette épingle avec bbox_to_anchor juste au-delà des axes (> 1 ou < 0), puis assurez-vous que l'export utilise un layout tight/constrained pour que la marge survive dans le fichier. Empilement à droite pour beaucoup de séries, rangée ncol en bas pour les figures larges.
Guides connexes
- Légende Matplotlib — style, titres et motifs multi-légendes
- Matplotlib savefig coupe les libellés — checklist de rognage à l'export
- Taille de figure Matplotlib — donner de la place aux légendes avant d'affiner les ancres
- Matplotlib fill_between — séries ombrées qui demandent des légendes claires
- Tracés multi-lignes Matplotlib — graphiques multi-séries qui déclenchent ce problème
- Annotations et texte Matplotlib — libellés quand une légende ne suffit pas
- Subplots Matplotlib — légendes partagées entre panneaux