Duplicate Items in Legend in Matplotlib

Duplicate items in legend in matplotlib?

As the docs say, although it's easy to miss:

If label attribute is empty string or starts with “_”, those artists
will be ignored.

So if I'm plotting similar lines in a loop and I only want one example line in the legend, I usually do something like

ax.plot(x, y, label="Representatives" if i == 0 else "")

where i is my loop index.

It's not quite as nice to look at as building them separately, but often I want to keep the label logic as close to the line drawing as possible.

(Note that the matplotlib developers themselves tend to use "_nolegend_" to be explicit.)

Stop matplotlib repeating labels in legend

plt.legend takes as parameters

  1. A list of axis handles which are Artist objects
  2. A list of labels which are strings

These parameters are both optional defaulting to plt.gca().get_legend_handles_labels().
You can remove duplicate labels by putting them in a dictionary before calling legend. This is because dicts can't have duplicate keys.

For example:

For Python versions < 3.7

from collections import OrderedDict
import matplotlib.pyplot as plt

handles, labels = plt.gca().get_legend_handles_labels()
by_label = OrderedDict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())

For Python versions > 3.7

As of Python 3.7, dictionaries retain input order by default. Thus, there is no need for OrderedDict form the collections module.

import matplotlib.pyplot as plt

handles, labels = plt.gca().get_legend_handles_labels()
by_label = dict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())

Sample Image

Docs for plt.legend

Matplotlib has duplicate legend entries

It ended up being a bug/type on my part, where I was supposed to write

maxes = [i[0] for i in sorted(maxes, key=itemgetter(1))]

instead of

percentUni = [i[0] for i in sorted(maxes, key=itemgetter(1))]

This mistake meant that maxes remained a list of 2-tuples instead of a list of integers, which is why things were plotted twice. And because I restricted the y-axis, I never saw that there were additional data elements plotted.

Thanks for your help, those who did answer!

How to remove duplicates and move the legend list to outside of the graph concurrently?

Credits to @MisterMiyagi for helping me out

I had two errors in my code:

  1. I used both plt.legend and ax.legend, so they overlapped each other
  2. However that still doesn't fix the problem, I also had to make sure when running ax.legend, it had to be in one command, not multiple as they would override each other!

This will work:

def func():

...

# revome duplicate legends
legend(ax)

# remove duplicate legends
def legend(ax):
handles, labels = ax.get_legend_handles_labels()
unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels)) if l not in labels[:i]]
ax.legend(*zip(*unique), loc='center left', bbox_to_anchor=(1, 0.5))

Python plot legend : markers appear twice

You can change the number of markers shown in the legend by using the numpoints keyword:

import matplotlib.pyplot as plt
import numpy as np
x1 = y1 = np.linspace(0, 10, 100)
x2 = np.sin(x1)
y2 = np.cos(y1)
plt.plot(x1,x2,'g--^', label='regional')
plt.plot(y1,y2,'b-o', label='local')
plt.legend( loc='upper left', numpoints = 1 )
plt.show()

Sample Image


I believe the reason the markers appear twice (by default) is because matplotlib is trying to show the linestyle connectors between the markers. It looks a little odd when there is no connector.

If the plot had solid and dashed lines,

plt.plot(x1,x2,'g--^', label='regional')
plt.plot(y1,y2,'b-o', label='local')

then the legend looks like this:

Sample Image

and now you can see the effect of the linestyle between the markers in the legend (as well as on the graph).


If you don't want any legend handle at all, then you could use

plt.legend(..., handlelength=0)

For example,

import numpy as np
import matplotlib.pyplot as plt

x1 = y1 = np.linspace(0, 10, 100)
x2 = np.sin(x1)
y2 = np.cos(y1)
plt.plot(x1,x2,'g--^', label='regional')
plt.plot(y1,y2,'b-o', label='local')
plt.legend(loc='best', numpoints=1, handlelength=0)
plt.show()

Sample Image

You could use

plt.legend(loc='best', numpoints=1, handlelength=0, 
markerscale=0, handletextpad=0)

to remove the legend marker as well.

Duplicated legend labels on Bokeh

I think this will work:

legend_tmp = {x.label['value']: x for x in p.legend.items}
p.legend.items.clear()
p.legend.items.extend(legend_tmp.values())

When it creates the legend for the plot, it is adding all of the items for both angular_wedge's but it doesn't get deduplicated the way you might expect, since the legend members are fairly complex objects themselves (meaning they are identified by more than just the value of the label).



Related Topics



Leave a reply



Submit