Leyenda de Matplotlib fuera del gráfico: chuleta de bbox_to_anchor
Publicado el
Actualizado el

Las leyendas por defecto van dentro de los ejes y a menudo tapan los datos. Para dejar la leyenda fuera, combina loc (qué esquina del cuadro de la leyenda es el ancla) con bbox_to_anchor (dónde se coloca ese ancla en coordenadas de los ejes).
Solución rápida
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()| Colocación | Llamada típica |
|---|---|
| A la derecha de los ejes | legend(bbox_to_anchor=(1.02, 1), loc="upper left") |
| Derecha, centrada en vertical | legend(loc="center left", bbox_to_anchor=(1.02, 0.5)) |
| Debajo, horizontal | legend(loc="upper center", bbox_to_anchor=(0.5, -0.12), ncol=n) |
| Arriba | legend(loc="lower center", bbox_to_anchor=(0.5, 1.02), ncol=n) |
| Exportar sin recortes | savefig(..., bbox_inches="tight") o tight_layout() / constrained_layout=True |
Coordenadas de los ejes: (0, 0) es la esquina inferior izquierda de los ejes, (1, 1) la superior derecha. Valores un poco por encima de 1 o por debajo de 0 quedan justo fuera del marco del gráfico.
- Runcell Science: alternativa open source a Claude Science para investigación
- Cómo evitar que Mac se duerma: mantener Codex, Claude Code y agentes de IA corriendo
- OpenClaw vs ZeroClaw vs Pi Agent vs Nanobot: ¿Qué stack de agentes de IA deberías elegir en 2026?
- Cómo Claude Code analiza notebooks de Jupyter en Data Science: lo que sí hace y lo que no
- Claude Code routines: qué son y por qué importan los cron jobs de agentes de IA
- Claude Code Desktop Bypass Permissions: cómo activarlo
- Cómo Construir Dos Agentes en Python con el Protocolo A2A de Google - Tutorial Paso a Paso
- Las 10 principales bibliotecas de visualización de datos en Python que crecen en 2025
El problema: la leyenda encima de los datos
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" solo elige la esquina interna menos mala. Nunca saca la leyenda al margen de la figura.
Cómo trabajan juntos bbox_to_anchor y loc
bbox_to_anchor=(x, y)— punto en coordenadas fraccionarias de los ejes (por defecto).loc="upper left"(etc.) — qué punto del cuadro de la leyenda se fija a ese ancla.borderaxespad— padding entre los ejes y la leyenda; pon0cuando quieras un anclaje justito por fuera.
Modelo mental: punto de ancla en el gráfico + qué esquina de la leyenda se sienta en ese punto.
Colocar la leyenda a la derecha
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 ventana sigue recortando la leyenda, llama a tight_layout() / usa constrained_layout=True en subplots, o reserva espacio reduciendo los ejes (siguiente sección).
Reduce los ejes y luego ancla la leyenda
Cuando tienes muchas series, deja una columna dedicada a la leyenda:
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()
Alternativa moderna: crea la figura con motores de layout que cooperan mejor con artistas fuera de los ejes:
fig, ax = plt.subplots(layout="constrained")
# ... plot ...
ax.legend(bbox_to_anchor=(1.02, 1), loc="upper left")Leyenda debajo del gráfico (horizontal)
Usa ncol para que las entradas queden en una fila bajo el gráfico: bien para diapositivas y dashboards anchos:
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()
Guía de decisión
| Situación | Prefiere |
|---|---|
| 2–4 series, gráfico de líneas simple | bbox_to_anchor=(1.02, 1), loc="upper left" + tight_layout() |
| Muchas series, layout estable | Reducir ejes / layout="constrained" + leyenda a la derecha |
| Figura ancha / presentación | Leyenda inferior con ncol |
| Mapa o imagen donde cualquier caja molesta | Leyenda interna semitransparente: framealpha=0.3 (compromiso) |
| Guardar PNG/PDF para papers | Prueba siempre bbox_inches="tight" (abajo) |
Trampa al exportar: la leyenda exterior desaparece en el archivo
Las ventanas interactivas pueden mostrar la leyenda mientras savefig la recorta. El arreglo habitual:
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")
Profundidad relacionada: savefig recorta etiquetas. Si las etiquetas siguen chocando, sube el tamaño de figura antes de microajustar anclas.
Controles extra (sin mover el cuadro)
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— leyenda en varias columnasframealpha— transparencia cuando debas dejar la leyenda sobre los datostitle— etiqueta de grupo para gráficos multi-serie
Para estilos de leyenda en general (no solo posición), ver Matplotlib legend.
Trampas frecuentes
| Trampa | Qué ves | Arreglo |
|---|---|---|
Solo pones loc="right" | La leyenda sigue dentro | Necesitas bbox_to_anchor más allá de 1.0 |
| Leyenda fuera en la GUI, ausente en el PNG | Exportación recortada | bbox_inches="tight" o constrained layout |
bbox_to_anchor en coords de datos por error | La leyenda se va volando | Por defecto son coords de ejes; pasa una 2-tupla, no un Bbox salvo que sea a propósito |
| Fuente enorme de leyenda | Domina la figura | fontsize=8–10, o menos columnas |
| Solapamiento con colorbar | Margen aplastado | Reserva espacio para ambos, o pon la leyenda debajo |
FAQ
Conclusión
Las leyendas fuera son un problema de layout, no una API misteriosa: fija una esquina de la leyenda con loc, coloca ese pin con bbox_to_anchor justo más allá de los ejes (> 1 o < 0), y asegúrate de que la exportación use layout tight/constrained para que el margen sobreviva en el archivo. Usa una pila a la derecha para muchas series y una fila inferior con ncol para figuras anchas.
Related Guides
- Matplotlib legend — estilos, títulos y patrones de multi-leyenda
- Matplotlib savefig cuts off labels — checklist de recortes al exportar
- Matplotlib figure size — dar espacio a la leyenda antes de afinar anclas
- Matplotlib fill_between — series sombreadas que necesitan leyendas claras
- Matplotlib multiple line plots — gráficos multi-serie que disparan este problema
- Matplotlib annotations and text — etiquetas cuando una leyenda no basta
- Matplotlib subplots — leyendas compartidas entre paneles