Home > other >  Extract original object from matplotlib legend entry for errorbars
Extract original object from matplotlib legend entry for errorbars

Time:04-15

When I create a simple plot like this with the errorbar function and add legend text at the end

import matplotlib.pyplot as plt

p1 = plt.errorbar([1,2],[3,4])
p2 = plt.errorbar([1,2],[5,6])

leg = plt.legend(('a','b'))

is there any way I can still programmatically identify which legend entry belongs to which plot? Because keys = [h.get_label() for h in leg.legendHandles] only returns _nolegend_ for both while p1.get_label() is still None. Is there any other way to link the actual legend text to its plot?

EDIT Maybe to make my intentions more clear: I am aware that providing a label directly during the plot command helps. But I am working on a package where a I would like to check whether a certain object is represented in any form in the legend. So far, it seems like this can't be said for certain based only on the Artist object and the legend handle without knowledge of the plot order, right?

CodePudding user response:

Defining the axis beforehand helps, at least in my solution:

import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot()
p1 = ax.errorbar([1,2],[3,4], label='a')
p2 = ax.errorbar([1,2],[5,6], label='b')
plt.legend()

leg = ax.get_legend()
print([x.get_text() for x in leg.texts])

CodePudding user response:

plt.legend(('a','b')) means to make a legend for each artist in an axes children list, which can be obtained by Axes.get_children(). So you can iterate over the legend text list together with the axes's children artist, and if a children artist matches the plotted p1 or p2, then you can link the legend text to the corresponding plot.

import matplotlib.pyplot as plt

p1 = plt.errorbar([1,2],[3,4])
p2 = plt.errorbar([1,2],[5,6])

leg = plt.legend(('a','b'))

children = plt.gca().get_children()

mapping = {}
artists = [p1, p2]
for txt, art in zip(leg.get_texts(), children):
    for p in artists:
        if p.lines[0] is art:
            mapping[p] = txt.get_text()
            artists.remove(p)

Then mapping[p1] will be 'a', and mapping[p2] will be 'b'.

However, as the doc suggests, the call signature of legend(labels) is discouraged, because the relation between plot elements and labels is only implicit by their order and can easily be mixed up.

The recommended way to add a legend is such as @Giovanni Tardini did, and that way will make your link more easily. After all, Explicit is better than implicit., as the The Zen of Python said.

  • Related