web-dev-qa-db-fra.com

Matplotlib: Ajustez l'emplacement / la position de la légende

Je crée une figure avec plusieurs sous-intrigues. L'une de ces sous-intrigues me pose quelques problèmes, car aucun des coins ou centres des axes n'est libre (ou peut être libéré) pour placer la légende. Ce que j'aimerais faire, c'est que la légende soit placée quelque part entre les emplacements `` en haut à gauche '' et `` au centre à gauche '', tout en gardant le rembourrage entre elle et l'axe des y égal aux légendes des autres sous-parcelles (qui sont placé à l'aide de l'un des mots clés d'emplacement de légende prédéfinis).

Je sais que je peux spécifier une position personnalisée en utilisant loc=(x,y), mais je ne peux pas comprendre comment obtenir un rembourrage entre la légende et l'axe des y égal à celui utilisé par les autres légendes. Serait-il possible d'utiliser en quelque sorte la propriété borderaxespad de la première légende? Bien que je ne réussisse pas à faire fonctionner cela.

Toutes les suggestions seront les bienvenues!

Edit: Voici une illustration (très simplifiée) du problème:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 2, sharex=False, sharey=False)
ax[0].axhline(y=1, label='one')
ax[0].axhline(y=2, label='two')
ax[0].set_ylim([0.8,3.2])
ax[0].legend(loc=2)

ax[1].axhline(y=1, label='one')
ax[1].axhline(y=2, label='two')
ax[1].axhline(y=3, label='three')
ax[1].set_ylim([0.8,3.2])
ax[1].legend(loc=2)

plt.show()

enter image description here

Ce que j'aimerais, c'est que la légende dans le tracé de droite soit quelque peu abaissée pour ne plus chevaucher la ligne. En dernier recours, je pourrais changer les limites des axes, mais j'aimerais bien éviter cela.

12
Caleris

Après avoir passé beaucoup trop de temps à ce sujet, j'ai trouvé la solution satisfaisante suivante (le Transformations Tutorial a certainement aidé):

bapad = plt.rcParams['legend.borderaxespad']
fontsize = plt.rcParams['font.size']
axline = plt.rcParams['axes.linewidth']  #need this, otherwise the result will be off by a few pixels
pad_points = bapad*fontsize + axline  #padding is defined in relative to font size
pad_inches = pad_points/72.0  #convert from points to inches
pad_pixels = pad_inches*fig.dpi  #convert from inches to pixels using the figure's dpi

Ensuite, j'ai trouvé que les deux travaux suivants donnent la même valeur pour le rembourrage:

# Define inverse transform, transforms display coordinates (pixels) to axes coordinates
inv = ax[1].transAxes.inverted()
# Inverse transform two points on the display and find the relative distance
pad_axes = inv.transform((pad_pixels, 0)) - inv.transform((0,0))  
pad_xaxis = pad_axes[0]

ou

# Find how may pixels there are on the x-axis
x_pixels = ax[1].transAxes.transform((1,0)) - ax[1].transAxes.transform((0,0))
# Compute the ratio between the pixel offset and the total amount of pixels 
pad_xaxis = pad_pixels/x_pixels[0]

Et puis définissez la légende avec:

ax[1].legend(loc=(pad_xaxis,0.6))

Terrain:

8
Caleris

J'ai vu la réponse que vous avez publiée et je l'ai essayée. Le problème est cependant que cela dépend aussi de la taille de la figure.

Voici un nouvel essai:

import numpy
import matplotlib.pyplot as plt


x = numpy.linspace(0, 10, 10000)
y = numpy.cos(x) + 2.

x_value = .014    #Offset by eye
y_value = .55

fig, ax = plt.subplots(1, 2, sharex = False, sharey = False)
fig.set_size_inches(50,30)

ax[0].plot(x, y, label = "cos")
ax[0].set_ylim([0.8,3.2])
ax[0].legend(loc=2)

line1 ,= ax[1].plot(x,y)
ax[1].set_ylim([0.8,3.2])

axbox = ax[1].get_position()

fig.legend([line1], ["cos"], loc = (axbox.x0 + x_value, axbox.y0 + y_value))

plt.show()

Donc, ce que je fais maintenant, c'est essentiellement d'obtenir les coordonnées de la sous-intrigue. Je crée ensuite la légende en fonction des dimensions de la figure entière. Par conséquent, la taille de la figure ne change plus rien au positionnement de la légende.

Avec les valeurs de x_value et y_value la légende peut être positionnée dans le sous-tracé. x_value a été oculaire pour une bonne correspondance avec la légende "normale". Cette valeur peut être modifiée à votre guise. y_value détermine la hauteur de la légende.

enter image description here

Bonne chance!

10
The Dude