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

时间:2014-03-08 01:29:11

标签: python matplotlib legend

我不得不重新订购传奇中的项目,当时我认为不应该这样做。我试试:

from pylab import *
clf()
ax=gca()
ht=ax.add_patch(Rectangle((1,1),1,1,color='r',label='Top',alpha=.01))
h1=ax.bar(1,2,label='Middle')
hb=ax.add_patch(Rectangle((1,1),1,1,color='k',label='Bottom',alpha=.01))
legend()
show()

并以Midom为中心结束。我怎样才能得到正确的订单?它不是由创建顺序决定的吗?

Code results in the wrong legend item order

更新:以下内容可用于强制执行订单。我认为这可能是最简单的方法,这看起来很尴尬。问题是什么决定了原始订单?

hh=[ht,h1,hb]
legend([ht,h1.patches[0],hb],[H.get_label() for H in hh])

6 个答案:

答案 0 :(得分:59)

这是一个快速片段,用于对图例中的条目进行排序。它假设您已经添加了带有标签的绘图元素,例如

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

中列出的代码的简单修改

答案 1 :(得分:17)

其他一些产品稍有不同。列表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])

答案 2 :(得分:11)

订单是确定性的,但部分私人内容可以随时更改,请参阅代码hereself.*元素是已添加的艺术家列表,因此句柄列表首先按类型排序,其次按顺序排序。

如果您想明确控制图例中元素的顺序,请像编辑一样组合处理程序和标签列表。

答案 3 :(得分:2)

利用 Ian Hincks 的 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() 函数来对元素进行格式化和排序。

答案 4 :(得分:1)

以下函数查找图例句柄和标签,并根据给定列表(order)对它们进行排序或部分排序:

def reorderLegend(ax=None,order=None,unique=False):
    """
    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.
    """
    if ax is None: ax=plt.gca()

    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]))
    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: # Keep only the first of each handle
        labels, handles= zip(*unique_everseen(zip(labels,handles), key = labels))
    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 http://github.com/cpbl

引文:Kevin(本页)和Markus Jarderot(How do you remove duplicates from a list in whilst preserving order?)。

答案 5 :(得分:1)

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

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