Como colocar a lenda fora da trama

988

Eu tenho uma série de 20 gráficos (não sub-gráficos) a serem feitos em uma única figura. Eu quero que a lenda esteja fora da caixa. Ao mesmo tempo, não quero alterar os eixos, pois o tamanho da figura é reduzido. Por favor, me ajude para as seguintes perguntas:

  1. Quero manter a caixa de legenda fora da área de plotagem. (Eu quero que a legenda esteja do lado de fora do lado direito da área da plotagem).
  2. Existe alguma maneira de reduzir o tamanho da fonte do texto dentro da caixa de legenda, para que o tamanho da caixa de legenda seja pequeno.
pottigopi
fonte
14
Para versões mais recentes do matplotlib, esta resposta mostra como configurar o matplotlib para determinar automaticamente onde colocar a legenda sem interferir nas plotagens .
dotancohen
2
Teve a mesma pergunta e encontrei este grande exemplo que funcionou para mim "fora da caixa": matplotlib.org/1.3.1/users/legend_guide.html
robodasha
1
Essa resposta tem mais profundidade https://stackoverflow.com/a/43439132/52074. e faz isso com duas linhas de código! a resposta +1200 upvoted também é boa, mas eu achei que era menos genérico.
Trevor Boyd Smith
2
@dotancohen "determina automaticamente onde colocar a legenda sem interferir nas plotagens" Em certos casos, quando a plotagem tem muitas curvas, infelizmente é impossível. Nesses casos, o usuário pode querer colocar manualmente a legenda e colocá-la fora da área de plotagem. Estou tendo dificuldades com essa trama agora.
Ali
btw, a lista de opções de loc: best; canto superior direito; superior esquerdo; canto inferior esquerdo; inferior direito; direita; centro esquerdo; centro direito; centro inferior; centro superior; Centro;
Z-Y00 8/11/19

Respostas:

57

Você pode diminuir o texto da legenda criando propriedades de fonte:

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
fonte
50
o que há plot1nesta resposta?
Paul H
41
o que há legendnesta resposta?
24418 Richard
28
Isso responde à parte secundária da pergunta, mas não à primária (a que é intitulada).
Mateen Ulhaq
8
Além disso, a maneira correta de fazer isso éplt.legend(fontsize='small')
Mateen Ulhaq
41
Esta resposta é terrível e fornece muito pouco contexto!
Tekill 17/04/19
1797

Existem várias maneiras de fazer o que você deseja. Para adicionar o que @inalis e @Navi já disseram, você pode usar o bbox_to_anchorargumento keyword para colocar a legenda parcialmente fora dos eixos e / ou diminuir o tamanho da fonte.

Antes de considerar diminuir o tamanho da fonte (o que pode dificultar bastante a leitura), tente colocar a legenda em locais diferentes:

Então, vamos começar com um exemplo 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

Se fizermos a mesma coisa, mas usarmos o bbox_to_anchorargumento de palavra - chave, podemos deslocar a legenda ligeiramente fora dos limites dos eixos:

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

Da mesma forma, você pode tornar a legenda mais horizontal e / ou colocá-la no topo da figura (também estou ativando cantos arredondados e uma simples sombra):

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

Como alternativa, você pode reduzir a largura do gráfico atual e colocar a legenda completamente fora do eixo da figura (nota: se você usar tight_layout () , deixe de fora 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

E de maneira semelhante, você pode reduzir o gráfico verticalmente e colocar a legenda a horizontal na 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

Dê uma olhada no guia de legendas do matplotlib . Você também pode dar uma olhada plt.figlegend().

Joe Kington
fonte
10
Se alguém tiver problemas com isso, observe que tight_layout () causará problemas!
Matthew G.
4
Ótima resposta! o link correto para o doc é matplotlib.org/users/legend_guide.html#legend-location
meduz
4
como completude, você poderia dizer que, em geral (resumido no documento) " bbox_to_anchoré uma tupla de 4 flutuadores (x, y, largura, altura da bbox) ou uma tupla de 2 flutuadores (x, y) em eixos normalizados coordenadas. "
meduz 23/10
5
Devo admitir que esta é provavelmente a minha resposta mais visitada de todos os tempos. Eu simplesmente não posso deixar de voltar a repetir isso porque não há como uma pessoa razoável se lembrar dessa lógica sem procurá-la aqui.
KT.
9
Observe que se você deseja salvar a figura em um arquivo, provavelmente deve armazenar o objeto retornado, ou seja, legend = ax.legend()mais tardefig.savefig(bbox_extra_artists=(legend,))
coldfix
792

Colocando a legenda ( bbox_to_anchor)

Uma legenda é posicionada dentro da caixa delimitadora dos eixos usando o locargumento para plt.legend.
Por exemplo, loc="upper right"coloca a legenda no canto superior direito da caixa delimitadora, que por padrão se estende de (0,0)para (1,1)nas coordenadas dos eixos (ou na notação da caixa delimitadora (x0,y0, width, height)=(0,0,1,1)).

Para colocar a legenda fora da caixa delimitadora dos eixos, pode-se especificar uma tupla (x0,y0)de coordenadas dos eixos no canto inferior esquerdo da legenda.

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

No entanto, uma abordagem mais versátil seria especificar manualmente a caixa delimitadora na qual a legenda deve ser colocada, usando o bbox_to_anchorargumento Pode-se restringir-se a fornecer apenas a (x0,y0)parte da bbox. Isso cria uma caixa de amplitude zero, da qual a legenda será expandida na direção fornecida pelo locargumento. Por exemplo

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

coloca a legenda fora dos eixos, de modo que o canto superior esquerdo da legenda esteja na posição (1.04,1)nas coordenadas dos eixos.

Outros exemplos são dados abaixo, onde, adicionalmente, a interacção entre diferentes argumentos semelhantes modee ncolssão mostrados.

insira a descrição da imagem aqui

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

Detalhes sobre como interpretar o argumento de 4 tuplas bbox_to_anchor, como em l4, podem ser encontrados nesta pergunta . O mode="expand"expande a legenda horizontalmente dentro da caixa delimitadora fornecida pela 4-tupla. Para uma legenda verticalmente expandida, consulte esta pergunta .

Às vezes, pode ser útil especificar a caixa delimitadora nas coordenadas da figura em vez das coordenadas dos eixos. Isso é mostrado no exemplo l5acima, onde o bbox_transformargumento é usado para colocar a legenda no canto inferior esquerdo da figura.

Pós-processamento

Colocar a legenda fora dos eixos geralmente leva à situação indesejada de que está completamente ou parcialmente fora da tela da figura.

As soluções para esse problema são:

  • Ajustar os parâmetros da subparcela
    É possível ajustar os parâmetros da subparcela, para que os eixos ocupem menos espaço dentro da figura (e, portanto, deixem mais espaço para a legenda) usando plt.subplots_adjust. Por exemplo

    plt.subplots_adjust(right=0.7)

    deixa 30% de espaço no lado direito da figura, onde se pode colocar a legenda.

  • Layout apertado
    Usando plt.tight_layoutPermite ajustar automaticamente os parâmetros da subparcela, de modo que os elementos da figura fiquem firmes nas bordas da figura. Infelizmente, a legenda não é levada em consideração nesse automatismo, mas podemos fornecer uma caixa retangular na qual toda a área de subtrama (incluindo etiquetas) se encaixará.

    plt.tight_layout(rect=[0,0,0.75,1])
  • Salvando a figura combbox_inches = "tight"
    O argumento bbox_inches = "tight"to plt.savefigpode ser usado para salvar a figura, de modo que todos os artistas na tela (incluindo a legenda) se encaixem na área salva. Se necessário, o tamanho da figura é ajustado automaticamente.

    plt.savefig("output.png", bbox_inches="tight")
  • ajuste automático dos parâmetros de subparcela
    Uma maneira de ajustar automaticamente a posição da subparcela de forma que a legenda caiba dentro da tela sem alterar o tamanho da figura pode ser encontrada nesta resposta: Criando figura com tamanho exato e sem preenchimento (e legenda fora dos eixos)

Comparação entre os casos discutidos acima:

insira a descrição da imagem aqui

Alternativas

Uma legenda da figura
Pode-se usar uma legenda para a figura em vez dos eixos matplotlib.figure.Figure.legend,. Isso se tornou especialmente útil para a versão matplotlib> = 2.1, onde nenhum argumento especial é necessário

fig.legend(loc=7) 

para criar uma legenda para todos os artistas nos diferentes eixos da figura. A legenda é colocada usando o locargumento, semelhante à maneira como é colocada dentro de um eixo, mas em referência a toda a figura - portanto, ela estará fora dos eixos um pouco automaticamente. O que resta é ajustar as subparcelas para que não haja sobreposição entre a legenda e os eixos. Aqui, o ponto "Ajustar os parâmetros da subparcela" acima será útil. Um exemplo:

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

insira a descrição da imagem aqui

Legenda dentro dos eixos de subparcela dedicados
Uma alternativa ao uso bbox_to_anchorseria colocar a legenda em seus eixos de subparcela dedicados ( lax). Como a subparcela da legenda deve ser menor que a plotagem, podemos usar gridspec_kw={"width_ratios":[4,1]}na criação dos eixos. Podemos ocultar os eixos, lax.axis("off")mas ainda assim inserir uma legenda. Os identificadores e etiquetas da legenda precisam ser obtidos da plotagem real via h,l = ax.get_legend_handles_labels()e, em seguida, podem ser fornecidos à legenda na laxsubparcela lax.legend(h,l),. Um exemplo completo está abaixo.

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

Isso produz um gráfico visualmente bastante semelhante ao gráfico acima:

insira a descrição da imagem aqui

Também podemos usar os primeiros eixos para colocar a legenda, mas usar os bbox_transformeixos da legenda,

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

Nesta abordagem, não precisamos obter os identificadores de legenda externamente, mas precisamos especificar o bbox_to_anchorargumento.

Outras leituras e notas:

  • Considere o guia de legendas do matplotlib com alguns exemplos de outras coisas que você deseja fazer com as lendas.
  • Algum código de exemplo para colocar legendas para gráficos de pizza pode ser encontrado diretamente na resposta a esta pergunta: Python - Legenda se sobrepõe ao gráfico de pizza
  • O locargumento pode usar números em vez de strings, o que torna as chamadas mais curtas, no entanto, elas não são mapeadas de maneira muito intuitiva. Aqui está o mapeamento para referência:

insira a descrição da imagem aqui

ImportanceOfBeingErnest
fonte
Colocar a legenda em um eixo de subtrama dedicado sinergias muito bem com fig.tight_layout. Se você estiver usando plt.subplotspara criar os eixos, dê a ele algo como gridspec_kw={'height_ratios': [100, 1]}(ou width_ratios) para que os eixos da legenda sejam pequenos ... Em seguida fig.tight_layout(), ele será expandido para caber. Pelo menos para o matplotlib 3.0.3.
travc
161

Basta ligar para a legend()chamada após a plot()chamada da seguinte maneira:

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

Os resultados seriam algo assim:

insira a descrição da imagem aqui

Shital Shah
fonte
4
funciona quando passar os mesmos parâmetros para matplotlib.pyplot.legend bem
kidmose
8
Isso corta as palavras da legenda para mais alguém?
precisa saber é o seguinte
85

Para colocar a legenda fora da área de plotagem, use loce bbox_to_anchorpalavras - chave de legend(). Por exemplo, o código a seguir colocará a legenda à direita da área de plotagem:

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

Para mais informações, consulte o guia da legenda

Christian Alis
fonte
10
Ok - eu gosto da implementação, mas quando vou salvar a figura (sem redimensioná-la manualmente na janela, o que não quero fazer sempre), a lenda está sendo cortada. Alguma idéia de como eu posso consertar isso?
Astromax
@astromax Não tenho certeza, mas talvez tente ligar plt.tight_layout()?
Christian Alis
81

Resposta curta: você pode usar bbox_to_anchor+ bbox_extra_artists+ bbox_inches='tight'.


Resposta mais longa: você pode usar bbox_to_anchorpara especificar manualmente o local da caixa da legenda, como algumas pessoas apontaram nas respostas.

No entanto, o problema usual é que a caixa de legenda é cortada, por exemplo:

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

insira a descrição da imagem aqui

Para impedir que a caixa de legenda seja cortada, ao salvar a figura, você pode usar os parâmetros bbox_extra_artistse bbox_inchessolicitar savefiga inclusão de elementos cortados na imagem salva:

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

Exemplo (apenas alterei a última linha para adicionar 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')

insira a descrição da imagem aqui

Desejo que o matplotlib permita nativamente um local externo para a caixa de legenda, como o 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])

insira a descrição da imagem aqui

Franck Dernoncourt
fonte
6
Muito obrigado! O "bbox_to_anchor", "bbox_extra_artist" e "" bbox_inches = 'apertado" parâmetros eram exatamente o que eu precisava para fazer o trabalho corretamente impressionante.!
Demitrian
6
Obrigado, mas realmente bbox_inches='tight'funciona perfeitamente para mim mesmo sem bbox_extra_artist
avtomaton
1
@avtomaton Obrigado, bom saber, qual versão do matplotlib você usa?
Franck Dernoncourt 8/16
1
@FranckDernoncourt python3, matplotlib versão 1.5.3
avtomaton
68

Além de todas as excelentes respostas aqui, as versões mais recentes matplotlibe pylabpodem determinar automaticamente onde colocar a legenda sem interferir nas plotagens , se possível.

pylab.legend(loc='best')

Isso colocará automaticamente a legenda longe dos dados, se possível! Compare o uso de loc = 'best'

No entanto, se não houver lugar para colocar a legenda sem sobrepor os dados, tente uma das outras respostas; o uso loc="best"nunca colocará a legenda fora da trama.

dotancohen
fonte
2
Obrigado por apontar isto! Procurei por isso há alguns anos e não a encontrei, e é algo que realmente facilita minha vida.
Edgar H
4
essa opção é útil, mas não responde à pergunta, então eu votei com menos votos. tanto quanto eu posso dizer, melhor não coloca a legenda fora da trama
Tommy
3
@ Tommy: Nos comentários do OP (que parece ter desaparecido agora), foi explicitamente esclarecido que o OP queria que a lenda não cobrisse os dados do gráfico, e ele pensou que fora da trama era a única maneira de fazer isso. Você pode ver isso nas respostas de mefathy, Mateo Sanchez, Bastiaan e radtek. O OP pediu X, mas ele queria Y .
dotancohen 9/09/15
1
Na verdade não. Ele / ela pediu especificamente que a lenda estivesse fora da trama. Está no nome da pergunta;) "Como colocar a lenda fora da trama".
durbachit
4
Isso não garante que a legenda não oculte os dados. Basta fazer um enredo muito denso - não há lugar para colocar a lenda. Por exemplo, tente isso ... de 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. No entanto, se você está procurando por uma solução que possa ser útil para o seu projeto, é importante que você faça o seguinte: x1.grid (True) # ax1.set_ylim ((- 2, 2)) ax1.set_ylabel ('1 Hz') ax1.set_title ( 'Uma onda senoidal ou duas') para o rótulo em ax1.get_xticklabels (): label.set_color ('r') plt.legend (loc = 'best') plt.show ()
adam.r
56

Resposta curta : chame a legível arrastável e mova-a de forma interativa para onde desejar:

ax.legend().draggable()

Resposta longa : Se preferir colocar a legenda de maneira interativa / manual, em vez de programaticamente, você pode alternar o modo arrastável da legenda para poder arrastá-la para onde quiser. Veja o exemplo abaixo:

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
fonte
Não tenho certeza se entendi isso completamente. Como "arrasto" a legenda para onde eu quiser com isso? Eu estou usando Python 3.6 e Jupyter Notebook
sb2020
14

Não é exatamente o que você pediu, mas eu achei uma alternativa para o mesmo problema. Torne a legenda semi-transparente, da seguinte forma: plotagem matplotlib com legenda semi-transparente e caixa de texto semitransparente

Faça isso com:

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
fonte
8

Como observado, você também pode colocar a legenda na plotagem, ou um pouco fora dela também. Aqui está um exemplo usando a API Plotly Python , feita com um notebook IPython . Eu estou no time.

Para começar, você desejará instalar os pacotes necessários:

import plotly
import math
import random
import numpy as np

Em seguida, instale o 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)

Isso cria seu gráfico e permite que você mantenha a legenda dentro da própria plotagem. O padrão para a legenda, se não estiver definida, é colocá-la na plotagem, conforme mostrado aqui.

insira a descrição da imagem aqui

Para um posicionamento alternativo, você pode alinhar estreitamente a borda do gráfico e a borda da legenda e remover as linhas da borda para um ajuste mais próximo.

insira a descrição da imagem aqui

Você pode mover e refazer o estilo da legenda e do gráfico com código ou com a GUI. Para mudar a legenda, você tem as seguintes opções para posicionar a legenda dentro do gráfico, atribuindo valores x e y de <= 1. Por exemplo:

  • {"x" : 0,"y" : 0} -- Inferior esquerdo
  • {"x" : 1, "y" : 0} -- Canto inferior direito
  • {"x" : 1, "y" : 1} -- Canto superior direito
  • {"x" : 0, "y" : 1} - Superior esquerdo
  • {"x" :.5, "y" : 0} - Centro inferior
  • {"x": .5, "y" : 1} - Centro superior

Nesse caso, escolhemos o canto superior direito legendstyle = {"x" : 1, "y" : 1}, também descrito na documentação :

insira a descrição da imagem aqui

Mateo Sanchez
fonte
3

Algo nesse sentido funcionou para mim. Começando com um pouco de código retirado de Joe, esse método modifica a largura da janela para ajustar automaticamente uma legenda à direita da 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()
Martin
fonte
Achei isso bastante útil e funcionou para mim. Observe que se você estiver no back-end wx (por exemplo, usando o Windows), substitua mgr.window.wm_geometry ("% ix% i"% (winWidthNew, mgr.window.winfo_height ())) por mgr.window.SetClientSizeWH (winWidthNew , winHeightNew) ou algo semelhante #
Ezekiel Kruglick
Se você estiver usando o back-end Qt4Agg (que é o padrão na minha instalação Linux do matplotlib), substitua a linha mgr.window.wm_geometry(...)por mgr.window.setFixedWidth(winWidthNew).
Filip S.
E, como acabei de descobrir, se você estiver usando um back-end que não mostra nenhuma janela, destinado a salvar diretamente em um arquivo (como os back-ends SVG e AGG), basta pular o redimensionamento da janela. fig.set_size_inches(...)cuida do redimensionamento que você precisa.
Filip S.
3

Vale a pena atualizar essa pergunta, pois as versões mais recentes do Matplotlib tornaram muito mais fácil posicionar a legenda fora da trama. Eu produzi este exemplo com a versão Matplotlib 3.1.1.

Os usuários podem passar duas tuplas de coordenadas para o locparâmetro para posicionar a legenda em qualquer lugar da caixa delimitadora. O único problema é que você precisa executar plt.tight_layout()para que o matplotlib recompute as dimensões da plotagem para que a legenda fique visível:

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

Isso leva ao seguinte gráfico:

enredo com lenda fora

Referências:

luc
fonte
2

Você também pode tentar figlegend. É possível criar uma legenda independente de qualquer objeto Axes. No entanto, pode ser necessário criar alguns caminhos "fictícios" para garantir que a formatação dos objetos seja transmitida corretamente.

Uri Laserson
fonte
1

Aqui está um exemplo do tutorial matplotlib encontrado aqui . Este é um dos exemplos mais simples, mas adicionei transparência à legenda e adicionei plt.show () para que você possa colar isso no shell interativo e obter um 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
fonte
1

A solução que funcionou para mim quando eu tinha uma lenda enorme foi usar um layout de imagem extra vazio. No exemplo a seguir, criei 4 linhas e na parte inferior plotei a imagem com deslocamento para legenda (bbox_to_anchor) na parte superior, não é cortada.

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
fonte
1

Aqui está outra solução, semelhante à adição bbox_extra_artistse bbox_inches, na qual você não precisa ter artistas extras no escopo de sua savefigligação. Eu vim com isso desde que eu gere a maior parte do meu enredo dentro de funções.

Em vez de adicionar todas as suas adições à caixa delimitadora quando quiser escrevê-las, você poderá adicioná-las antecipadamente aos Figureartistas do artista. Usando algo semelhante à resposta de Franck Dernoncourt acima :

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

Aqui está o gráfico gerado.

ivirshup
fonte
-1

não sei se você já resolveu o problema ... provavelmente sim, mas ... simplesmente usei a string 'outside' para o local, como no matlab. Importei o pylab do matplotlib. veja o código da seguinte maneira:

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)

Clique para ver a trama

Ziuccia
fonte