Comment mettre la légende hors de l'intrigue
j'ai une série de 20 parcelles (parcelles) pour être réalisés 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, comme la taille de la figure est réduite. Veuillez m'aider pour les questions suivantes:
- je veux garder la boîte de légende en dehors de la zone de la parcelle. (Je veux que la légende soit à l'extérieur du côté droit de la parcelle).
- est là de toute façon que je réduis la police Taille du texte à l'intérieur de la boîte de légende, de sorte que la taille de la boîte de légende sera petite.
16 réponses
créer des propriétés de police
from matplotlib.font_manager import FontProperties
fontP = FontProperties()
fontP.set_size('small')
legend([plot1], "title", prop=fontP)
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 bbox_to_anchor
pour placer la légende partiellement en dehors des axes et/ou diminuer la taille de la police.
avant d'envisager de diminuer la taille de la police (ce qui peut rendre les choses terriblement difficiles à lire), essayez de jouer avec le placement de la légende dans différents endroits:
donc, 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 la même façon, vous pouvez rendre la légende plus horizontale et / ou la mettre au sommet de la figure (je tourne également sur les coins arrondis et une ombre goutte simple):
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()
alternativement, vous pouvez rétrécir la largeur de la parcelle actuelle, et mettre 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 d'une manière similaire, vous pouvez rétrécir la parcelle à la verticale, et mettre la légende horizontale au 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()
ont un regardez les matplotlib légende du "guide de 1519440920" . Vous pourriez aussi jeter un coup d'oeil à plt.figlegend()
. Espérons que cela vous aide un peu, de toute façon!
placer la légende ( bbox_to_anchor
)
une légende est placée à l'intérieur de la boîte limite des axes en utilisant l'argument loc
pour plt.legend
.
Par exemple: loc="upper right"
place la légende dans le coin supérieur droit de la boîte limite, qui par défaut s'étend de (0,0)
à (1,1)
dans les coordonnées des axes (ou dans la notation de la boîte limite (x0,y0, width, height)=(0,0,1,1)
).
à placer la légende à l'extérieur de la boîte de limite des axes, on peut spécifier un tuple (x0,y0)
des coordonnées des axes du coin inférieur gauche de la légende.
plt.legend(loc=(1.04,0))
cependant, une approche plus souple consisterait à spécifier manuellement la zone de délimitation dans laquelle la légende devrait être placée, en utilisant l'argument bbox_to_anchor
. On peut se limiter à ne fournir que la partie (x0,y0)
de la bbox. Cela crée une boîte à zéro portée, à partir de laquelle la légende va s'étendre dans la direction donnée par l'argument loc
. Par exemple:
plt.legend(bbox_to_anchor=(1.04,1), loc="upper left")
place la légende en dehors des axes, de sorte que le coin supérieur gauche de la légende est à la position (1.04,1)
dans les coordonnées des axes.
D'autres exemples sont donnés ci-dessous, où en outre l'interaction entre les différents arguments comme mode
et ncols
sont montrés.
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 de 4-tuples à bbox_to_anchor
, comme dans l4
, peuvent être trouvés dans cette question . Le mode="expand"
étend la légende horizontalement à l'intérieur de la boîte limite donnée par le 4-tuple. Pour une légende étendue verticalement, voir cette question .
parfois il peut être utile de spécifier la zone de délimitation dans les coordonnées de la figure au lieu des coordonnées des axes. Cela 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.
post-traitement
ayant placé la légende en dehors des axes conduit souvent à la situation indésirable qu'il est complètement ou partiellement en dehors de la toile de la figure.
Les Solutions à ce problème sont:
-
ajuster les paramètres des sous-lots
On peut ajuster les paramètres subplot de telle sorte que les axes prennent moins d'espace à l'intérieur de la figure (et laissent ainsi plus d'espace à la légende) en utilisantplt.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 légende.
-
"1519570920 Serrée" mise en page
L'utilisation deplt.tight_layout
permet d'ajuster automatiquement les paramètres du sous-lot de telle sorte que les éléments de la figure s'assoient fermement 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 toute la zone des sous-lots (y compris les étiquettes) s'insérera.plt.tight_layout(rect=[0,0,0.75,1])
-
sauver le chiffre avec
bbox_inches = "tight"
L'argumentbbox_inches = "tight"
àplt.savefig
peut être utilisé pour sauver la figure de sorte que tous les artistes sur la toile (y compris la légende) sont adaptés dans la zone sauvegardée. Si nécessaire, la taille de la figure est ajustée automatiquement.plt.savefig("output.png", bbox_inches="tight")
- réglage automatique intrigue secondaire params
Une façon d'ajuster automatiquement la position du sous-lot de telle sorte que la légende s'adapte à l'intérieur de la toile sans changer la taille de la figure peut être trouvée dans cette réponse: création de la figure avec la taille exacte et aucun rembourrage (et la légende en dehors des axes) 15191000920"
comparaison entre les cas discutés ci-dessus:
Alternatives
Une figure de légende
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)
pour 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'argument loc
, similaire à la façon dont elle est placée à l'intérieur d'un axe, mais en référence à l'ensemble de la figure - par conséquent, il sera en dehors des axes un peu automatiquement. Il ne reste qu'à ajuster les intrigues secondaires tels qu'il n'y a pas de chevauchement entre la légende et les axes. Ici, le point "ajuster les paramètres du sous-lot" d'en haut 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 à l'intérieur dédié intrigue secondaire axes
Une alternative à l'utilisation de bbox_to_anchor
serait de placer la légende dans ses sous-axes dédiés ( lax
).
Puisque la sous-parcelle de la légende devrait être plus petite que la parcelle, nous pouvons utiliser gridspec_kw={"width_ratios":[4,1]}
à la création des axes.
On peut cacher les haches lax.axis("off")
mais quand même mettre une légende. Les poignées de légende et les étiquettes doivent être obtenues à partir de la parcelle réelle via h,l = ax.get_legend_handles_labels()
, et peut ensuite être fourni à la légende dans le lax
sous-lot, 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 parcelle qui est visuellement assez similaire à la parcelle d'en haut:
nous pourrions également utiliser les premiers axes pour placer la légende, mais utiliser le bbox_transform
de la légende axes,
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 externes, mais nous devons spécifier l'argument bbox_to_anchor
.
autres lectures et notes:
- considérez le matplotlib guide des légendes 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 diagrammes à secteurs peut être trouvé directement en réponse à cette question: Python-légende chevauche avec le diagramme à secteurs
- l'argument
loc
peut prendre des nombres au lieu de chaînes, ce qui rend les appels plus courts, cependant, ils ne sont pas très intuitivement mappés les uns aux autres. Voici la carte pour référence:
si vous utilisez Pandas plot()
fonction d'emballage et que vous voulez placer la légende à l'extérieur, alors voici le moyen très facile:
df.myCol.plot().legend(loc='center left', bbox_to_anchor=(1, 0.5))
Nous venons de la chaîne d' legend()
appel après le plot()
.
résultats ressembleraient à quelque chose comme ceci:
brève réponse: 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 la légende, comme d'autres personnes l'ont souligné dans les réponses.
cependant, la question habituelle est que la boîte de légende est coupé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 pour empêcher la boîte de légende de se couper, lorsque vous sauvegardez la figure, vous pouvez utiliser les paramètres bbox_extra_artists
et bbox_inches
pour demander savefig
pour inclure des éléments coupés dans l'image sauvegardé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')
j'aimerais que matplotlib permette nativement emplacement extérieur de la boîte de légende Matlab does :
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])
Réponse Courte : Invoquer déplaçable sur la légende et de manière interactive le déplacer où vous le souhaitez:
ax.legend().draggable()
longue réponse : si vous préférez placer la légende interactivement/manuellement plutôt que programmatiquement, vous pouvez basculer le mode draggable de la légende afin que vous puissiez la traîner où vous voulez. Cochez 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()
en plus de toutes les excellentes réponses ici, les nouvelles versions de matplotlib
et pylab
peuvent déterminer automatiquement où mettre la légende sans interférer avec les tracés .
pylab.legend(loc='best')
cela placera automatiquement la légende en dehors de l'intrigue!
pour placer la légende en dehors de la zone de la parcelle, utilisez les mots clés loc et bbox_to_anchor de legend(). Par exemple, le code suivant placera la légende à droite de la parcelle:
legend(loc="upper left", bbox_to_anchor=(1,1))
pour plus d'information, voir le guide des légendes
pas exactement ce que vous avez demandé, mais j'ai trouvé que c'est une alternative pour le même problème. Faire la légende semi-transparente, comme ça:
Faire 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 décalé vers le bord. Voici un exemple utilisant le API Python Plotly , fait avec un Bloc-notes IPython . Je suis sur l'équipe.
pour commencer, vous voudrez installer les paquets nécessaires:
import plotly
import math
import random
import numpy as np
puis, installer 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 permet une possibilité de garder la légende au sein de l'intrigue elle-même. La valeur par défaut pour la légende si elle n'est pas définie est de la placer dans le graphe, comme indiqué ici.
pour un placement alternatif, vous pouvez aligner étroitement le bord du graphe et le bord de la légende, et supprimer les lignes de bordure pour un ajustement plus proche.
vous pouvez déplacer et re-style la légende et le graphique avec le code, ou avec L'interface graphique. Pour déplacer la légende, vous avez les options suivantes pour placer la légende à l'intérieur du graphe en assignant des valeurs de x et y de <= 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}
-- Bas Au Centre -
{"x": .5, "y" : 1}
-- En Haut Au Centre
dans ce cas, nous choisissons la droite supérieure, legendstyle = {"x" : 1, "y" : 1}
, également décrit dans la documentation :
quelque chose de ce genre a fonctionné pour moi. À partir d'un peu de code tiré de Joe, cette méthode modifie la largeur de la fenêtre pour ajuster automatiquement une légende à la 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 aussi 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 "fictifs" pour vous assurer que le formatage des objets est transmis correctement.
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 ajouté plt.show () vous permet de coller ceci dans le shell interactif et d'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'ai eu la légende énorme était d'utiliser la disposition d'image vide supplémentaire. Dans l'exemple suivant j'ai fait 4 lignes et en bas je trace l'image avec offset pour la légende (bbox_to_anchor) en haut il ne se coupe pas.
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')
Voici une autre solution, semblable à ajouter bbox_extra_artists
et bbox_inches
, où vous ne devez pas avoir vos artistes supplémentaires dans le cadre de votre appel savefig
. Je suis venu avec cela depuis que je génère la plupart de mon intrigue fonctions à l'intérieur.
au lieu d'ajouter tous vos ajouts à la boîte limite quand vous voulez l'écrire, vous pouvez les ajouter à l'avance aux artistes du Figure
. En utilisant quelque chose de similaire à la réponse de Franck Dernoncourt au-dessus de :
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")
je ne sais pas si vous avez déjà réglé votre problème...oui, probablement, mais... J'ai simplement utilisé la chaîne "outside" 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)