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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 13:37:41  来源:igfitidea点击:

Duplicate items in legend in matplotlib?

pythonmatplotlib

提问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

我最终得到了这个情节

enter image description here

在此处输入图片说明

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 iis 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 matplotlibdevelopers themselves tend to use "_nolegend_"to be explicit.)

(请注意,matplotlib开发人员自己倾向于使用"_nolegend_"显式。)

回答by wflynny

This is not an error. Your label inside the forloop is adding len(representatives)-1repetitive 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, repis 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 handlesand labels.

和编辑的内容handleslabels

回答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: enter image description hereOn 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 ifs. You can also build this into a wrapper around legend or something like that.

优点是您可以完成大部分代码,只需正常分配标签,而不必担心内联循环或ifs。您还可以将其构建到图例或类似内容的包装器中。

回答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()

enter image description here

在此处输入图片说明