Pregunta Cómo sacar la leyenda de la trama


Tengo una serie de 20 tramas (no subparcelas) para hacer en una sola figura. Quiero que la leyenda esté fuera de la caja. Al mismo tiempo, no quiero cambiar los ejes, ya que el tamaño de la figura se reduce. Amablemente ayúdame para las siguientes consultas:

  1. Quiero mantener el cuadro de leyenda fuera del área de trazado. (Quiero que la leyenda esté afuera en el lado derecho del área de trazado).
  2. ¿Hay alguna forma de que reduzca el tamaño de fuente del texto dentro del cuadro de leyenda, de modo que el tamaño del cuadro de leyenda será pequeño?

587
2018-01-15 16:10


origen


Respuestas:


Crear propiedades de fuente

from matplotlib.font_manager import FontProperties

fontP = FontProperties()
fontP.set_size('small')
legend([plot1], "title", prop=fontP)

88
2018-01-15 16:21



Hay varias formas de hacer lo que desea. Para agregar a lo que @inalis y @Navi ya dijeron, puedes usar bbox_to_anchor argumento de palabra clave para colocar la leyenda parcialmente fuera de los ejes y / o disminuir el tamaño de la fuente.

Antes de considerar disminuir el tamaño de la fuente (lo que puede hacer que las cosas sean muy difíciles de leer), intente jugar colocando la leyenda en diferentes lugares:

Entonces, comencemos con un ejemplo genérico:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$' % i)

ax.legend()

plt.show()

alt text

Si hacemos lo mismo, pero usamos el bbox_to_anchor argumento de palabra clave podemos cambiar la leyenda ligeramente fuera de los límites de los ejes:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$' % i)

ax.legend(bbox_to_anchor=(1.1, 1.05))

plt.show()

alt text

Del mismo modo, puede hacer que la leyenda sea más horizontal y / o ponerla en la parte superior de la figura (también estoy activando esquinas redondeadas y una simple sombra paralela):

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    line, = ax.plot(x, i * x, label='$y = %ix$'%i)

ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.05),
          ncol=3, fancybox=True, shadow=True)
plt.show()

alt text

Alternativamente, puede reducir el ancho del gráfico actual y colocar la leyenda completamente fuera del eje de la figura:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$'%i)

# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])

# Put a legend to the right of the current axis
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

plt.show()

alt text

Y de manera similar, puede reducir la trama verticalmente y colocar la leyenda horizontal en la parte inferior:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    line, = ax.plot(x, i * x, label='$y = %ix$'%i)

# Shrink current axis's height by 10% on the bottom
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * 0.1,
                 box.width, box.height * 0.9])

# Put a legend below current axis
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),
          fancybox=True, shadow=True, ncol=5)

plt.show()

alt text

Eche un vistazo al guía de leyenda matplotlib. También puede echar un vistazo a plt.figlegend(). Espero que ayude un poco, de todos modos!


1274
2018-01-15 18:12



Colocando la leyenda (bbox_to_anchor)

Una leyenda se coloca dentro del cuadro delimitador de los ejes utilizando el loc argumento para plt.legend.
P.ej. loc="upper right" coloca la leyenda en la esquina superior derecha del cuadro delimitador, que de forma predeterminada se extiende desde (0,0) a (1,1) en las coordenadas de los ejes (o en la notación de cuadro delimitador) (x0,y0, width, height)=(0,0,1,1))

Para colocar la leyenda fuera del cuadro delimitador de ejes, se puede especificar una tupla (x0,y0) de las coordenadas de los ejes de la esquina inferior izquierda de la leyenda.

plt.legend(loc=(1.04,0))

Sin embargo, un enfoque más versátil sería especificar manualmente el cuadro delimitador en el que debe colocarse la leyenda, utilizando el bbox_to_anchor argumento. Uno puede restringirse a suministrar solo el (x0,y0) parte de la bbox. Esto crea un cuadro de span cero, fuera de la cual la leyenda se expandirá en la dirección dada por el loc argumento. P.ej.

plt.legend (bbox_to_anchor = (1.04,1), loc = "superior izquierda")

coloca la leyenda fuera de los ejes, de modo que la esquina superior izquierda de la leyenda esté en posición (1.04,1) en las coordenadas de los ejes

Más ejemplos se dan a continuación, donde, además, la interacción entre diferentes argumentos como mode y ncols son exhibidos.

enter image description here

l1 = plt.legend(bbox_to_anchor=(1.04,1), borderaxespad=0)
l2 = plt.legend(bbox_to_anchor=(1.04,0), loc="lower left", borderaxespad=0)
l3 = plt.legend(bbox_to_anchor=(1.04,0.5), loc="center left", borderaxespad=0)
l4 = plt.legend(bbox_to_anchor=(0,1.02,1,0.2), loc="lower left",
                mode="expand", borderaxespad=0, ncol=3)
l5 = plt.legend(bbox_to_anchor=(1,0), loc="lower right", 
                bbox_transform=fig.transFigure, ncol=3)
l6 = plt.legend(bbox_to_anchor=(0.4,0.8), loc="upper right")

Detalles sobre cómo interpretar el argumento 4-tuple para bbox_to_anchor, como en l4, puede encontrarse en esta pregunta. los mode="expand" expande la leyenda horizontalmente dentro del cuadro delimitador dado por la 4-tupla. Para una leyenda expandida verticalmente, vea esta pregunta.

A veces puede ser útil especificar el cuadro delimitador en las coordenadas de la figura en lugar de las coordenadas de los ejes. Esto se muestra en el ejemplo l5 desde arriba, donde el bbox_transform el argumento se usa para poner la leyenda en la esquina inferior izquierda de la figura.

Postprocesamiento

Habiendo colocado la leyenda fuera de los ejes a menudo conduce a la situación no deseada de que esté completa o parcialmente fuera del lienzo de la figura.

Las soluciones a este problema son:

  • Ajuste los parámetros de la subparcela
    Uno puede ajustar los parámetros de la subtrama de tal manera que los ejes ocupen menos espacio dentro de la figura (y así dejen más espacio a la leyenda) al usar plt.subplots_adjust. P.ej.

    plt.subplots_adjust(right=0.7)
    

    deja un 30% de espacio en el lado derecho de la figura, donde se podría colocar la leyenda.

  • Diseño apretado
    Utilizando plt.tight_layout Permite ajustar automáticamente los parámetros de la subtrama de modo que los elementos de la figura se asienten firmemente contra los bordes de la figura. Desafortunadamente, la leyenda no se tiene en cuenta en este automatismo, pero podemos suministrar un rectángulo que encaje en toda el área de las subtramas (incluidas las etiquetas).

    plt.tight_layout(rect=[0,0,0.75,1])
    
  • Guardando la figura con bbox_inches = "tight"
    El argumento bbox_inches = "tight" a plt.savefig se puede usar para guardar la figura de modo que todos los artistas del lienzo (incluida la leyenda) quepan en el área guardada. Si es necesario, el tamaño de la figura se ajusta automáticamente.

    plt.savefig("output.png", bbox_inches="tight")
    
  • ajustando automáticamente los parámetros de la subparcela
    Una forma de ajustar automáticamente la posición de la subtrama de modo que la leyenda entre dentro del lienzo sin cambiar el tamaño de la figura se puede encontrar en esta respuesta: Creación de figura con tamaño exacto y sin relleno (y leyenda fuera de los ejes)

Comparación entre los casos discutidos anteriormente:

enter image description here

Alternativas

Una leyenda de la figura
Se puede usar una leyenda para la figura en lugar de los ejes, matplotlib.figure.Figure.legend. Esto se ha vuelto especialmente útil para la versión matplotlib> = 2.1, donde no se necesitan argumentos especiales

fig.legend(loc=7) 

para crear una leyenda para todos los artistas en los diferentes ejes de la figura. La leyenda se coloca usando el loc argumento, similar a cómo se coloca dentro de un eje, pero en referencia a la figura completa; por lo tanto, estará fuera de los ejes de forma algo automática. Lo que resta es ajustar las subparcelas de modo que no haya superposición entre la leyenda y los ejes. Aquí el punto "Ajuste los parámetros de la subparcela"  desde arriba será útil. Un ejemplo:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,2*np.pi)
colors=["#7aa0c4","#ca82e1" ,"#8bcd50","#e18882"]
fig, axes = plt.subplots(ncols=2)
for i in range(4):
    axes[i//2].plot(x,np.sin(x+i), color=colors[i],label="y=sin(x+{})".format(i))

fig.legend(loc=7)
fig.tight_layout()
fig.subplots_adjust(right=0.75)   
plt.show()

enter image description here

Leyenda dentro de ejes de subtrama dedicados
Una alternativa al uso bbox_to_anchor sería colocar la leyenda en sus ejes de subtrama dedicados (lax) Dado que la subtrama de la leyenda debe ser más pequeña que la trama, podemos usar gridspec_kw={"width_ratios":[4,1]} en la creación de ejes. Podemos esconder los ejes lax.axis("off") pero aún así se pone una leyenda. La leyenda maneja y las etiquetas necesitan ser obtenidas de la trama real a través de h,l = ax.get_legend_handles_labels(), y luego se puede suministrar a la leyenda en el lax subtrama, lax.legend(h,l). Un ejemplo completo está abajo.

import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = 6,2

fig, (ax,lax) = plt.subplots(ncols=2, gridspec_kw={"width_ratios":[4,1]})
ax.plot(x,y, label="y=sin(x)")
....

h,l = ax.get_legend_handles_labels()
lax.legend(h,l, borderaxespad=0)
lax.axis("off")

plt.tight_layout()
plt.show()

Esto produce una trama que es visualmente muy similar a la trama de arriba:

enter image description here

También podríamos usar los primeros ejes para colocar la leyenda, pero usemos bbox_transform de los ejes de la leyenda,

ax.legend(bbox_to_anchor=(0,0,1,1), bbox_transform=lax.transAxes)
lax.axis("off")

En este enfoque, no necesitamos obtener los manejadores de leyenda externamente, pero tenemos que especificar el bbox_to_anchor argumento.

Lecturas y notas adicionales:

  • Considere el matplotlib guía de leyenda con algunos ejemplos de otras cosas que quieres hacer con leyendas.
  • Algunos ejemplos de código para colocar leyendas para gráficos circulares se pueden encontrar directamente en respuesta a esta pregunta: Python: la leyenda se superpone con el gráfico circular
  • los loc el argumento puede tomar números en lugar de cadenas, lo que hace que las llamadas sean más cortas, sin embargo, no se mapean muy intuitivamente entre sí. Aquí está el mapeo de referencia:

enter image description here


308
2018-04-16 16:04



Si estás usando pandas plot() función de envoltura y desea colocar la leyenda fuera de aquí, esta es una manera muy fácil:

df.myCol.plot().legend(loc='center left', bbox_to_anchor=(1, 0.5))

Nosotros solo encadenamos legend() llamar despues del plot().

Los resultados se verían así:

enter image description here


107
2017-07-03 02:43



Respuesta corta: puedes usar bbox_to_anchor + bbox_extra_artists + bbox_inches='tight'.


Respuesta más larga: Puedes usar bbox_to_anchor para especificar manualmente la ubicación del cuadro de leyenda, como han señalado otras personas en las respuestas.

Sin embargo, el problema habitual es que el cuadro de leyenda está recortado, por ejemplo:

import matplotlib.pyplot as plt

# data 
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]

# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)

# Add legend, title and axis labels
lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')

fig.savefig('image_output.png', dpi=300, format='png')

enter image description here

Para evitar que se recorte la caja de leyenda, cuando guarde la figura, puede usar los parámetros bbox_extra_artists y bbox_inches preguntar savefig para incluir elementos recortados en la imagen guardada:

fig.savefig('image_output.png', bbox_extra_artists=(lgd,), bbox_inches='tight')

Ejemplo (solo cambié la última línea para agregar 2 parámetros a fig.savefig())

import matplotlib.pyplot as plt

# data 
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]

# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)

# Add legend, title and axis labels
lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')    

fig.savefig('image_output.png', dpi=300, format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')

enter image description here

Desearía que matplotlib permitiera de forma nativa la ubicación externa para el cuadro de leyenda como Matlab lo hace:

figure
x = 0:.2:12;
plot(x,besselj(1,x),x,besselj(2,x),x,besselj(3,x));
hleg = legend('First','Second','Third',...
              'Location','NorthEastOutside')
% Make the text of the legend italic and color it brown
set(hleg,'FontAngle','italic','TextColor',[.3,.2,.1])

enter image description here


69
2017-08-16 22:49



Respuesta corta: Invoque la leyenda arrastrándola y muévala interactivamente donde desee:

ax.legend().draggable()

Respuesta larga: Si prefiere colocar la leyenda de forma interactiva / manual en lugar de programáticamente, puede alternar el modo de la leyenda que se puede arrastrar para que pueda arrastrarlo a donde desee. Verifique el ejemplo a continuación:

import matplotlib.pylab as plt
import numpy as np
#define the figure and get an axes instance
fig = plt.figure()
ax = fig.add_subplot(111)
#plot the data
x = np.arange(-5, 6)
ax.plot(x, x*x, label='y = x^2')
ax.plot(x, x*x*x, label='y = x^3')
ax.legend().draggable()
plt.show()

50
2018-02-20 19:41



Además de todas las excelentes respuestas aquí, las versiones más nuevas de matplotlib y pylab poder determinar automáticamente dónde colocar la leyenda sin interferir con las parcelas.

pylab.legend(loc='best')

Esto colocará automáticamente la leyenda fuera de la trama! Compare the use of loc='best'


46
2017-12-08 09:46