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
- A list of axis handles which are
Artist
objects - 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())
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:
- I used both
plt.legend
andax.legend
, so they overlapped each other - 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()
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:
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()
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
Differencebetween a Pandas Series and a Single-Column Dataframe
How to Remove Leading and Trailing Zeros in a String? Python
Importerror After Cython Embed
Comments Not Working in Jinja2
How to Create an Empty Array and Then Append to It in Numpy
Differencebetween Exec_Command and Send with Invoke_Shell() on Paramiko
How to Log Server Errors on Django Sites
Python:When Is a Variable Passed by Reference and When by Value
Combining Two Series into a Dataframe in Pandas
Installing Module from Github Through Jupyter Notebook
Sending Mail from Python Using Smtp
Convert a 1D Array to a 2D Array in Numpy
Replace Column Values Based on Another Dataframe Python Pandas - Better Way
String Comparison Doesn't Seem to Work for Lines Read from a File