263 votes

Déplacer la légende matplotlib à l'extérieur de l'axe la fait couper par la boîte de la figure

Je suis familier avec les questions suivantes:

Matplotlib savefig with a legend outside the plot

How to put the legend out of the plot

Il semble que les réponses à ces questions ont le luxe de pouvoir jouer avec le rétrécissement exact de l'axe pour que la légende s'adapte.

Cependant, rétrécir les axes n'est pas une solution idéale car cela rend les données plus petites, ce qui rend en fait plus difficile à interpréter; particulièrement lorsque c'est complexe et qu'il y a beaucoup de choses en cours ... d'où le besoin d'une grande légende

L'exemple d'une légende complexe dans la documentation démontre le besoin car la légende dans leur graphique obscurcit en fait complètement plusieurs points de données.

http://matplotlib.sourceforge.net/users/legend_guide.html#legend-of-complex-plots

Ce que j'aimerais pouvoir faire, c'est agrandir dynamiquement la taille de la boîte de la figure pour accueillir la légende de la figure en expansion.

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-2*np.pi, 2*np.pi, 0.1)
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(x, np.sin(x), label='Sine')
ax.plot(x, np.cos(x), label='Cosine')
ax.plot(x, np.arctan(x), label='Inverse tan')
lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,0))
ax.grid('on')

Remarquez comment le dernier label 'Inverse tan' est en fait à l'extérieur de la boîte de la figure (et semble mal coupé - pas de qualité de publication!) entrer la description de l'image ici

Enfin, on m'a dit que c'est un comportement normal en R et en LaTeX, donc je suis un peu confus pourquoi cela est si difficile en python... Y a-t-il une raison historique? Est-ce que Matlab est tout aussi pauvre sur cette question?

J'ai la version (seulement légèrement) plus longue de ce code sur pastebin http://pastebin.com/grVjc007

10 votes

En ce qui concerne les raisons, c'est parce que matplotlib est conçu pour des graphiques interactifs, tandis que R, etc., ne le sont pas. (Et oui, Matlab est "tout aussi pauvre" dans ce cas particulier.) Pour le faire correctement, vous devez vous soucier de redimensionner les axes à chaque fois que la figure est redimensionnée, zoomée ou que la position de la légende est mise à jour. (En effet, cela signifie vérifier à chaque fois que le tracé est dessiné, ce qui entraîne des ralentissements.) Ggplot, etc., sont statiques, c'est pourquoi ils ont tendance à le faire par défaut, alors que matplotlib et matlab ne le font pas. Cela étant dit, tight_layout() devrait être modifié pour prendre en compte les légendes.

3 votes

Je discute également de cette question sur la liste de diffusion des utilisateurs de matplotlib. J'ai donc la suggestion d'ajuster la ligne savefig à: fig.savefig('samplefigure', bbox_extra_artists=(lgd,), bbox='tight')

6 votes

Je sais que matplotlib aime promouvoir le fait que tout est sous le contrôle de l'utilisateur, mais tout ce problème avec les légendes est un peu trop. Si je mets la légende à l'extérieur, je veux évidemment qu'elle reste visible. La fenêtre devrait simplement se redimensionner pour s'adapter au lieu de créer ce problème énorme de redimensionnement. Au moins, il devrait y avoir une option par défaut True pour contrôler ce comportement de redimensionnement automatique. Forcer les utilisateurs à faire un nombre ridicule de redessins pour essayer d'ajuster les chiffres d'échelle correctement au nom du contrôle aboutit à l'effet inverse.

1voto

dylan Points 11

Je suis d'accord avec John Thomas, si vous utilisez une figure basée sur plt, tout ce dont vous avez probablement besoin est: plt.savefig('myplot.png', bbox_inches='tight')

1voto

Igor Points 874

L'option layout="constrained" (disponible depuis Matplotlib 3.7.0) permet une implémentation assez simple :

import matplotlib.pyplot as plt
import numpy as np

if __name__ == "__main__":
    x = np.arange(-2 * np.pi, 2 * np.pi, 0.1)
    fig, ax = plt.subplots(1, 1, layout="constrained")
    ax.plot(x, np.sin(x), label='Sine')
    ax.plot(x, np.cos(x), label='Cosine')
    ax.plot(x, np.arctan(x), label='Inverse tan')
    handles, labels = ax.get_legend_handles_labels()
    ax.legend(handles, labels, loc='upper center', bbox_to_anchor=(0.5, -0.1))
    text = ax.text(-0.2, 1.05, "Texte arbitraire", transform=ax.transAxes)
    ax.set_title("Trigonométrie")
    ax.grid('on')
    fig.savefig('samplefigure.png')
    fig.show()

entrer la description de l'image ici

Un des avantages (comparé à la réponse originale de jonathanbsyd) est que fig.show() fonctionne tout aussi bien.

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