1311 votes

Comment mettre la légende hors de l'intrigue

J'ai une série de 20 tracés (pas de sous-tracés) à réaliser dans 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 diminue. Veuillez m'aider pour les questions suivantes :

  1. Je veux que la boîte de légende reste en dehors de la zone de tracé. (Je veux que la légende soit à l'extérieur, sur le côté droit de la zone de tracé).
  2. Est-il possible de réduire 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 réduite ?

2142voto

Joe Kington Points 68089

Il y a plusieurs façons de faire ce que vous voulez. Pour ajouter à ce que @inalis et @Navi ont déjà dit, vous pouvez utiliser la fonction bbox_to_anchor argument de mot-clé pour placer la légende partiellement à l'extérieur 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 terriblement difficiles à lire), essayez de placer 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()

alt text

Si on fait la même chose, mais qu'on utilise l'option bbox_to_anchor L'argument du mot clé nous permet de 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()

alt text

De même, rendez la légende plus horizontale et/ou placez-la en haut de la figure (j'opte également pour 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()

alt text

Une autre solution consiste à réduire la largeur du tracé actuel et à placer la légende entièrement à l'extérieur de l'axe de la figure (remarque : si vous utilisez la fonction tight_layout() puis laissez tomber 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()

alt text

Et de la même manière, réduisez le tracé verticalement, et mettez une 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()

alt text

Jetez un coup d'œil à la Guide de légende de matplotlib . Vous pouvez également consulter plt.figlegend() .

0 votes

La légende multicolonne (avec ncol=<num cols> ) est exactement ce dont j'avais besoin.

181voto

ShitalShah Points 2213

Appelez simplement legend() après l'appel plot() appelez comme ça :

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

enter image description here

4 votes

Fonctionne également en passant les mêmes paramètres à matplotlib.pyplot.legend.

12 votes

Est-ce que cela coupe les mots de la légende pour quelqu'un d'autre ?

1 votes

L'appel à "tight_layout()" corrige le problème des mots coupés pour moi.

175voto

Navi Points 3644

enter image description here

  • Comme l'a noté Mateen Ulhaq , fontsize='xx-small' fonctionne également, sans importer FontProperties .

    plt.legend(handles=[p1, p2], title='title', bbox_to_anchor=(1.05, 1), loc='upper left', fontsize='xx-small')

89voto

Franck Dernoncourt Points 4769

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 boîte de légende, comme d'autres personnes l'ont signalé dans les réponses.

Cependant, le problème habituel est que la boîte 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')

enter image description here

Afin d'éviter que la boîte de légende ne soit rognée, lorsque vous enregistrez la figure, vous pouvez utiliser les paramètres suivants bbox_extra_artists et bbox_inches pour demander savefig pour inclure les é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')

enter image description here

Je souhaite que matplotlib permette nativement un emplacement extérieur pour la boîte de légende comme Matlab 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])

enter image description here

6 votes

Merci beaucoup ! Les paramètres "bbox_to_anchor", "bbox_extra_artist" et ""bbox_inches='tight" étaient exactement ce dont j'avais besoin pour que cela fonctionne correctement. C'est génial !

7 votes

Merci, mais en fait bbox_inches='tight' fonctionne parfaitement pour moi même sans bbox_extra_artist

1 votes

@avtomaton Merci, bon à savoir, quelle version de matplotlib utilisez-vous ?

57voto

mefathy Points 193

Réponse courte : Invoquer draggable sur la légende et la déplacer interactivement où vous voulez :

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 programmatique, vous pouvez basculer le mode dragable 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()

0 votes

Je ne suis pas sûr de bien comprendre. Comment puis-je faire "glisser" la légende où je veux avec ceci ? J'utilise Python 3.6 et Jupyter Notebook.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X