web-dev-qa-db-fra.com

Matplotlib légende automatique hors tracé

J'essaie d'utiliser le mot clé bbox_to_anchor() dans un tracé matplotlib en Python.

Voici une intrigue très basique que j'ai produite:

import matplotlib.pyplot as plt
x = [1,2,3]
plt.subplot(211)
plt.plot(x, label="test1")
plt.plot([3,2,1], label="test2")
plt.legend(bbox_to_anchor=(0, -0.15, 1, 0), loc=2, ncol=2, mode="expand", borderaxespad=0)
plt.show()

Il est basé sur l'exemple ici: http://matplotlib.org/users/legend_guide.html#plotting-guide-legend

J'essaie de placer automatiquement la légende en dehors de l'intrigue en utilisant bbox_to_anchor(). Dans cet exemple, bbox_to_anchor() a 4 arguments répertoriés.

Dans cet exemple particulier (ci-dessus), la légende est placée sous le tracé, de sorte que le nombre -0,15 doit être entré manuellement à chaque changement de tracé (taille de police, titre de l'axe supprimé, etc.). Est-il possible de calculer automatiquement ces 4 nombres pour les scénarios suivants? :

  1. légende sous l'intrigue
  2. légende au-dessus de l'intrigue
  3. légende à droite de l'intrigue

Sinon, est-il possible de bien deviner ces nombres, en Python?

De plus, dans l'exemple de code ci-dessus, j'ai défini les 2 derniers chiffres de bbox_to_anchor() sur 1 et 0 car je ne comprends pas ce qu'ils sont ni comment ils fonctionnent. Que signifient les 2 derniers chiffres de bbox_to_anchor()?

16
edesz

MODIFIER:

JE RECOMMANDE FORTEMENT D'UTILISER LA RÉPONSE DE ImportanceOfBeingErnest: Comment mettre la légende hors de l'intrigue

Celui-ci est plus facile à comprendre:

import matplotlib.pyplot as plt
x = [1,2,3]
plt.subplot(211)
plt.plot(x, label="test1")
plt.plot([3,2,1], label="test2")
plt.legend(bbox_to_anchor=(0, 1), loc='upper left', ncol=1)
plt.show()

jouer maintenant avec les coordonnées to (x, y). Pour loc, vous pouvez utiliser:

valid locations are:
right
center left
upper right
lower right
best
center
lower left
center right
upper left
upper center
lower center
25
Moritz

L'argument de bbox_to_anchor est en coordonnées d'axe. matplotlib utilise différents systèmes de coordonnées pour faciliter le placement des objets sur l'écran. Lorsque vous traitez des légendes de positionnement, les systèmes de coordonnées critiques à traiter sont les coordonnées des axes, les coordonnées des figures et les coordonnées d'affichage (en pixels), comme indiqué ci-dessous:

systèmes de coordonnées matplotlib

Comme mentionné précédemment, bbox_to_anchor est en coordonnées Axes et ne nécessite pas les 4 arguments Tuple pour un rectangle. Vous pouvez simplement lui donner un Tuple à deux arguments contenant (xpos, ypos) en coordonnées Axes. L'argument loc dans ce cas définira le point d'ancrage de la légende. Ainsi, pour épingler la légende à l'extérieur à droite des axes et aligné avec le bord supérieur, vous émettez ce qui suit:

lgd = plt.legend(bbox_to_anchor=(1.01, 1), loc='upper left')

Cependant, cela ne repositionne pas les axes par rapport à la figure et cela placera probablement la légende hors du canevas de la figure. Pour repositionner automatiquement le canevas de la figure pour l'aligner avec les axes et la légende, j'ai utilisé l'algorithme suivant.

Tout d'abord, dessinez la légende sur le canevas pour lui attribuer de vraies coordonnées en pixels:

plt.gcf().canvas.draw()

Définissez ensuite la transformation pour passer des coordonnées pixel aux coordonnées figure:

invFigure = plt.gcf().transFigure.inverted()

Ensuite, obtenez l'étendue de la légende en pixels et convertissez-la en coordonnées de figure. Tirez la mesure la plus éloignée dans la direction x car c'est la direction du canevas que nous devons ajuster:

lgd_pos = lgd.get_window_extent()
lgd_coord = invFigure.transform(lgd_pos)
lgd_xmax = lgd_coord[1, 0]

Faites de même pour les axes:

ax_pos = plt.gca().get_window_extent()
ax_coord = invFigure.transform(ax_pos)
ax_xmax = ax_coord[1, 0]

Enfin, ajustez le canevas de la figure à l'aide de tight_layout pour la proportion des axes qui doivent se déplacer pour laisser de la place à la légende pour qu'elle tienne dans le canevas:

shift = 1 - (lgd_xmax - ax_xmax)
plt.gcf().tight_layout(rect=(0, 0, shift, 1))

Notez que l'argument rect à tight_layout se trouve dans les coordonnées de la figure et définit les coins inférieur gauche et supérieur droit d'un rectangle contenant les limites tight_layout des axes, qui n'inclut pas la légende. Ainsi, un simple appel tight_layout équivaut à définir des limites droites de (0, 0, 1, 1).

4
Steve Horst