Comment sortir la légende de l'intrigue

988

J'ai une série de 20 parcelles (pas de sous-parcelles) à faire en une seule figure. Je veux que la légende soit en dehors de la boîte. En même temps, je ne veux pas changer les axes, car la taille de la figure se réduit. Veuillez m'aider pour les requêtes suivantes:

  1. Je souhaite conserver la zone de légende en dehors de la zone de traçage. (Je veux que la légende soit à l'extérieur sur le côté droit de la zone de traçage).
  2. Existe-t-il de toute façon que je réduise la taille de la police du texte à l'intérieur de la zone de légende, de sorte que la taille de la zone de légende soit petite.
pottigopi
la source
14
Pour les versions plus récentes de matplotlib, cette réponse montre comment définir matplotlib pour déterminer automatiquement où placer la légende sans interférer avec les tracés .
dotancohen
2
A eu la même question et a trouvé ce grand exemple qui a fonctionné pour moi "hors de la boîte": matplotlib.org/1.3.1/users/legend_guide.html
robodasha
1
Cette réponse a plus de profondeur https://stackoverflow.com/a/43439132/52074. et le fait avec deux lignes de code! la réponse votée +1200 est également bonne mais je l'ai trouvée moins générique.
Trevor Boyd Smith
2
@dotancohen "détermine automatiquement où placer la légende sans interférer avec les tracés" Dans certains cas, lorsque l'intrigue a beaucoup de courbes, c'est malheureusement impossible. Dans ces cas, l'utilisateur peut vouloir placer manuellement la légende, et en fait la mettre en dehors de la zone de traçage. J'ai des difficultés avec un tel complot en ce moment.
Ali
btw, la liste des choix de loc: best; En haut à droite; en haut à gauche; en bas à gauche; en bas à droite; droite; centre gauche; au centre à droite; centre inférieur; centre supérieur; centre;
Z-Y00

Réponses:

57

Vous pouvez réduire le texte de la légende en créant des propriétés de police:

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
la source
50
que plot1contient cette réponse?
Paul H
41
que legendcontient cette réponse?
Richard
28
Cela répond à la partie secondaire de la question, mais pas à la principale (celle qui est intitulée).
Mateen Ulhaq
8
En outre, la bonne façon de le faire estplt.legend(fontsize='small')
Mateen Ulhaq
41
Cette réponse est terrible et fournit très peu de contexte!
Tekill
1799

Il existe plusieurs façons de faire ce que vous voulez. Pour ajouter à ce que @inalis et @Navi ont déjà dit, vous pouvez utiliser l' bbox_to_anchorargument mot - clé pour placer la légende partiellement en dehors des axes et / ou diminuer la taille de la police.

Avant d'envisager de réduire la taille de la police (ce qui peut rendre les choses extrêmement difficiles à lire), essayez de jouer avec le placement de la légende à différents endroits:

Commençons donc par un exemple générique:

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

texte alternatif

Si nous faisons la même chose, mais en utilisant l' bbox_to_anchorargument mot - clé, nous pouvons déplacer la légende légèrement en dehors des limites des axes:

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

texte alternatif

De même, vous pouvez rendre la légende plus horizontale et / ou la placer en haut de la figure (j'allume également des coins arrondis et une simple ombre portée):

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

texte alternatif

Vous pouvez également réduire la largeur du tracé actuel et placer la légende entièrement en dehors de l'axe de la figure (remarque: si vous utilisez tight_layout () , puis omettez 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()

texte alternatif

Et de la même manière, vous pouvez réduire l'intrigue verticalement et mettre la légende horizontale en bas:

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

texte alternatif

Jetez un œil au guide de légende de matplotlib . Vous pouvez également consulterplt.figlegend() .

Joe Kington
la source
10
Si quelqu'un a des problèmes avec cela, notez que tight_layout () causera des problèmes!
Matthew G.19
4
très bonne réponse! le lien correct vers le doc est matplotlib.org/users/legend_guide.html#legend-location
meduz
4
comme exhaustivité, on pourrait dire qu'en général (résumé du doc) " bbox_to_anchorest un tuple de 4 flotteurs (x, y, largeur, hauteur de la bbox), ou un tuple de 2 flotteurs (x, y) dans des axes normalisés coordonnées. "
meduz
5
Je dois admettre que c'est probablement ma réponse SO la plus visitée jamais. Je ne peux pas m'empêcher d'y revenir encore et encore parce qu'il n'y a aucun moyen qu'une personne raisonnable puisse se souvenir de cette logique sans la chercher ici.
KT.
9
Notez que si vous souhaitez enregistrer la figure dans un fichier, vous devez probablement stocker l'objet retourné, c'est legend = ax.legend()-à- dire et plus tardfig.savefig(bbox_extra_artists=(legend,))
coldfix
794

Placer la légende (bbox_to_anchor )

Une légende est positionnée à l'intérieur du cadre de sélection des axes à l'aide de l' locargument to plt.legend.
Par exemple, loc="upper right"place la légende dans le coin supérieur droit du cadre de sélection, qui s'étend par défaut de (0,0)à (1,1)en coordonnées d'axe (ou en notation de cadre de sélection(x0,y0, width, height)=(0,0,1,1) ).

Pour placer la légende en dehors du cadre de délimitation des axes, on peut spécifier un tuple (x0,y0)de coordonnées d'axes du coin inférieur gauche de la légende.

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

Cependant, une approche plus polyvalente serait de spécifier manuellement la boîte englobante dans laquelle la légende doit être placée, en utilisant l' bbox_to_anchorargument. On peut se limiter à ne fournir que la (x0,y0)partie de la bbox. Cela crée une zone de portée nulle, à partir de laquelle la légende s'étendra dans la direction donnée par l' locargument. Par exemple

plt.legend (bbox_to_anchor = (1.04,1), loc = "en haut à gauche")

place la légende en dehors des axes, de sorte que le coin supérieur gauche de la légende se trouve en position des (1.04,1)coordonnées des axes.

D'autres exemples sont donnés ci-dessous, où en plus l'interaction entre différents arguments comme modeet ncolsest montrée.

entrez la description de l'image ici

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

Les détails sur la façon d'interpréter l'argument à 4 tuples bbox_to_anchor, comme dans l4, se trouvent dans cette question . Le mode="expand"développe la légende horizontalement à l'intérieur de la boîte englobante donnée par le quadruple. Pour une légende étendue verticalement, voir cette question .

Parfois, il peut être utile de spécifier le cadre de délimitation en coordonnées de figure au lieu de coordonnées d'axe. Ceci est illustré dans l'exemple l5ci-dessus, où lebbox_transform argument est utilisé pour placer la légende dans le coin inférieur gauche de la figure.

Post-traitement

Le fait d'avoir placé la légende en dehors des axes conduit souvent à la situation indésirable qu'elle est complètement ou partiellement en dehors du canevas de la figure.

Les solutions à ce problème sont:

  • Ajuster les paramètres de sous-intrigue
    On peut ajuster les paramètres de sous-intrigue de telle sorte que les axes prennent moins d'espace à l'intérieur de la figure (et ainsi laissent plus d'espace à la légende) en utilisant plt.subplots_adjust. Par exemple

    plt.subplots_adjust(right=0.7)

    laisse 30% d'espace sur le côté droit de la figure, où l'on pourrait placer la légende.

  • Disposition serrée
    Utilisation plt.tight_layoutPermet d'ajuster automatiquement les paramètres du sous- tracé de sorte que les éléments de la figure soient bien serrés contre les bords de la figure. Malheureusement, la légende n'est pas prise en compte dans cet automatisme, mais nous pouvons fournir une boîte rectangulaire dans laquelle toute la zone des sous-parcelles (y compris les étiquettes) rentrera.

    plt.tight_layout(rect=[0,0,0.75,1])
  • Enregistrement de la figure avecbbox_inches = "tight"
    L'argument bbox_inches = "tight"à plt.savefigpeut être utilisé pour enregistrer la figure de telle sorte que tous les artistes sur la toile (y compris la légende) soient placés dans la zone enregistrée. Si nécessaire, la taille de la figure est automatiquement ajustée.

    plt.savefig("output.png", bbox_inches="tight")
  • ajustement automatique des paramètres de sous-intrigue
    Un moyen d'ajuster automatiquement la position du sous-tracé de telle sorte que la légende s'adapte à l'intérieur du canevas sans changer la taille de la figure se trouve dans cette réponse: Création d'une figure avec la taille exacte et sans remplissage (et légende en dehors des axes)

Comparaison entre les cas discutés ci-dessus:

entrez la description de l'image ici

Alternatives

Une légende des figures
, on peut utiliser une légende à la figure au lieu des axes, matplotlib.figure.Figure.legend. Ceci est devenu particulièrement utile pour la version matplotlib> = 2.1, où aucun argument spécial n'est nécessaire

fig.legend(loc=7) 

créer une légende pour tous les artistes dans les différents axes de la figure. La légende est placée en utilisant l' locargument, similaire à la façon dont elle est placée à l'intérieur d'un axe, mais en référence à la figure entière - elle sera donc en dehors des axes un peu automatiquement. Il reste à ajuster les sous-tracés de manière à ce qu'il n'y ait pas de chevauchement entre la légende et les axes. Ici, le point "Ajuster les paramètres du sous-tracé" ci-dessus sera utile. Un exemple:

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

entrez la description de l'image ici

Légende à l'intérieur des axes de sous-tracé dédiés
Une alternative à l'utilisation bbox_to_anchorserait de placer la légende dans ses axes de sous-tracé dédiés ( lax). Étant donné que le sous-tracé de légende doit être plus petit que le tracé, nous pouvons utiliser gridspec_kw={"width_ratios":[4,1]}lors de la création des axes. Nous pouvons masquer les axes lax.axis("off")mais toujours mettre une légende. Les poignées et les étiquettes de légende doivent être obtenues à partir du tracé réel via h,l = ax.get_legend_handles_labels(), et peuvent ensuite être fournies à la légende dans lelax sous - intrigue, lax.legend(h,l). Un exemple complet est ci-dessous.

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

Cela produit une intrigue qui est visuellement assez similaire à l'intrigue ci-dessus:

entrez la description de l'image ici

Nous pourrions également utiliser les premiers axes pour placer la légende, mais utiliser le bbox_transform axes de légende,

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

Dans cette approche, nous n'avons pas besoin d'obtenir les poignées de légende en externe, mais nous devons spécifier le bbox_to_anchor argument.

Lectures complémentaires et notes:

  • Considérez le guide de légende matplotlib avec quelques exemples d'autres choses que vous voulez faire avec des légendes.
  • Un exemple de code pour placer des légendes pour les graphiques à secteurs peut être trouvé directement en réponse à cette question: Python - La légende chevauche le graphique à secteurs
  • L' locargument peut prendre des nombres au lieu de chaînes, ce qui raccourcit les appels, cependant, ils ne sont pas très intuitivement mappés les uns aux autres. Voici le mappage pour référence:

entrez la description de l'image ici

ImportanceDeBestErnest
la source
Mettre la légende dans un axe de sous-parcelle dédié aux synergies très bien avec fig.tight_layout. Si vous utilisez plt.subplotspour créer les axes, donnez-lui simplement quelque chose comme gridspec_kw={'height_ratios': [100, 1]}(ou width_ratios) pour que les axes de la légende soient minuscules ... Ensuite fig.tight_layout(), vous les agrandirez pour les ajuster. Au moins pour matplotlib 3.0.3.
travc
161

Il suffit d' legend()appeler après l' plot()appel comme ceci:

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

Les résultats ressembleraient à ceci:

entrez la description de l'image ici

Shital Shah
la source
4
fonctionne aussi en passant les mêmes paramètres à matplotlib.pyplot.legend
kidmoser
8
Est-ce que cela coupe les mots de la légende pour quelqu'un d'autre?
user1717828
85

Pour placer la légende en dehors de la zone de tracé, utilisez les mots loc- bbox_to_anchorclés et legend(). Par exemple, le code suivant placera la légende à droite de la zone de traçage:

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

Pour plus d'informations, consultez le guide des légendes

Christian Alis
la source
10
D'accord - j'aime l'implémentation, mais quand je vais enregistrer la figure (sans la redimensionner manuellement dans la fenêtre, ce que je ne veux pas faire à chaque fois), la légende est coupée. Des idées sur la façon dont je pourrais résoudre ce problème?
astromax
@astromax Je ne suis pas sûr mais peut-être essayez d'appeler plt.tight_layout()?
Christian Alis
81

Réponse courte: vous pouvez utiliser bbox_to_anchor+ bbox_extra_artists+ bbox_inches='tight'.


Réponse plus longue: vous pouvez utiliser bbox_to_anchor pour spécifier manuellement l'emplacement de la zone de légende, comme d'autres personnes l'ont souligné dans les réponses.

Cependant, le problème habituel est que la zone de légende est rognée, par exemple:

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

entrez la description de l'image ici

Afin d'empêcher la zone de légende de se recadrer, lorsque vous enregistrez la figure, vous pouvez utiliser les paramètres bbox_extra_artistset bbox_inchesdemander savefigd'inclure des éléments recadrés dans l'image enregistrée:

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

Exemple (j'ai seulement changé la dernière ligne pour ajouter 2 paramètres 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')

entrez la description de l'image ici

Je souhaite que matplotlib autorise nativement l'emplacement extérieur pour la boîte de légende comme Matlab le fait :

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

entrez la description de l'image ici

Franck Dernoncourt
la source
6
Merci beaucoup! Les paramètres "bbox_to_anchor", "bbox_extra_artist" et "" bbox_inches = 'tight "étaient exactement ce dont j'avais besoin pour le faire fonctionner correctement. Génial!
Demitrian
6
Merci, mais bbox_inches='tight'fonctionne parfaitement pour moi même sans bbox_extra_artist
avtomaton
1
@avtomaton Merci, bon à savoir, quelle version de matplotlib utilisez-vous?
Franck Dernoncourt
1
@FranckDernoncourt python3, matplotlib version 1.5.3
avtomaton
68

En plus de toutes les excellentes réponses ici, des versions plus récentes de matplotlibet pylabpeuvent déterminer automatiquement où placer la légende sans interférer avec les tracés , si possible.

pylab.legend(loc='best')

Cela placera automatiquement la légende loin des données si possible! Comparez l'utilisation de loc = 'best'

Cependant, s'il n'y a pas de place pour mettre la légende sans chevaucher les données, alors vous voudrez essayer l'une des autres réponses; l'utilisation loc="best"ne mettra jamais la légende en dehors de l'intrigue.

dotancohen
la source
2
Merci de l'avoir signalé! J'ai cherché cela il y a quelques années et je ne l'ai pas trouvé, et c'est quelque chose qui me facilite vraiment la vie.
Edgar H
4
cette option est utile mais ne répond pas à la question, j'ai donc voté contre. pour autant que je sache, mieux ne met jamais la légende en dehors de l'intrigue
Tommy
3
@Tommy: Dans les commentaires du PO (qui semble avoir disparu maintenant), il a été explicitement précisé que le PO voulait que la légende ne couvre pas les données du graphique, et il pensait qu'en dehors de l'intrigue était le seul moyen de le faire. Vous pouvez le voir dans les réponses de mefathy, Mateo Sanchez, Bastiaan et radtek. L'OP a demandé X, mais il voulait Y .
dotancohen
1
Pas vraiment. Il / elle a spécifiquement demandé que la légende soit en dehors de l'intrigue. C'est au nom de la question;) "Comment faire sortir la légende de l'intrigue".
durbachit
4
Cela ne garantit pas que la légende ne masque pas les données. Faites juste une intrigue très dense - il n'y a pas de place pour mettre la légende. Par exemple, essayez ceci ... à partir de numpy import arange, sin, pi import matplotlib.pyplot as 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 ( 'Une onde sinusoïdale ou deux') pour l'étiquette dans ax1.get_xticklabels (): label.set_color ('r') plt.legend (loc = 'best') plt.show ()
adam.r
56

Réponse courte : invoquez le draggable sur la légende et déplacez-la de manière interactive où vous le souhaitez:

ax.legend().draggable()

Réponse longue : Si vous préférez plutôt placer la légende de manière interactive / manuelle plutôt que par programme, vous pouvez basculer le mode de glissement de la légende afin de pouvoir la faire glisser où vous le souhaitez. Consultez l'exemple ci-dessous:

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()
méfathie
la source
Je ne suis pas sûr de bien comprendre cela. Comment "glisser" la légende où je veux avec ça? J'utilise Python 3.6 et Jupyter Notebook
sb2020
14

Pas exactement ce que vous avez demandé, mais j'ai trouvé que c'était une alternative pour le même problème. Rendez la légende semi-transparente, comme ceci: tracé matplotlib avec légende semi-transparente et zone de texte semi-transparente

Faites ceci avec:

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
la source
8

Comme indiqué précédemment, vous pouvez également placer la légende dans l'intrigue, ou légèrement sur le bord également. Voici un exemple utilisant l' API Plotly Python , réalisée avec un bloc-notes IPython . Je fais partie de l'équipe.

Pour commencer, vous voudrez installer les packages nécessaires:

import plotly
import math
import random
import numpy as np

Ensuite, installez 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)

Cela crée votre graphique et vous permet de conserver la légende dans l'intrigue elle-même. La valeur par défaut de la légende si elle n'est pas définie est de la placer dans le tracé, comme illustré ici.

entrez la description de l'image ici

Pour un placement alternatif, vous pouvez aligner étroitement le bord du graphique et la bordure de la légende, et supprimer les lignes de bordure pour un ajustement plus proche.

entrez la description de l'image ici

Vous pouvez déplacer et remodeler la légende et le graphique avec du code ou avec l'interface graphique. Pour déplacer la légende, vous disposez des options suivantes pour positionner la légende à l'intérieur du graphique en affectant des valeurs x et y <= 1. Par exemple:

  • {"x" : 0,"y" : 0} -- En bas à gauche
  • {"x" : 1, "y" : 0} -- En bas à droite
  • {"x" : 1, "y" : 1} -- En haut à droite
  • {"x" : 0, "y" : 1} -- En haut à gauche
  • {"x" :.5, "y" : 0} - En bas au centre
  • {"x": .5, "y" : 1} -- Centre supérieur

Dans ce cas, nous choisissons le coin supérieur droit legendstyle = {"x" : 1, "y" : 1}, également décrit dans la documentation :

entrez la description de l'image ici

Mateo Sanchez
la source
3

Quelque chose dans ce sens a fonctionné pour moi. En commençant avec un peu de code extrait de Joe, cette méthode modifie la largeur de la fenêtre pour ajuster automatiquement une légende à droite de la figure.

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
la source
J'ai trouvé cela très utile et cela a fonctionné pour moi. Notez que si vous êtes dans le backend wx (par exemple en utilisant Windows), remplacez mgr.window.wm_geometry ("% ix% i"% (winWidthNew, mgr.window.winfo_height ())) par mgr.window.SetClientSizeWH (winWidthNew , winHeightNew) ou similaire
Ezekiel Kruglick
Si vous utilisez le backend Qt4Agg (qui est par défaut sur mon installation Linux de matplotlib), remplacez la ligne mgr.window.wm_geometry(...)par mgr.window.setFixedWidth(winWidthNew).
Filip S.
Et, comme je viens de le découvrir, si vous utilisez un backend qui n'affiche aucune fenêtre, qui est destiné à l'enregistrement directement dans un fichier (comme les backends SVG et AGG), ignorez simplement le redimensionnement de la fenêtre. fig.set_size_inches(...)s'occupe du redimensionnement dont vous avez besoin.
Filip S.
3

Il vaut la peine de rafraîchir cette question, car les nouvelles versions de Matplotlib ont beaucoup facilité la position de la légende en dehors de l'intrigue. J'ai produit cet exemple avec la version Matplotlib 3.1.1.

Les utilisateurs peuvent transmettre un tuple de coordonnées au locparamètre pour positionner la légende n'importe où dans le cadre de sélection. Le seul problème est que vous devez exécuter plt.tight_layout()pour que matplotlib recalcule les dimensions du tracé afin que la légende soit 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()

Cela conduit à l'intrigue suivante:

terrain avec légende à l'extérieur

Références:

luc
la source
2

Vous pouvez également essayer figlegend. Il est possible de créer une légende indépendante de tout objet Axes. Cependant, vous devrez peut-être créer des chemins "factices" pour vous assurer que la mise en forme des objets est correctement transmise.

Uri Laserson
la source
1

Voici un exemple du tutoriel matplotlib que vous trouverez ici . C'est l'un des exemples les plus simples, mais j'ai ajouté de la transparence à la légende et ajouté plt.show () afin que vous puissiez le coller dans le shell interactif et obtenir un résultat:

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
la source
1

La solution qui a fonctionné pour moi quand j'avais une énorme légende était d'utiliser une disposition d'image vide supplémentaire. Dans l'exemple suivant, j'ai fait 4 rangées et en bas, je trace l'image avec un décalage pour la légende (bbox_to_anchor) en haut, elle n'est pas coupée.

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
la source
1

Voici une autre solution, similaire à l'ajout bbox_extra_artistset bbox_inches, où vous n'avez pas besoin d'avoir vos artistes supplémentaires dans le cadre de votresavefig appel. Je suis venu avec cela depuis que je génère la plupart de mes fonctions intrigue à l'intérieur.

Au lieu d'ajouter tous vos ajouts à la boîte englobante lorsque vous souhaitez l'écrire, vous pouvez les ajouter à l'avance aux Figureartistes de. En utilisant quelque chose de similaire à la réponse de Franck Dernoncourt ci - dessus :

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

Voici l'intrigue générée.

ivirshup
la source
-1

Je ne sais pas si vous avez déjà réglé votre problème ... probablement oui, mais ... j'ai simplement utilisé la chaîne "extérieur" pour l'emplacement, comme dans matlab. J'ai importé pylab de matplotlib. voir le code comme suit:

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)

Cliquez pour voir l'intrigue

Ziuccia
la source