J'ai une série de 20 parcelles (pas des sous-parcelles) à réaliser en une seule figure. Je veux que la légende soit en dehors de la boîte. Dans le même temps, je ne souhaite pas modifier les axes car la taille de la figure est réduite. Veuillez m'aider pour les requêtes suivantes:
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
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 l'argument de mot clé bbox_to_anchor
pour placer la légende partiellement en dehors des axes et/ou réduire la taille de la police.
Avant d’envisager de réduire la taille de la police (ce qui peut rendre les choses très difficiles à lire), essayez de placer la légende à différents endroits:
Commençons 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()
Si nous faisons la même chose, mais en utilisant l'argument de mot clé bbox_to_anchor
, 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()
De même, vous pouvez rendre la légende plus horizontale et/ou la mettre en haut de la figure (je tourne aussi sur 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()
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:
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()
Et de la même manière, vous pouvez réduire le tracé verticalement et placer 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()
Consultez le guide de légende de matplotlib . Vous pouvez également jeter un oeil à plt.figlegend()
. J'espère que ça aide un peu, quand même!
bbox_to_anchor
_)Une légende est positionnée à l'intérieur du cadre de sélection des axes à l'aide de l'argument loc
to plt.legend
.
Par exemple. _loc="upper right"
_ place la légende dans le coin supérieur droit du cadre de sélection, laquelle s'étend par défaut de _(0,0)
_ à _(1,1)
_ en coordonnées d'axes (ou en notation _(x0,y0, width, height)=(0,0,1,1)
_).
Pour placer la légende en dehors du cadre de sélection des axes, vous pouvez spécifier un tuple _(x0,y0)
_ des coordonnées d'axes du coin inférieur gauche de la légende.
_plt.legend(loc=(1.04,0))
_
Cependant, une approche plus polyvalente consisterait à spécifier manuellement le cadre de sélection dans lequel la légende doit être placée, à l'aide de l'argument bbox_to_anchor
. On peut se limiter à ne fournir que la partie _(x0,y0)
_ de la bbox. Cela crée une zone de portée zéro, à partir de laquelle la légende se développera dans la direction indiquée par l'argument loc
. 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 à la position _(1.04,1)
_ dans les coordonnées des axes.
D'autres exemples sont donnés ci-dessous, où l'interaction entre différents arguments tels que mode
et ncols
est également illustrée.
_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")
_
Des détails sur la façon d'interpréter l'argument 4-Tuple en _bbox_to_anchor
_, comme dans _l4
_, peuvent être trouvés dans cette question . Le _mode="expand"
_ étend la légende horizontalement à l'intérieur du cadre de sélection donné par le 4-Tuple. Pour une légende étendue verticalement, voir cette question .
Parfois, il peut être utile de spécifier le cadre de sélection dans les coordonnées de la figure au lieu des coordonnées des axes. Ceci est montré dans l'exemple _l5
_ ci-dessus, où l'argument _bbox_transform
_ est utilisé pour mettre la légende dans le coin inférieur gauche de la figure.
Après avoir placé la légende en dehors des axes, il est fréquent que la légende se trouve complètement ou partiellement en dehors de la figure.
Les solutions à ce problème sont les suivantes:
Ajustez les paramètres de la sous-parcelle
On peut ajuster les paramètres de la sous-parcelle de telle sorte que les axes prennent moins de place dans la figure (et ainsi laissent plus de place à la légende) en utilisant plt.subplots_adjust
. Par exemple.
_plt.subplots_adjust(right=0.7)
_
laisse 30% d'espace à droite de la figure, où l'on peut placer la légende.
Disposition serrée
Using plt.tight_layout
Permet d’ajuster automatiquement les paramètres de la sous-parcelle de sorte que les éléments de la figure soient bien ajustés contre les bords de la figure. Malheureusement, la légende n'est pas prise en compte dans cet automatisme, mais nous pouvons fournir un rectangle dans lequel s'inscrira toute la zone des sous-parcelles (y compris les étiquettes).
_plt.tight_layout(rect=[0,0,0.75,1])
_
Enregistrement de la figure avec _bbox_inches = "tight"
_
L'argument _bbox_inches = "tight"
_ à plt.savefig
peut être utilisé pour enregistrer la figure, de sorte que tous les artistes de la zone de dessin (y compris la légende) entrent dans la zone enregistrée. . Si nécessaire, la taille de la figure est automatiquement ajustée.
_plt.savefig("output.png", bbox_inches="tight")
_
Comparaison entre les cas discutés ci-dessus:
Une légende de la figure
On peut utiliser une légende pour la figure au lieu des axes, matplotlib.figure.Figure.legend
. Ceci est devenu particulièrement utile pour la version de 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 à l’aide de l’argument loc
, de la même façon qu’elle est placée à l’intérieur d’un axe, mais en référence à la figure entière. Elle se trouve donc en dehors des axes de manière quelque peu automatique. Ce qui reste à faire est d’ajuster les sous-parcelles afin qu’il n’y ait pas de chevauchement entre la légende et les axes. Ici, le point "Ajuster les paramètres de la sous-parcelle" 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()
_
Légende dans les axes de sous-parcelle dédiés
Une alternative à l'utilisation de _bbox_to_anchor
_ serait de placer la légende dans ses axes de sous-parcelle dédiés (lax
). Comme la sous-parcelle de légende doit être plus petite que la parcelle, nous pouvons utiliser _gridspec_kw={"width_ratios":[4,1]}
_ lors de la création des axes. Nous pouvons masquer les axes lax.axis("off")
tout en insérant 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 le sous-tracé lax
, 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 jolie, semblable à l'intrigue d'en haut:
Nous pourrions également utiliser les premiers axes pour placer la légende, mais utiliser le _bbox_transform
_ des axes de la légende,
_ax.legend(bbox_to_anchor=(0,0,1,1), bbox_transform=lax.transAxes)
lax.axis("off")
_
Dans cette approche, il n'est pas nécessaire d'obtenir les descripteurs de légende en externe, mais de spécifier l'argument _bbox_to_anchor
_.
loc
peut prendre des chiffres au lieu de chaînes, ce qui raccourcit les appels, mais ils ne sont pas très intuitivement mappés les uns aux autres. Voici la cartographie pour référence:Appelez simplement legend()
appel après l'appel plot()
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:
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 indiqué dans les réponses.
Cependant, le problème habituel est que la boîte de légende est recadré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')
Pour éviter que la zone de légende ne soit recadrée, vous pouvez utiliser les paramètres bbox_extra_artists
et bbox_inches
pour demander à savefig
d'inclure des éléments recadrés dans l'image sauvegardée:
fig.savefig('image_output.png', bbox_extra_artists=(lgd,), bbox_inches='tight')
Exemple (j'ai seulement modifié 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')
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])
Pour placer la légende en dehors de la zone de tracé, utilisez loc
et bbox_to_anchor
mots-clés de legend()
. Par exemple, le code suivant placera la légende à droite de la zone de tracé:
legend(loc="upper left", bbox_to_anchor=(1,1))
Pour plus d'informations, voir le guide de légende
En plus de toutes les excellentes réponses ici, les versions plus récentes de matplotlib
et pylab
peuvent 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!
Cependant, s'il n'y a pas de place pour mettre la légende sans superposer les données, vous voudrez alors essayer l'une des autres réponses; utiliser loc="best"
ne mettra jamais la légende à l'extérieur du tracé.
Réponse courte: Invoquez la glissière sur la légende et déplacez-la de manière interactive n'importe où:
ax.legend().draggable()
Réponse longue: Si vous préférez placer la légende de manière interactive/manuelle plutôt que par programme, vous pouvez basculer le mode déplaçable de la légende afin de pouvoir la faire glisser où vous le souhaitez. Vérifiez 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()
Ce n’est pas exactement ce que vous avez demandé, mais j’ai trouvé que c’était une alternative au même problème. Rendre la légende semi-transparente, comme suit:
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)
Comme indiqué, vous pouvez également placer la légende dans l’intrigue ou légèrement au-delà. Voici un exemple utilisant l'API Plotly Python _ , créé avec un IPython Notebook . Je suis dans 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 le tracé même. La légende par défaut si elle n’est pas définie est de la placer dans le graphique, comme indiqué ici.
Pour un placement alternatif, vous pouvez aligner étroitement le bord du graphique et le bord de la légende, et supprimer les lignes de bord pour un ajustement plus précis.
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 avez les options suivantes pour la positionner dans le graphique en attribuant des valeurs x et y de <= 1. E.g:
{"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}
- Centre bas{"x": .5, "y" : 1}
- Centre supérieurDans ce cas, nous choisissons le coin supérieur droit, legendstyle = {"x" : 1, "y" : 1}
, également décrit dans la documentation :
Quelque chose dans ce sens a fonctionné pour moi. En commençant par un peu de code extrait de Joe, cette méthode modifie la largeur de la fenêtre pour qu'elle s'adapte 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()
Vous pouvez également essayer figlegend
. Il est possible de créer une légende indépendante de tout objet Axes. Toutefois, vous devrez peut-être créer des chemins "factices" pour vous assurer que la mise en forme des objets est correctement transmise.
Voici une autre solution, similaire à l'ajout de bbox_extra_artists
et de bbox_inches
, où vous n'avez pas besoin d'avoir vos artistes supplémentaires dans la portée de votre appel savefig
. Je suis venu avec cela depuis que je génère la plupart de mes parcelles dans les fonctions.
Au lieu d'ajouter tous vos ajouts au cadre de sélection lorsque vous souhaitez l'écrire, vous pouvez les ajouter à l'avance aux artistes de Figure
. En utilisant quelque chose de similaire à celui de Franck Dernoncourt réponse 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 un exemple du tutoriel matplotlib trouvé ici . C’est l’un des exemples les plus simples, mais j’ai ajouté de la transparence à la légende et plt.show () pour 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()
La solution qui a fonctionné pour moi quand j'avais une énorme légende était d'utiliser une mise en page d'image vide supplémentaire. Dans l'exemple suivant, j'ai créé 4 lignes et en bas, je trace l'image avec le 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')
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)