【问题标题】:How is order of items in matplotlib legend determined?matplotlib 图例中的项目顺序是如何确定的?
【发布时间】:2014-03-08 01:29:11
【问题描述】:

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

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

【问题讨论】:

  • 这有帮助吗? matplotlib.org/users/…
  • 谢谢。我在问题中添加了一种强制命令的方法,但这很尴尬,问题是如何使它变得不必要(如果可能的话)。如果是这种情况,我想我必须接受订单未记录/未确定的答案。

标签: python matplotlib legend


【解决方案1】:

这是对图例中的条目进行排序的快速 sn-p。它假定您已经添加了带有标签的绘图元素,例如,像

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

【讨论】:

  • 是否可以在标签上使用自然排序?这是starting point
  • @Agostino:我怀疑你仍然需要这个,但万一有人需要:ax.legend(*zip(*sorted(zip(*ax.get_legend_handles_labels()), key = lambda s: [int(t) if t.isdigit() else t.lower() for t in re.split('(\d+)', s[1])])))
【解决方案2】:

与其他一些问题略有不同。列表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])

【讨论】:

  • 很好的答案:短代码总订购灵活性。为了清楚起见注释:顺序向量的数字是标签的旧位置,向量中的槽是新位置:order=[0,2,1] 表示第一个标签“0”仍然是第一个,“第一个数组槽” ;第三个标签“2”转到第二个位置,“第二个数组槽”;等等。
  • 这似乎是最好的答案,但是我正在尝试重新排序一个图例,其中还包括一个对 plt.axvline() 的调用。当我调用plt.legend() 时,垂直线正确显示在图例中,但是当我调用plt.gca().get_legend_handles_labels() 时,它的句柄不包括在内。 ://
【解决方案3】:

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

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

【讨论】:

  • 链接现在指向不相关的行。为了将来参考,最好固定到特定的提交。
  • 我认为最好的例子是行间[235-242]。您可以简单地收集每条绘制线的句柄,然后根据需要重新排序。为了将来参考,这个简单的代码有效地改变了行序:fig,ax=plt.subplots();h1,=ax.plot([1,2,3],label='tag1');h2,=ax.plot([1,2,3],label='tag2');ax.legend(handles=[h2,h1]);plt.show()
【解决方案4】:

以下函数使图例顺序的控制变得简单易读。

您可以通过标签指定您想要的顺序。它将找到图例句柄和标签,删除重复标签,并根据您给定的列表(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.mathgraphhttps://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 参数确保删除具有相同标签的重复绘图对象。

【讨论】:

    【解决方案5】:

    利用 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() 函数不需要单独调用来对元素进行格式化和排序。

    【讨论】:

      【解决方案6】:

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

      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

      【讨论】:

        猜你喜欢
        • 2021-07-06
        • 2013-12-31
        • 2023-01-16
        • 1970-01-01
        • 2016-07-28
        • 1970-01-01
        • 1970-01-01
        • 2011-02-09
        • 2012-04-13
        相关资源
        最近更新 更多