Python matplotlib 中图例中的重复项?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19385639/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Duplicate items in legend in matplotlib?
提问by
I am trying to add the legend to my plot with this snippet:
我正在尝试使用以下代码段将图例添加到我的情节中:
import matplotlib.pylab as plt
fig = plt.figure()
axes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # left, bottom, width, height (range 0 to 1)
axes.set_xlabel('x (m)')
axes.set_ylabel('y (m)')
for i, representative in enumerate(representatives):
axes.plot([e[0] for e in representative], [e[1] for e in representative], color='b', label='Representatives')
axes.scatter([e[0] for e in intersections], [e[1] for e in intersections], color='r', label='Intersections')
axes.legend()
I end up with this plot
我最终得到了这个情节
Obviously, the items are duplicated in the plot. How can I correct this error?
显然,这些项目在图中是重复的。我该如何纠正这个错误?
采纳答案by DSM
As the docssay, although it's easy to miss:
正如文档所说,虽然很容易错过:
If label attribute is empty string or starts with “_”, those artists will be ignored.
如果 label 属性为空字符串或以“_”开头,则这些艺术家将被忽略。
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.
i
我的循环索引在哪里。
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.)
(请注意,matplotlib
开发人员自己倾向于使用"_nolegend_"
显式。)
回答by wflynny
This is not an error. Your label inside the for
loop is adding len(representatives)-1
repetitive labels to your legend. What if instead you did something like
这不是错误。您在for
循环内的len(representatives)-1
标签正在向您的图例添加重复标签。如果你做了类似的事情怎么办
for i, representative in enumerate(representatives):
rep, = axes.plot([e[0] for e in representative], [e[1] for e in representative], color='b')
inter = axes.scatter([e[0] for e in intersections], [e[1] for e in intersections], color='r')
axes.legend((rep, inter), ("Representatives", "Intersections"))
Edit: The format of the below code uses the format posted on the matplotlib legend tutorial. The reason the above code failed is because there was a missing comma after rep, =
. Each iteration, rep
is being overwritten and when it is used to call legend
, only the last representatives plot is stored in rep
.
编辑:以下代码的格式使用matplotlib legend tutorial上发布的格式。上面代码失败的原因是rep, =
. 每次迭代rep
都会被覆盖,当它用于调用 时legend
,只有最后一个代表图存储在 中rep
。
fig = plt.figure()
ax = fig.add_subplot(111)
for i, representative in enumerate(representatives):
rep, = ax.plot([e[0] for e in representative], [e[1] for e in representative], color='b')
inter = ax.scatter([e[0] for e in intersections], [e[1] for e in intersections], color='r')
ax.legend((rep, inter), ("Representatives", "Intersections"))
You could also try plotting your data the way you do in your OP but make the legend using
您也可以尝试按照您在 OP 中的方式绘制数据,但使用
handles, labels = ax.get_legend_handles_labels()
and editing the contents of handles
and labels
.
和编辑的内容handles
和labels
。
回答by EL_DON
Here's a method for removing duplicated legend entries after already assigning labels normally:
这是在正常分配标签后删除重复图例条目的方法:
representatives=[[[-100,40],[-50,20],[0,0],[75,-5],[100,5]], #made up some data
[[-60,80],[0,85],[100,90]],
[[-60,15],[-50,90]],
[[-2,-2],[5,95]]]
fig = plt.figure()
axes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # left, bottom, width, height (range 0 to 1)
axes.set_xlabel('x (m)')
axes.set_ylabel('y (m)')
for i, representative in enumerate(representatives):
axes.plot([e[0] for e in representative], [e[1] for e in representative],color='b', label='Representatives')
#make sure only unique labels show up (no repeats)
handles,labels=axes.get_legend_handles_labels() #get existing legend item handles and labels
i=arange(len(labels)) #make an index for later
filter=array([]) #set up a filter (empty for now)
unique_labels=tolist(set(labels)) #find unique labels
for ul in unique_labels: #loop through unique labels
filter=np.append(filter,[i[array(labels)==ul][0]]) #find the first instance of this label and add its index to the filter
handles=[handles[int(f)] for f in filter] #filter out legend items to keep only the first instance of each repeated label
labels=[labels[int(f)] for f in filter]
axes.legend(handles,labels) #draw the legend with the filtered handles and labels lists
And here are the results:
On the left is the result of the script above. On the right, the legend call has been replaced with
axes.legend()
.
结果如下:
左侧是上述脚本的结果。在右侧,图例调用已替换为
axes.legend()
。
The advantage is you can go through most of your code and just assign labels normally and not worry about inline loops or if
s. You can also build this into a wrapper around legend or something like that.
优点是您可以完成大部分代码,只需正常分配标签,而不必担心内联循环或if
s。您还可以将其构建到图例或类似内容的包装器中。
回答by Fons
Based on the answer by EL_DON, here is a general methodfor drawing a legend without duplicate labels:
根据EL_DON 的回答,这里是绘制没有重复标签的图例的一般方法:
def legend_without_duplicate_labels(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))
Example usage:(open in repl.it
)
实例:(开放中repl.it
)
fig, ax = plt.subplots()
ax.plot([0,1], [0,1], c="y", label="my lines")
ax.plot([0,1], [0,2], c="y", label="my lines")
legend_without_duplicate_labels(ax)
plt.show()