Cómo sacar la leyenda de la trama

988

Tengo una serie de 20 tramas (no subtramas) 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údenme para las siguientes consultas:

  1. Quiero mantener el cuadro de leyenda fuera del área de la trama. (Quiero que la leyenda esté afuera en el lado derecho del área de la trama).
  2. ¿Hay alguna forma de reducir el tamaño de fuente del texto dentro del cuadro de leyenda, de modo que el tamaño del cuadro de leyenda sea pequeño.
pottigopi
fuente
14
Para las versiones más recientes de matplotlib, esta respuesta muestra cómo configurar matplotlib para determinar automáticamente dónde colocar la leyenda sin interferir con los gráficos .
dotancohen
2
Tenía la misma pregunta y encontré este gran ejemplo que funcionó para mí "fuera de la caja": matplotlib.org/1.3.1/users/legend_guide.html
robodasha
1
Esta respuesta tiene más profundidad https://stackoverflow.com/a/43439132/52074. ¡Y lo hace con dos líneas de código! la respuesta votada +1200 también es buena, pero me pareció menos genérica.
Trevor Boyd Smith
2
@dotancohen "determina automáticamente dónde colocar la leyenda sin interferir con las tramas" En ciertos casos, cuando la trama tiene muchas curvas, desafortunadamente es imposible. En esos casos, el usuario puede querer colocar manualmente la leyenda y, de hecho, ponerla fuera del área de trazado. Estoy teniendo dificultades con tal complot en este momento.
Ali
por cierto, la lista de opciones de loc: mejor; superior derecha; arriba a la izquierda; abajo a la izquierda; inferior derecha; Correcto; centro izquierda; centro derecha; centro inferior centro superior; centrar;
Z-Y00

Respuestas:

57

Puede hacer que el texto de la leyenda sea más pequeño creando propiedades de fuente:

from matplotlib.font_manager import FontProperties

fontP = FontProperties()
fontP.set_size('small')
legend([plot1], "title", prop=fontP) 
# or add prop=fontP to whatever legend() call you already have
Navi
fuente
50
¿Qué hay plot1en esta respuesta?
Paul H
41
¿Qué hay legenden esta respuesta?
Richard
28
Esto responde a la parte secundaria de la pregunta, pero no a la primaria (la que se titula).
Mateen Ulhaq
8
Además, la forma correcta de hacer esto esplt.legend(fontsize='small')
Mateen Ulhaq
41
¡Esta respuesta es terrible y proporciona muy poco contexto!
Tekill
1798

Hay varias formas de hacer lo que quieres. Para agregar a lo que ya dijeron @inalis y @Navi, puede usar el bbox_to_anchorargumento de la 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), intenta 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()

texto alternativo

Si hacemos lo mismo, pero usamos el bbox_to_anchorargumento de la 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()

texto alternativo

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 girando en las 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()

texto alternativo

Alternativamente, puede reducir el ancho del gráfico actual y colocar la leyenda completamente fuera del eje de la figura (nota: si usa tight_layout () , entonces omita ax.set_position ():

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

texto alternativo

Y de manera similar, puede reducir la trama verticalmente y colocar una 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()

texto alternativo

Echa un vistazo a la guía de leyenda matplotlib . También puedes echarle un vistazo plt.figlegend().

Joe Kington
fuente
10
Si alguien tiene problemas con esto, tenga en cuenta que tight_layout () causará problemas.
Matthew G.
44
¡gran respuesta! el enlace correcto al documento es matplotlib.org/users/legend_guide.html#legend-location
meduz
44
como completitud, se podría decir que en general (resumido del documento) " bbox_to_anchores una tupla de 4 flotadores (x, y, ancho, altura de la caja), o una tupla de 2 flotadores (x, y) en ejes normalizados coordenadas ".
Meduz
55
Debo admitir que esta es probablemente mi respuesta SO más visitada. Simplemente no puedo evitar volver una y otra vez porque no hay forma de que una persona razonable pueda recordar esta lógica sin buscarla aquí.
KT.
99
Tenga en cuenta que si desea guardar la figura en un archivo, probablemente debería almacenar el objeto devuelto, es decir, legend = ax.legend()y más tardefig.savefig(bbox_extra_artists=(legend,))
Coldfix
793

Colocando la leyenda ( bbox_to_anchor)

Se coloca una leyenda dentro del cuadro delimitador de los ejes utilizando el locargumento to plt.legend.
Por ejemplo, loc="upper right"coloca la leyenda en la esquina superior derecha del cuadro delimitador, que de forma predeterminada se extiende desde (0,0)hasta (1,1)en las coordenadas de los ejes (o en la notación del 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 coordenadas de 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 se debe colocar la leyenda, utilizando el bbox_to_anchorargumento. Uno puede restringirse para suministrar solo la (x0,y0)parte de bbox. Esto crea un cuadro de intervalo cero, fuera del cual la leyenda se expandirá en la dirección dada por el locargumento. P.ej

plt.legend (bbox_to_anchor = (1.04,1), loc = "arriba a la 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.

A continuación se dan más ejemplos, donde además se muestra la interacción entre diferentes argumentos como modey ncols.

ingrese la descripción de la imagen aquí

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

Los detalles sobre cómo interpretar el argumento de 4 tuplas bbox_to_anchor, como en l4, se pueden encontrar en esta pregunta . El mode="expand"expande la leyenda horizontalmente dentro del cuadro delimitador propuesta por el 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 l5de arriba, donde elbbox_transform 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á total o parcialmente fuera del lienzo de la figura.

Las soluciones a este problema son:

  • Ajuste los parámetros de la subtrama
    Uno puede ajustar los parámetros de la subtrama de tal manera que los ejes ocupen menos espacio dentro de la figura (y, por lo tanto, dejen más espacio para la leyenda) 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 puede colocar la leyenda.

  • Diseño ajustado
    Usando plt.tight_layoutPermite 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 proporcionar un cuadro rectangular en el que se ajustará toda el área de subtramas (incluidas las etiquetas).

    plt.tight_layout(rect=[0,0,0.75,1])
  • Guardar la figura conbbox_inches = "tight"
    El argumento bbox_inches = "tight"to plt.savefigse puede usar para guardar la figura de modo que todos los artistas en el 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")
  • ajuste automático de los parámetros de la subtrama
    En esta respuesta se puede encontrar una forma de ajustar automáticamente la posición de la subtrama de modo que la leyenda se ajuste dentro del lienzo sin cambiar el tamaño de la figura : Crear una figura con tamaño exacto y sin relleno (y leyenda fuera de los ejes)

Comparación entre los casos discutidos anteriormente:

ingrese la descripción de la imagen aquí

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 matplotlib versión> = 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 locargumento, similar a cómo se coloca dentro de los ejes, pero en referencia a la figura completa, por lo tanto, estará fuera de los ejes de forma algo automática. Lo que queda es ajustar las subtramas para que no haya superposición entre la leyenda y los ejes. Aquí será útil el punto "Ajustar los parámetros de la subtrama" desde arriba. 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()

ingrese la descripción de la imagen aquí

Leyenda dentro de ejes de subtrama dedicados
Una alternativa al uso bbox_to_anchorserí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 usarla gridspec_kw={"width_ratios":[4,1]}en la creación de ejes. Podemos ocultar los ejes lax.axis("off")pero todavía poner una leyenda en. Los tiradores de leyenda y etiquetas necesitan obtenida a partir de la trama real a través h,l = ax.get_legend_handles_labels(), y luego se puede suministrar a la leyenda en la laxtrama secundaria, 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 bastante similar a la trama de arriba:

ingrese la descripción de la imagen aquí

También podríamos usar los primeros ejes para colocar la leyenda, pero usar los bbox_transformejes 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 identificadores de leyenda externamente, pero necesitamos especificar el bbox_to_anchor argumento.

Lecturas adicionales y notas:

  • Considere la guía de la leyenda matplotlib con algunos ejemplos de otras cosas que desea hacer con las leyendas.
  • Algunos códigos de ejemplo 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
  • El locargumento puede tomar números en lugar de cadenas, lo que hace que las llamadas sean más cortas, sin embargo, no están muy intuitivamente asignadas entre sí. Aquí está el mapeo para referencia:

ingrese la descripción de la imagen aquí

Importancia de ser ernesto
fuente
Poner la leyenda en un eje de subtrama dedicado sinergias muy bien con fig.tight_layout. Si está utilizando plt.subplotspara crear los ejes, simplemente dele algo como gridspec_kw={'height_ratios': [100, 1]}(o width_ratios) para que los ejes de la leyenda sean pequeños ... Luego fig.tight_layout()lo expandirá para que se ajuste. Al menos para matplotlib 3.0.3.
travc
161

Simplemente llame legend()después de la plot()llamada así:

# matplotlib
plt.plot(...)
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))

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

Los resultados se verían así:

ingrese la descripción de la imagen aquí

Shital Shah
fuente
44
funciona al pasar los mismos parámetros a matplotlib.pyplot.legend también
kidmose
8
¿Esto corta las palabras en la leyenda para alguien más?
user1717828
85

Para colocar la leyenda fuera del área de trazado, use locy bbox_to_anchorpalabras clave de legend(). Por ejemplo, el siguiente código colocará la leyenda a la derecha del área de trazado:

legend(loc="upper left", bbox_to_anchor=(1,1))

Para obtener más información, consulte la guía de la leyenda.

Christian Alis
fuente
10
Bien, me gusta la implementación, pero cuando voy a guardar la figura (sin cambiar el tamaño manualmente en la ventana, lo que no quiero hacer siempre), la leyenda se corta. ¿Alguna idea sobre cómo podría solucionar eso?
astromax
@astromax No estoy seguro, ¿pero tal vez intente llamar plt.tight_layout()?
Christian Alis
81

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


Respuesta más larga: puede usar bbox_to_anchorpara 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')

ingrese la descripción de la imagen aquí

Para evitar que el cuadro de leyenda se recorte, cuando guarde la figura, puede usar los parámetros bbox_extra_artistsy bbox_inchessolicitar savefigincluir 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 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')

ingrese la descripción de la imagen aquí

Desearía que matplotlib permitiera nativamente la ubicación externa del cuadro de leyenda como lo hace Matlab :

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

ingrese la descripción de la imagen aquí

Franck Dernoncourt
fuente
66
Muchas gracias! Los parámetros "bbox_to_anchor", "bbox_extra_artist" y "" bbox_inches = 'tight "eran exactamente lo que necesitaba para que funcionara correctamente. ¡Impresionante!
Demitrian
66
Gracias, pero en realidad bbox_inches='tight'funciona perfectamente para mí, incluso sin bbox_extra_artist
avtomaton
1
@avtomaton Gracias, es bueno saber, ¿qué versión de matplotlib usas?
Franck Dernoncourt el
1
@FranckDernoncourt python3, matplotlib versión 1.5.3
avtomaton el
68

Además de todas las excelentes respuestas aquí, las versiones más nuevas de matplotliby pylabpueden determinar automáticamente dónde colocar la leyenda sin interferir con las tramas , si es posible.

pylab.legend(loc='best')

¡Esto alejará automáticamente la leyenda de los datos si es posible! Compare el uso de loc = 'best'

Sin embargo, si no hay lugar para colocar la leyenda sin superponer los datos, entonces querrá probar una de las otras respuestas; usar loc="best"nunca pondrá la leyenda fuera de la trama.

dotancohen
fuente
2
¡Gracias por señalar esto! Lo busqué hace unos años y no lo encontré, y es algo que realmente me hace la vida más fácil.
Edgar H
44
Esta opción es útil pero no responde la pregunta, así que voté en contra. Por lo que puedo decir, lo mejor es nunca poner la leyenda fuera de la trama
Tommy
3
@Tommy: En los comentarios del OP (que parece haberse ido ahora) se aclaró explícitamente que el OP quería que la leyenda no cubriera los datos del gráfico, y pensó que fuera de la trama era la única forma de hacerlo. Puedes ver esto en las respuestas de mefathy, Mateo Sanchez, Bastiaan y radtek. El PO pidió X, pero que quería Y .
dotancohen
1
En realidad no. Él / ella pidió específicamente que la leyenda esté fuera de la trama. Está en el nombre de la pregunta;) "Cómo sacar la leyenda de la trama".
Durbachit
44
Esto no garantiza que la leyenda no oculte los datos. Simplemente haga una trama muy densa: no hay lugar para poner la leyenda. Por ejemplo, intente esto ... desde numpy import arange, sin, pi import matplotlib.pyplot como plt t = arange (0.0, 100.0, 0.01) fig = plt.figure (1) ax1 = fig.add_subplot (211) ax1. scatter (t, sin (2 * pi * t), label = 'test') ax1.grid (True) # ax1.set_ylim ((- 2, 2)) ax1.set_ylabel ('1 Hz') ax1.set_title ( 'Una onda sinusoidal o dos') para la etiqueta en ax1.get_xticklabels (): label.set_color ('r') plt.legend (loc = 'best') plt.show ()
adam.r
56

Respuesta corta : invoque arrastrable en la leyenda y muévala interactivamente donde desee:

ax.legend().draggable()

Respuesta larga : si prefiere colocar la leyenda de forma interactiva / manual en lugar de mediante programación, puede alternar el modo arrastrable de la leyenda para poder arrastrarla a donde desee. Verifique el siguiente ejemplo:

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()
mefathy
fuente
No estoy seguro de entender esto completamente. ¿Cómo puedo "arrastrar" la leyenda a donde quiera con esto? Estoy usando Python 3.6 y Jupyter Notebook
sb2020
14

No es exactamente lo que pediste, pero descubrí que es una alternativa para el mismo problema. Haga que la leyenda sea semi-transparente, así: diagrama de matplotlib con leyenda semitransparente y cuadro de texto semitransparente

Haz esto con:

fig = pylab.figure()
ax = fig.add_subplot(111)
ax.plot(x,y,label=label,color=color)
# Make the legend transparent:
ax.legend(loc=2,fontsize=10,fancybox=True).get_frame().set_alpha(0.5)
# Make a transparent text box
ax.text(0.02,0.02,yourstring, verticalalignment='bottom',
                     horizontalalignment='left',
                     fontsize=10,
                     bbox={'facecolor':'white', 'alpha':0.6, 'pad':10},
                     transform=self.ax.transAxes)
Bastiaan
fuente
8

Como se señaló, también puede colocar la leyenda en la trama, o ligeramente fuera del borde también. Aquí hay un ejemplo usando la API Plotly Python , hecha con un IPython Notebook . Estoy en el equipo

Para comenzar, querrás instalar los paquetes necesarios:

import plotly
import math
import random
import numpy as np

Luego, instale Plotly:

un='IPython.Demo'
k='1fw3zw2o13'
py = plotly.plotly(username=un, key=k)


def sin(x,n):
sine = 0
for i in range(n):
    sign = (-1)**i
    sine = sine + ((x**(2.0*i+1))/math.factorial(2*i+1))*sign
return sine

x = np.arange(-12,12,0.1)

anno = {
'text': '$\\sum_{k=0}^{\\infty} \\frac {(-1)^k x^{1+2k}}{(1 + 2k)!}$',
'x': 0.3, 'y': 0.6,'xref': "paper", 'yref': "paper",'showarrow': False,
'font':{'size':24}
}

l = {
'annotations': [anno], 
'title': 'Taylor series of sine',
'xaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
'yaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
'legend':{'font':{'size':16},'bordercolor':'white','bgcolor':'#fcfcfc'}
}

py.iplot([{'x':x, 'y':sin(x,1), 'line':{'color':'#e377c2'}, 'name':'$x\\\\$'},\
      {'x':x, 'y':sin(x,2), 'line':{'color':'#7f7f7f'},'name':'$ x-\\frac{x^3}{6}$'},\
      {'x':x, 'y':sin(x,3), 'line':{'color':'#bcbd22'},'name':'$ x-\\frac{x^3}{6}+\\frac{x^5}{120}$'},\
      {'x':x, 'y':sin(x,4), 'line':{'color':'#17becf'},'name':'$ x-\\frac{x^5}{120}$'}], layout=l)

Esto crea su gráfico y le permite tener la leyenda dentro de la trama. El valor predeterminado de la leyenda si no está configurado es colocarlo en el diagrama, como se muestra aquí.

ingrese la descripción de la imagen aquí

Para una ubicación alternativa, puede alinear estrechamente el borde del gráfico y el borde de la leyenda, y eliminar las líneas de borde para un ajuste más cercano.

ingrese la descripción de la imagen aquí

Puede mover y cambiar el estilo de la leyenda y el gráfico con código o con la GUI. Para cambiar la leyenda, tiene las siguientes opciones para colocar la leyenda dentro del gráfico asignando valores x e y de <= 1. Por ejemplo:

  • {"x" : 0,"y" : 0} - Abajo a la izquierda
  • {"x" : 1, "y" : 0} -- Abajo a la derecha
  • {"x" : 1, "y" : 1} -- Parte superior derecha
  • {"x" : 0, "y" : 1} -- Arriba a la izquierda
  • {"x" :.5, "y" : 0} -- Parte inferior central
  • {"x": .5, "y" : 1} -- Centro Superior

En este caso, elegimos la esquina superior derecha legendstyle = {"x" : 1, "y" : 1}, también descrita en la documentación :

ingrese la descripción de la imagen aquí

Mateo Sanchez
fuente
3

Algo en este sentido me funcionó. Comenzando con un poco de código tomado de Joe, este método modifica el ancho de la ventana para que se ajuste automáticamente a una leyenda a la derecha de la figura.

import matplotlib.pyplot as plt
import numpy as np

plt.ion()

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)

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

plt.draw()

# Get the ax dimensions.
box = ax.get_position()
xlocs = (box.x0,box.x1)
ylocs = (box.y0,box.y1)

# Get the figure size in inches and the dpi.
w, h = fig.get_size_inches()
dpi = fig.get_dpi()

# Get the legend size, calculate new window width and change the figure size.
legWidth = leg.get_window_extent().width
winWidthNew = w*dpi+legWidth
fig.set_size_inches(winWidthNew/dpi,h)

# Adjust the window size to fit the figure.
mgr = plt.get_current_fig_manager()
mgr.window.wm_geometry("%ix%i"%(winWidthNew,mgr.window.winfo_height()))

# Rescale the ax to keep its original size.
factor = w*dpi/winWidthNew
x0 = xlocs[0]*factor
x1 = xlocs[1]*factor
width = box.width*factor
ax.set_position([x0,ylocs[0],x1-x0,ylocs[1]-ylocs[0]])

plt.draw()
Martín
fuente
Encontré esto bastante útil y funcionó para mí. Tenga en cuenta que si está en el backend de wx (por ejemplo, usando Windows), reemplace mgr.window.wm_geometry ("% ix% i"% (winWidthNew, mgr.window.winfo_height ())) con mgr.window.SetClientSizeWH (winWidthNew , winHeightNew) o similar
Ezekiel Kruglick
Si está utilizando el backend Qt4Agg (que es el predeterminado en mi instalación Linux de matplotlib), reemplace la línea mgr.window.wm_geometry(...)con mgr.window.setFixedWidth(winWidthNew).
Filip S.
Y, como acabo de descubrir, si está utilizando un backend que no muestra ninguna ventana, destinado a guardar directamente en un archivo (como los backends SVG y AGG), simplemente omita el cambio de tamaño de la ventana por completo. fig.set_size_inches(...)se encarga del cambio de tamaño que necesita.
Filip S.
3

Vale la pena actualizar esta pregunta, ya que las versiones más nuevas de Matplotlib han hecho que sea mucho más fácil colocar la leyenda fuera de la trama. Produje este ejemplo con la versión Matplotlib 3.1.1.

Los usuarios pueden pasar 2 tuplas de coordenadas al locparámetro para colocar la leyenda en cualquier lugar del cuadro delimitador. El único problema es que debe ejecutar plt.tight_layout()para obtener matplotlib para volver a calcular las dimensiones de la trama para que la leyenda sea visible:

import matplotlib.pyplot as plt

plt.plot([0, 1], [0, 1], label="Label 1")
plt.plot([0, 1], [0, 2], label='Label 2')

plt.legend(loc=(1.05, 0.5))
plt.tight_layout()

Esto lleva a la siguiente trama:

trama con leyenda afuera

Referencias

luc
fuente
2

También puedes intentarlo figlegend. Es posible crear una leyenda independiente de cualquier objeto Axes. Sin embargo, es posible que deba crear algunas rutas "ficticias" para asegurarse de que el formato de los objetos se transmite correctamente.

Uri Laserson
fuente
1

Aquí hay un ejemplo del tutorial matplotlib que se encuentra aquí . Este es uno de los ejemplos más simples, pero agregué transparencia a la leyenda y agregué plt.show () para que pueda pegar esto en el shell interactivo y obtener un resultado:

import matplotlib.pyplot as plt
p1, = plt.plot([1, 2, 3])
p2, = plt.plot([3, 2, 1])
p3, = plt.plot([2, 3, 1])
plt.legend([p2, p1, p3], ["line 1", "line 2", "line 3"]).get_frame().set_alpha(0.5)
plt.show()
radtek
fuente
1

La solución que funcionó para mí cuando tenía una gran leyenda era usar un diseño de imagen vacío adicional. En el siguiente ejemplo hice 4 filas y en la parte inferior trazo una imagen con desplazamiento para la leyenda (bbox_to_anchor) en la parte superior, no se corta.

f = plt.figure()
ax = f.add_subplot(414)
lgd = ax.legend(loc='upper left', bbox_to_anchor=(0, 4), mode="expand", borderaxespad=0.3)
ax.autoscale_view()
plt.savefig(fig_name, format='svg', dpi=1200, bbox_extra_artists=(lgd,), bbox_inches='tight')
Cristal
fuente
1

Aquí hay otra solución, similar a agregar bbox_extra_artistsy bbox_inches, donde no tiene que tener sus artistas adicionales en el alcance de susavefig llamada. Se me ocurrió esto ya que genero la mayor parte de mi trama dentro de las funciones.

En lugar de agregar todas sus adiciones al cuadro delimitador cuando desee escribirlas, puede agregarlas con anticipación a los Figureartistas de. Usando algo similar a la respuesta de Franck Dernoncourt anterior :

import matplotlib.pyplot as plt

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

# plotting function
def gen_plot(x, y):
    fig = plt.figure(1)
    ax = fig.add_subplot(111)
    ax.plot(all_x, all_y)
    lgd = ax.legend( [ "Lag " + str(lag) for lag in all_x], loc="center right", bbox_to_anchor=(1.3, 0.5))
    fig.artists.append(lgd) # Here's the change
    ax.set_title("Title")
    ax.set_xlabel("x label")
    ax.set_ylabel("y label")
    return fig

# plotting
fig = gen_plot(all_x, all_y)

# No need for `bbox_extra_artists`
fig.savefig("image_output.png", dpi=300, format="png", bbox_inches="tight")

Aquí está la trama generada.

ivirshup
fuente
-1

no sé si ya resolvió su problema ... probablemente sí, pero ... simplemente usé la cadena 'afuera' para la ubicación, como en matlab. Importé pylab de matplotlib. ver el código de la siguiente manera:

from matplotlib as plt
from matplotlib.font_manager import FontProperties
...
...
t = A[:,0]
sensors = A[:,index_lst]

for i in range(sensors.shape[1]):
    plt.plot(t,sensors[:,i])

plt.xlabel('s')
plt.ylabel('°C')
lgd = plt.legend(b,loc='center left', bbox_to_anchor=(1, 0.5),fancybox = True, shadow = True)

Haga clic para ver la trama

Ziuccia
fuente