【问题标题】:pyplot combine multiple line labels in legendpyplot 在图例中组合多个行标签
【发布时间】:2014-10-13 10:10:53
【问题描述】:

我的数据会导致绘制多条线,我想在我的图例中为这些线提供一个标签。我认为使用下面的示例可以更好地证明这一点,

a = np.array([[ 3.57,  1.76,  7.42,  6.52],
              [ 1.57,  1.2 ,  3.02,  6.88],
              [ 2.23,  4.86,  5.12,  2.81],
              [ 4.48,  1.38,  2.14,  0.86],
              [ 6.68,  1.72,  8.56,  3.23]])

plt.plot(a[:,::2].T, a[:, 1::2].T, 'r', label='data_a')

plt.legend(loc='best')

正如您在 Out[23] 中看到的那样,该图产生了 5 条不同的线。结果图如下所示

有什么方法可以告诉 plot 方法避免使用多个标签?我不想尽可能多地使用自定义图例(您可以同时指定标签和线条形状)。

【问题讨论】:

  • 您需要新闻广播来创建自定义图例。无法粘贴链接,因为我的手机很垃圾。谷歌“matplotlib 手动创建图例”。有一个 SO 答案,其中包含您需要的所有内容。
  • @will 谢谢,这很有帮助

标签: python matplotlib plot legend


【解决方案1】:

如果我打算经常做的话,我会亲自做一个小助手函数;

from matplotlib import pyplot
import numpy


a = numpy.array([[ 3.57,  1.76,  7.42,  6.52],
                 [ 1.57,  1.2 ,  3.02,  6.88],
                 [ 2.23,  4.86,  5.12,  2.81],
                 [ 4.48,  1.38,  2.14,  0.86],
                 [ 6.68,  1.72,  8.56,  3.23]])


def plotCollection(ax, xs, ys, *args, **kwargs):

  ax.plot(xs,ys, *args, **kwargs)

  if "label" in kwargs.keys():

    #remove duplicates
    handles, labels = pyplot.gca().get_legend_handles_labels()
    newLabels, newHandles = [], []
    for handle, label in zip(handles, labels):
      if label not in newLabels:
        newLabels.append(label)
        newHandles.append(handle)

    pyplot.legend(newHandles, newLabels)

ax = pyplot.subplot(1,1,1)  
plotCollection(ax, a[:,::2].T, a[:, 1::2].T, 'r', label='data_a')
plotCollection(ax, a[:,1::2].T, a[:, ::2].T, 'b', label='data_b')
pyplot.show()

从图例的 handleslabels 中删除重复项(比您拥有的)更简单(并且 IMO 更清晰)的方法是:

handles, labels = pyplot.gca().get_legend_handles_labels()
newLabels, newHandles = [], []
for handle, label in zip(handles, labels):
  if label not in newLabels:
    newLabels.append(label)
    newHandles.append(handle)
pyplot.legend(newHandles, newLabels)

【讨论】:

  • 如果您使用set 代替newLabels,您将避免在检查成员资格时遍历整个事情。
【解决方案2】:

Numpy 解决方案基于上述 will 的响应。

import numpy as np
import matplotlib.pylab as plt
a = np.array([[3.57, 1.76, 7.42, 6.52],
              [1.57, 1.20, 3.02, 6.88],
              [2.23, 4.86, 5.12, 2.81],
              [4.48, 1.38, 2.14, 0.86],
              [6.68, 1.72, 8.56, 3.23]])

plt.plot(a[:,::2].T, a[:, 1::2].T, 'r', label='data_a')
handles, labels = plt.gca().get_legend_handles_labels()

假设相同的标签有相同的句柄,得到唯一的标签和它们各自的索引,它们对应于句柄索引。

labels, ids = np.unique(labels, return_index=True)
handles = [handles[i] for i in ids]
plt.legend(handles, labels, loc='best')
plt.show()

【讨论】:

  • 另一个非常简短的解决方案:legs = ax.get_legend_handles_labels(); list(zip(*[[legs[0][i], legs[1][i]] for i in [legs[1].index(l) for l in set(legs[1])]]))
【解决方案3】:

Matplotlib 为您提供了一个很好的线条集合界面,LineCollection。代码很简单

import numpy
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection

a = numpy.array([[ 3.57,  1.76,  7.42,  6.52],
                 [ 1.57,  1.2 ,  3.02,  6.88],
                 [ 2.23,  4.86,  5.12,  2.81],
                 [ 4.48,  1.38,  2.14,  0.86],
                 [ 6.68,  1.72,  8.56,  3.23]])

xs = a[:,::2]
ys = a[:, 1::2]
lines = LineCollection([list(zip(x,y)) for x,y in zip(xs, ys)], label='data_a')
f, ax = plt.subplots(1, 1)
ax.add_collection(lines)
ax.legend()
ax.set_xlim([xs.min(), xs.max()]) # have to set manually
ax.set_ylim([ys.min(), ys.max()])
plt.show()

这导致以下输出:

【讨论】:

    【解决方案4】:

    所以使用will的建议和另一个问题here,我把我的补救措施留在这里

    handles, labels = plt.gca().get_legend_handles_labels()
    i =1
    while i<len(labels):
        if labels[i] in labels[:i]:
            del(labels[i])
            del(handles[i])
        else:
            i +=1
    
    plt.legend(handles, labels)
    

    新的情节看起来像,

    【讨论】:

      【解决方案5】:

      一个低技术的解决方案是进行两次剧情调用。一个绘制你的数据,第二个只绘制手柄:

      a = np.array([[ 3.57,  1.76,  7.42,  6.52],
                    [ 1.57,  1.2 ,  3.02,  6.88],
                    [ 2.23,  4.86,  5.12,  2.81],
                    [ 4.48,  1.38,  2.14,  0.86],
                    [ 6.68,  1.72,  8.56,  3.23]])
      
      plt.plot(a[:,::2].T, a[:, 1::2].T, 'r')
      plt.plot([],[], 'r', label='data_a')
      
      plt.legend(loc='best')
      

      结果如下:

      【讨论】:

        【解决方案6】:

        我会这样做:

        for i in range(len(a)):
          plt.plot(a[i,::2].T, a[i, 1::2].T, 'r', label='data_a' if i==0 else None)
        

        【讨论】:

        • 当我尝试它时这不起作用。调用plt.legend()时抛出No handles with labels found to put in legend.
        • 完整代码为:import numpy as np import matplotlib.pyplot as plt a = np.array([[ 3.57, 1.76, 7.42, 6.52], [ 1.57, 1.2 , 3.02, 6.88], [ 2.23, 4.86, 5.12, 2.81], [ 4.48, 1.38, 2.14, 0.86], [ 6.68, 1.72, 8.56, 3.23]]) for i in range(len(a)): plt.plot(a[i,::2].T, a[i, 1::2].T, 'r', label='data_a' if i==0 else None) plt.legend(loc='best') plt.savefig('test_plot_legend.png')
        【解决方案7】:

        删除重复项最简单和最 Pythonic 的方法是使用保证唯一的 dict 键。这也确保我们只对每个 (handle, label) 对进行一次迭代。

        handles, labels = plt.gca().get_legend_handles_labels()
        
        # labels will be the keys of the dict, handles will be values
        temp = {k:v for k,v in zip(labels, handles)}
        
        plt.legend(temp.values(), temp.keys(), loc='best')
        

        【讨论】:

        • 100% 这应该是答案。简单,pythonic,并生成所需的结果。
        【解决方案8】:

        我找到了解决这个问题的捷径:

        a = np.array([[ 3.57,  1.76,  7.42,  6.52],
                      [ 1.57,  1.2 ,  3.02,  6.88],
                      [ 2.23,  4.86,  5.12,  2.81],
                      [ 4.48,  1.38,  2.14,  0.86],
                      [ 6.68,  1.72,  8.56,  3.23]])
        
        p1=plt.plot(a[:,::2].T, a[:, 1::2].T, color='r')
        plt.legend([p1[0]],['data_a'],loc='best')
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-10-09
          • 1970-01-01
          • 2016-12-17
          • 2011-10-21
          • 1970-01-01
          • 2021-11-17
          • 1970-01-01
          • 2018-04-14
          相关资源
          最近更新 更多