Skip to content
Thèmes
Matplotlib
Matplotlib Legend Outside the Plot: bbox_to_anchor Cheatsheet

Légende Matplotlib hors du graphique : aide-mémoire bbox_to_anchor

Publié le

Mis à jour le

Placez une légende Matplotlib hors des axes avec bbox_to_anchor et loc. À droite, à gauche ou sous le tracé ; réduisez les axes si besoin ; exportez avec bbox_inches='tight' sans rognage.

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()
EmplacementAppel typique
À droite des axeslegend(bbox_to_anchor=(1.02, 1), loc="upper left")
À droite, centré verticalementlegend(loc="center left", bbox_to_anchor=(1.02, 0.5))
En dessous, horizontallegend(loc="upper center", bbox_to_anchor=(0.5, -0.12), ncol=n)
Au-dessuslegend(loc="lower center", bbox_to_anchor=(0.5, 1.02), ncol=n)
Export sans rognagesavefig(..., 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é.

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

Default Matplotlib legend inside the axes

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

  1. bbox_to_anchor=(x, y) — point en coordonnées fractionnaires des axes (par défaut).
  2. loc="upper left" (etc.) — quel point de la boîte de légende est épinglé à cette ancre.
  3. borderaxespad — marge entre les axes et la légende ; mettez 0 pour 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()

Legend placed outside to the right of the axes

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

Axes shrunk with legend docked on the right

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

Horizontal legend placed below the plot

Guide de décision

SituationPréférer
2–4 séries, graphique en lignes simplebbox_to_anchor=(1.02, 1), loc="upper left" + tight_layout()
Beaucoup de séries, layout stableRéduire les axes / layout="constrained" + légende à droite
Figure large / présentationLégende en bas avec ncol
Carte ou image où toute boîte gêneLégende intérieure semi-transparente : framealpha=0.3 (compromis)
Sauvegarde PNG/PDF pour articlesToujours 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")

Saved figure that keeps the outside legend via bbox_inches tight

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-colonnes
  • framealpha — transparence quand vous devez garder une légende sur les données
  • title — 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ègeCe que vous voyezCorrection
Ne régler que loc="right"Légende toujours à l'intérieurIl faut bbox_to_anchor au-delà de 1.0
Légende visible dans le GUI, absente du PNGExport rognébbox_inches="tight" ou layout contraint
bbox_to_anchor en coords de données par erreurLégende qui s'envolePar défaut : coords d'axes ; passez un 2-tuple, pas un Bbox sauf intention
Police de légende énormeDomine la figurefontsize=8–10, ou moins de colonnes
Chevauchement avec colorbarMarge écraséeRé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