2 votes

Est-il possible de construire itérativement des entrées de légende à travers plusieurs appels de fonction de tracé ?

En vous basant sur la question et la réponse ici (Line plus shaded region for error band in matplotlib's legend et similaire à Combined legend entry for plot and fill_between), j'ai pu créer une entrée de légende qui combine des éléments de ligne et de patch.

Dans mon cas d'utilisation, j'ai besoin d'en tracer plusieurs. Lorsque je le fais, je n'ai une entrée de légende que pour la dernière combinaison ligne + patch.

import numpy as np
import matplotlib.pyplot as plt

def plot(x, y, ax, col, group, **kwargs):
    hline, = ax.plot(x, y, 'k--', color=col)
    hpatch = ax.fill_between(x, y+10, y-10, color=col, alpha=0.5)
    ax.legend([(hline, hpatch)], [f"groupe {group}: Moyenne + intervalle"])

fig, ax = plt.subplots()
x = np.linspace(1, 100, 100)
plot(x, x, ax, "C0", 1)
plot(x, x+30, ax, "C1", 2)
plot(x, x+60, ax, "C2", 3)

description de l'image ici

Remarquez la présence uniquement de la dernière entrée (groupe 3) dans la légende.

Y a-t-il un moyen d'inclure tous les groupes de lignes/chemins dans la légende de sorte qu'il y ait 3 éléments dans la légende (dans ce cas) ?

Des points bonus si cela peut être géré entièrement dans la fonction plot, évitant ainsi de devoir transmettre les références de la fonction de tracé.

Cette question ne concerne pas plusieurs légendes distinctes.

3voto

JohanC Points 38863

Pour qu'une information apparaisse dans la légende, matplotlib utilise le mot-clé label=. Vous pouvez utiliser ax.get_legend_handles_labels() pour trouver tous les éléments qui ont un label. Recombiner ces handles et labels peut créer votre légende souhaitée. Appeler ax.legend plusieurs fois effacera l'ancienne légende et en définira une nouvelle.

Le code de test remplace ax.plot(x, y, 'k--', ... par ax.plot(x, y, '--', .... Notez que ici k colorerait la ligne en noir, mais la couleur est déjà définie par le mot-clé color=.

import matplotlib.pyplot as plt
import numpy as np

def plot(x, y, ax, col, group, **kwargs):
    ax.plot(x, y, '--', color=col, label=f"groupe {group} : Moyenne")
    ax.fill_between(x, y + 10, y - 10, color=col, alpha=0.5, label='intervalle')
    handles, labels = ax.get_legend_handles_labels()
    print(handles, labels)
    ax.legend(handles=[(h1, h2) for h1, h2 in zip(handles[::2], handles[1::2])],
              labels=[l1 + " + " +l2 for l1, l2 in zip(labels[::2], labels[1::2])])

fig, ax = plt.subplots()
x = np.linspace(1, 100, 100)
plot(x, x, ax, "C0", 1)
plot(x, x + 30, ax, "C1", 2)
plot(x, x + 60, ax, "C2", 3)

plt.tight_layout()
plt.show()

graphique avec extension de la légende

2voto

Rutger Kassies Points 7713

Vous pourriez retourner l'artiste combiné et l'étiquette de la fonction de tracé et les utiliser pour créer la légende à la fin.

def plot(x, y, ax, col, group, **kwargs):
    hline, = ax.plot(x, y, 'k--', color=col)
    hpatch = ax.fill_between(x, y+10, y-10, color=col, alpha=0.5)
    return (hline, hpatch), f"groupe {group}: Moyenne + intervalle"

fig, ax = plt.subplots()
x = np.linspace(1, 100, 100)

l1 = plot(x, x, ax, "C0", 1)
l2 = plot(x, x+30, ax, "C1", 2)
l3 = plot(x, x+60, ax, "C2", 3)

ax.legend(*zip(*[l1,l2,l3]))

1voto

Tomas Capretto Points 651

J'ai essayé ce qui suit, pensant que cela fonctionnerait

def plot(x, y, ax, col, group, **kwargs):  
    legend = ax.get_legend() or []
    if legend:
        handles = legend.legendHandles
        labels = [txt.get_text() for txt in legend.get_texts()]
    else:
        handles = []
        labels = []
    hline, = ax.plot(x, y, ls='--', color=col)
    hpatch = ax.fill_between(x, y+10, y-10, color=col, alpha=0.5)

    handles += [(hline, hpatch)]
    labels += [f"group {group}: Mean + interval"]

    ax.legend(handles, labels)

fig, ax = plt.subplots(figsize=(9, 6))
x = np.linspace(1, 100, 100)
plot(x, x, ax, "C0", 1)
plot(x, x + 30, ax, "C1", 2)
plot(x, x + 60, ax, "C2", 3)

Cependant, je reçois ceci

Si nous examinons les poignées, il semble qu'il ne montre que les lignes

ax.get_legend().legendHandles

[,
 ,
 ]

J'essayais de voir s'il s'agit d'un bogue ou d'un comportement intentionnel.

J'ai aussi essayé

from matplotlib.lines import Line2D
from matplotlib.patches import Patch

def plot(x, y, ax, col, group, **kwargs):  
    legend = ax.get_legend() or []
    if legend:
        handles = legend.legendHandles
        labels = [txt.get_text() for txt in legend.get_texts()]
    else:
        handles = []
        labels = []
    hline, = ax.plot(x, y, ls='--', color=col)
    hpatch = ax.fill_between(x, y+10, y-10, color=col, alpha=0.5)
    label = f"group {group}: Mean + interval"
    handle = (Line2D([], [], color=col, label=label), Patch(color=col, alpha=0.5, label=label))
    handles += [handle]
    labels += [label]

    ax.legend(handles, labels)

mais le résultat est toujours le même

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