web-dev-qa-db-fra.com

Python - La légende chevauche le graphique à secteurs

Utilisation de matplotlib en python. La légende chevauche mon graphique à secteurs. J'ai essayé diverses options pour "loc" telles que "best", 1,2,3 ... mais en vain. Avez-vous des suggestions sur la façon de mentionner exactement la position de la légende (comme donner un remplissage à partir des limites du graphique à secteurs) ou au moins de vous assurer qu'elle ne se chevauche pas?

17
cassandra

La réponse courte est: vous pouvez utiliser les arguments de plt.legendloc, bbox_to_anchor Et en plus bbox_transform Et mode, pour positionner la légende dans un axe ou une figure.


Étape 1: S'assurer qu'une légende est nécessaire.

Dans de nombreux cas, aucune légende n'est nécessaire et les informations peuvent être déduites directement du contexte ou de la couleur:

enter image description here

enter image description here

Si en effet l'intrigue ne peut pas vivre sans légende, passez à l'étape 2.

Étape 2: Assurez-vous qu'un graphique à secteurs est nécessaire.

Dans de nombreux cas, les graphiques circulaires ne sont pas le meilleur moyen de transmettre des informations.

enter image description here

Si la nécessité d'un graphique à secteurs est déterminée sans ambiguïté, passons à la légende.

Placer la légende

plt.legend() a deux arguments principaux pour déterminer la position de la légende. L'argument loc est le plus important et en lui-même suffisant.
Par exemple. plt.legend(loc="upper left") a placé la légende de telle sorte qu'elle se trouve dans le coin supérieur gauche de son cadre de sélection. Si aucun autre argument n'est spécifié, ce cadre de sélection sera l'ensemble des axes.

Cependant, nous pouvons spécifier notre propre boîte englobante en utilisant l'argument bbox_to_anchor. Si bbox_to_anchor Reçoit un 2-Tuple par ex. bbox_to_anchor=(1,1) cela signifie que le cadre de sélection est situé dans le coin supérieur droit des axes et n'a aucune étendue. Il agit alors comme un point par rapport auquel la légende sera placée selon l'argument loc. Il se développera ensuite hors de la zone de délimitation de taille nulle. Par exemple. si loc est "upper left", le coin supérieur gauche de la légende est en position (1,1) et la légende s'étendra vers la droite et vers le bas.

Ce concept est utilisé pour l'intrigue ci-dessus, qui nous dit la vérité choquante sur le parti pris dans les élections de Miss Univers.

import matplotlib.pyplot as plt
import matplotlib.patches

total = [100]
labels = ["Earth", "Mercury", "Venus", "Mars", "Jupiter",  "Saturn", 
           "Uranus", "Neptune", "Pluto *"]
plt.title('Origin of Miss Universe since 1952')
plt.gca().axis("equal")
pie = plt.pie(total, startangle=90, colors=[plt.cm.Set3(0)],
                            wedgeprops = { 'linewidth': 2, "edgecolor" :"k" })
handles = []
for i, l in enumerate(labels):
    handles.append(matplotlib.patches.Patch(color=plt.cm.Set3((i)/8.), label=l))
plt.legend(handles,labels, bbox_to_anchor=(0.85,1.025), loc="upper left")
plt.gcf().text(0.93,0.04,"* out of competition since 2006", ha="right")
plt.subplots_adjust(left=0.1, bottom=0.1, right=0.75)

Afin que la légende ne dépasse pas le chiffre, nous utilisons plt.subplots_adjust Pour obtenir plus d'espace entre le bord de la figure et l'axe, qui peut ensuite être occupé par la légende.

Il y a aussi la possibilité d'utiliser un 4-Tuple pour bbox_to_anchor. Comment utiliser ou interpréter cela est détaillé dans cette question: Que signifie un argument Tuple à 4 éléments pour 'bbox_to_anchor' dans matplotlib?
et on peut ensuite utiliser l'argument mode="expand" pour que la légende tienne dans le cadre de délimitation spécifié.

Il existe des alternatives utiles à cette approche:

Utilisation des coordonnées des figures

Au lieu de spécifier la position de la légende en coordonnées d'axe, on peut utiliser des coordonnées de figure. L'avantage est que cela permettra de placer simplement la légende dans un coin de la figure sans ajuster une grande partie du reste. À cette fin, on utiliserait l'argument bbox_transform Et lui fournirait la transformation de la figure. Les coordonnées données à bbox_to_anchor Sont alors interprétées comme des coordonnées de figure.

plt.legend(pie[0],labels, bbox_to_anchor=(1,0), loc="lower right", 
                          bbox_transform=plt.gcf().transFigure)

Ici (1,0) Est le coin inférieur droit de la figure. En raison des espacements par défaut entre les axes et la figure Edge, cela suffit pour placer la légende de sorte qu'elle ne chevauche pas le graphique.

enter image description here

Dans d'autres cas, il peut être nécessaire d'adapter ces espacements de sorte qu'aucun chevauchement ne soit observé, par ex.

title = plt.title('What slows down my computer')
title.set_ha("left")
plt.gca().axis("equal")
pie = plt.pie(total, startangle=0)
labels=["Trojans", "Viruses", "Too many open tabs", "The anti-virus software"]
plt.legend(pie[0],labels, bbox_to_anchor=(1,0.5), loc="center right", fontsize=10, 
           bbox_transform=plt.gcf().transFigure)
plt.subplots_adjust(left=0.0, bottom=0.1, right=0.45)

enter image description here

Enregistrement du fichier avec bbox_inches="tight"

Maintenant, il peut y avoir des cas où nous sommes plus intéressés par le chiffre enregistré que par ce qui est affiché à l'écran. On peut alors simplement positionner la légende au bord de la figure, comme ça

enter image description here

mais enregistrez-le en utilisant le bbox_inches="tight" dans savefig,

plt.savefig("output.png", bbox_inches="tight")

Cela créera une figure plus grande, qui se tient bien autour du contenu de la toile:

enter image description here

Une approche sophistiquée, qui permet de placer la légende étroitement à l'intérieur de la figure, sans changer la taille de la figure est présentée ici: Création d'une figure avec une taille exacte et sans rembourrage (et légende en dehors des axes)

Utilisation de sous-tracés

Une alternative consiste à utiliser des sous-tracés pour réserver de l'espace pour la légende. Dans ce cas, une sous-intrigue pourrait prendre le graphique à secteurs, une autre sous-intrigue contiendrait la légende. Ceci est illustré ci-dessous.

fig = plt.figure(4, figsize=(3,3))
ax = fig.add_subplot(211) 
total = [4,3,2,81]
labels = ["tough working conditions", "high risk of accident", 
              "harsh weather", "it's not allowed to watch DVDs"]
ax.set_title('What people know about oil rigs')
ax.axis("equal")
pie = ax.pie(total, startangle=0)
ax2 = fig.add_subplot(212)
ax2.axis("off") 
ax2.legend(pie[0],labels, loc="center")

enter image description here