如何确定matplotlib图例中项目的顺序?

3mpgtkmj  于 2023-01-05  发布在  其他
关注(0)|答案(7)|浏览(266)

我不得不重新排序图例中的项目,而我认为我不应该这样做。我尝试:

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])
dzhpxtsq

dzhpxtsq1#

与其他一些图例稍有不同。列表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])
gwo2fgha

gwo2fgha2#

下面是一个对图例中的条目进行排序的简短代码片段。它假设您已经添加了带有标签的绘图元素,例如,类似于

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中列出的代码的简单修改

f4t66c6m

f4t66c6m3#

顺序是确定的,但部分私有guts可以随时更改,请看这里的代码,它会转到这里,最后到这里。孩子是已经添加的艺术家,因此句柄列表是按照他们添加的顺序排序的(这是mpl34或mpl35的行为变化)。
如果您想显式控制图例中元素的顺序,那么就像在编辑中一样,组装一个处理程序和标签的列表。

zqdjd7g9

zqdjd7g94#

以下函数使图例顺序的控制变得容易且可读。
您可以指定您想要的标签顺序。它将查找图例句柄和标签,删除重复的标签,并根据您给定的列表(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参数可确保删除具有相同标签的重复打印对象。

w8f9ii69

w8f9ii695#

借鉴IanHincks的answer,图例元素顺序的更改可以通过嵌套列表解析在一行中完成,这避免了命名中间变量的需要,减少了代码重复。

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()函数来设置元素的格式和排序。

1sbrub3j

1sbrub3j6#

根据另一个列表对标签进行排序的简单方法如下所示:将所有绘图和标签添加到轴后,在显示标签前执行以下步骤。

handles,labels = ax.get_legend_handles_labels()
sorted_legends= [x for _,x in sorted(zip(k,labels),reverse=True)] 
#sort the labels based on the list k
#reverse=True sorts it in descending order
sorted_handles=[x for _,x in sorted(zip(k,handles),reverse=True)]
#to sort the colored handles
ax.legend(sorted_handles,sorted_legends,bbox_to_anchor=(1,0.5), loc='center left')
#display the legend on the side of your plot.

示例:

from matplotlib import pyplot as plt
import numpy as np

rollno=np.arange(1,11)
marks_math=np.random.randint(30,100,10)
marks_science=np.random.randint(30,100,10)
marks_english=np.random.randint(30,100,10)
print("Roll No. of the students: ",rollno)
print("Marks in Math: ",marks_math)
print("Marks in Science: ",marks_science)
print("Marks in English: ",marks_english)
average=[np.average(marks_math),np.average(marks_science),np.average(marks_english)] #storing the average of each subject in a list

fig1=plt.figure()
ax=fig1.add_subplot(1,1,1)
ax.set_xlabel("Roll No.")
ax.set_ylabel("Marks")
ax.plot(rollno,marks_math,c="red",label="marks in math, Mean="+str(average[0]))
ax.plot(rollno,marks_science,c="green",label="marks in science, Mean="+str(average[1]))
ax.plot(rollno,marks_english,c="blue",label="marks in english, Mean="+str(average[2]))
#ax.legend() # This would display the legend with red color first, green second and the blue at last

#but we want to sort the legend based on the average marks which must order the labels based on average sorted in decending order
handles,labels=ax.get_legend_handles_labels()
sorted_legends= [x for _,x in sorted(zip(average,labels),reverse=True)] #sort the labels based on the average which is on a list
sorted_handles=[x for _,x in sorted(zip(average,handles),reverse=True)] #sort the handles based on the average which is on a list
ax.legend(sorted_handles,sorted_legends,bbox_to_anchor=(1,0.5), loc='center left') #display the handles and the labels on the side
plt.show()
plt.close()

对于具有如下值的运行:

Roll No. of the students:  [ 1  2  3  4  5  6  7  8  9 10]
Marks in Math:  [66 46 44 70 37 72 93 32 81 84]
Marks in Science:  [71 99 99 40 59 80 72 98 91 81]
Marks in English:  [46 64 74 33 86 49 84 92 67 35]
The average in each subject [62.5, 79.0, 63.0]

标签应该按照红色、绿色和蓝色的顺序排列,因为它们在图中是按照这个顺序排列的,但我们希望根据平均值对它们进行排序,这将给我们一个绿色、蓝色和红色的顺序。
Check this image

nvbavucw

nvbavucw7#

我在一张图中有几个相同主题的图,当我尝试根据上面的答案改变标签时,我发现并排的图会以相同标签的不同颜色结束。
因此,对我来说最简单的解决方案是在创建绘图之前按所需的标签排序:

# Pandas adds the series in random order, we'll need to sort before plotting below...
pd.plotting.parallel_coordinates(
    df.sort_values(by='tier_label'), 
    ax=ax,
    class_column='tier_label', 
    alpha=0.5, color='#EDBB00 #004D98 #A50044'.split())

这当然需要排序,所以你决定它是否适用于你的情况。另外,如果你需要标签文本与class_column不同,那么你可能需要添加更多的代码。

相关问题