matplotlib图例中项目的顺序是如何确定的?
我在调整图例中的项目顺序,但我觉得我不应该这样做。我尝试了:
from pylab import *
clf()
ax=gca()
ht=ax.add_patch(Rectangle((1,1),1,1,color='r',label='Top',alpha=.1))
h1=ax.bar(1,2,label='Middle')
hb=ax.add_patch(Rectangle((1,1),1,1,color='k',label='Bottom',alpha=.11))
legend()
show()
结果却是“底部”在“中间”上面。那我该怎么才能得到正确的顺序呢?这个顺序不是应该由创建的顺序决定吗?
更新:可以使用以下方法来强制调整顺序。我觉得这可能是最简单的方法,但这听起来有点奇怪。问题是,最初的顺序是由什么决定的呢?
hh=[ht,h1,hb]
legend([ht,h1.patches[0],hb],[H.get_label() for H in hh])
7 个回答
7
根据Ian Hincks的回答,我们可以用一行代码来改变图例元素的顺序,这个方法使用了嵌套的列表推导式。这样做的好处是不用给中间变量命名,也减少了代码的重复。
plt.legend(*(
[ x[i] for i in [2,1,0] ]
for x in plt.gca().get_legend_handles_labels()
), handletextpad=0.75, loc='best')
我在最后加了一些额外的参数,目的是为了说明plt.legend()
这个函数不需要单独调用来格式化和排序元素。
14
下面这个函数可以让你轻松控制图例的顺序,而且看起来也很清晰。
你可以通过标签来指定你想要的顺序。它会找到图例的句柄和标签,去掉重复的标签,并根据你给出的列表(order
)进行排序或部分排序。用法如下:
reorderLegend(ax,['Top', 'Middle', 'Bottom'])
具体细节在下面。
# Returns tuple of handles, labels for axis ax, after reordering them to conform to the label order `order`, and if unique is True, after removing entries with duplicate labels.
def reorderLegend(ax=None,order=None,unique=False):
if ax is None: ax=plt.gca()
handles, labels = ax.get_legend_handles_labels()
labels, handles = zip(*sorted(zip(labels, handles), key=lambda t: t[0])) # sort both labels and handles by labels
if order is not None: # Sort according to a given list (not necessarily complete)
keys=dict(zip(order,range(len(order))))
labels, handles = zip(*sorted(zip(labels, handles), key=lambda t,keys=keys: keys.get(t[0],np.inf)))
if unique: labels, handles= zip(*unique_everseen(zip(labels,handles), key = labels)) # Keep only the first of each handle
ax.legend(handles, labels)
return(handles, labels)
def unique_everseen(seq, key=None):
seen = set()
seen_add = seen.add
return [x for x,k in zip(seq,key) if not (k in seen or seen_add(k))]
这个函数的更新版本在 cpblUtilities.mathgraph
中,链接是 https://gitlab.com/cpbl/cpblUtilities/blob/master/mathgraph.py
使用方法如下:
fig, ax = plt.subplots(1)
ax.add_patch(Rectangle((1,1),1,1,color='r',label='Top',alpha=.1))
ax.bar(1,2,label='Middle')
ax.add_patch(Rectangle((.8,.5),1,1,color='k',label='Bottom',alpha=.1))
legend()
reorderLegend(ax,['Top', 'Middle', 'Bottom'])
show()
可选的 unique
参数可以确保去掉那些标签相同的重复绘图对象。
104
这里有一个简单的代码片段,用来对图例中的条目进行排序。它假设你已经添加了带标签的绘图元素,比如像下面这样的:
ax.plot(..., label='label1')
ax.plot(..., label='label2')
然后就是主要的部分:
handles, labels = ax.get_legend_handles_labels()
# sort both labels and handles by labels
labels, handles = zip(*sorted(zip(labels, handles), key=lambda t: t[0]))
ax.legend(handles, labels)
这只是对在 http://matplotlib.org/users/legend_guide.html 上列出的代码进行的简单调整。
126
这是对其他一些回答的一个小变化。列表 order
的长度应该和图例项的数量一样,并且手动指定新的顺序。
handles, labels = plt.gca().get_legend_handles_labels()
order = [0,2,1]
plt.legend([handles[idx] for idx in order],[labels[idx] for idx in order])