【问题标题】:How do I assign multiple labels at once in matplotlib?如何在 matplotlib 中一次分配多个标签?
【发布时间】:2012-07-14 06:38:13
【问题描述】:

我有以下数据集:

x = [0, 1, 2, 3, 4]
y = [ [0, 1, 2, 3, 4],
      [5, 6, 7, 8, 9],
      [9, 8, 7, 6, 5] ]

现在我用:

import matplotlib.pyplot as plt
plt.plot(x, y)

但是,我想使用此命令标记 3 个 y 数据集,这会在调用 .legend() 时引发错误:

lineObjects = plt.plot(x, y, label=['foo', 'bar', 'baz'])
plt.legend()

File "./plot_nmos.py", line 33, in <module>
  plt.legend()
...
AttributeError: 'list' object has no attribute 'startswith'

当我检查lineObjects:

>>> lineObjects[0].get_label()
['foo', 'bar', 'baz']
>>> lineObjects[1].get_label()
['foo', 'bar', 'baz']
>>> lineObjects[2].get_label()
['foo', 'bar', 'baz']

问题

仅使用.plot() 方法是否有一种优雅的方式来分配多个标签?

【问题讨论】:

    标签: matplotlib label legend


    【解决方案1】:

    您可以遍历您的线对象列表,因此标签是单独分配的。内置pythoniter函数的示例:

    lineObjects = plt.plot(x, y)
    plt.legend(iter(lineObjects), ('foo', 'bar', 'baz'))`
    

    编辑: 更新到 matplotlib 1.1.1 后,它看起来像 plt.plot(x, y),其中 y 作为列表列表(由问题作者提供),不起作用了。在将 y 传递为 numpy.array (假设 (numpy)[http://numpy.scipy.org/] 之前已导入)之后,仍然可以考虑在不迭代 y 数组的情况下绘制一步。

    在这种情况下,使用plt.plot(x, y)(如果 2D y 数组中的数据排列为列 [axis 1])或plt.plot(x, y.transpose())(如果 2D y 数组中的数据排列为行 [axis 0] )

    编辑 2: 正如@pelson 所指出的(参见下面的评论),iter 函数是不必要的,一个简单的 plt.legend(lineObjects, ('foo', 'bar', 'baz')) 可以完美运行

    【讨论】:

    • 这对用户不起作用(提供的 x 和 y 不能在没有迭代步骤的情况下同时绘制)。即使绘图确实有效,假设 lineObjects 是一个列表(或元组等),iter 函数也是不必要的。
    • @pelson 确实,看起来它不适用于新的 matplotlib 版本。但是,如果 x 和 y 是 numpy arrays,您仍然可以使用 plot(x, y.transpose()) 一步绘制它们。在这种情况下,带有 iter 函数的语法仍然有效。
    • 你说得对,我不知道一个简单的转置就能解决它。 (numpy 数组可以通过 .T 转置,即y.T)。但是,我仍然坚持认为您的 iter 函数在这里是不必要的(尽管它显然仍然有效)。
    • @pelson 你是对的,一个简单的legend(lineObjects, ('foo', 'bar', 'baz')) 完美工作。我不知道为什么我在这里添加了iter 函数...谢谢
    【解决方案2】:

    不可能直接将这两个数组相互绘制(至少版本为 1.1.1),因此您必须循环遍历您的 y 数组。我的建议是同时遍历标签:

    import matplotlib.pyplot as plt
    
    x = [0, 1, 2, 3, 4]
    y = [ [0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [9, 8, 7, 6, 5] ]
    labels = ['foo', 'bar', 'baz']
    
    for y_arr, label in zip(y, labels):
        plt.plot(x, y_arr, label=label)
    
    plt.legend()
    plt.show()
    

    编辑:@gcalmettes 指出,作为 numpy 数组,可以同时绘制所有线(通过转置它们)。有关详细信息,请参阅@gcalmettes 答案和 cmets。

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题,现在我找到了一个最简单的解决方案!希望这对你来说还不算太晚。没有迭代器,只需将结果分配给结构...

      from numpy import *
      from matplotlib.pyplot import *
      from numpy.random import *
      
      a = rand(4,4)
      a
      >>> array([[ 0.33562406,  0.96967617,  0.69730654,  0.46542408],
         [ 0.85707323,  0.37398595,  0.82455736,  0.72127002],
         [ 0.19530943,  0.4376796 ,  0.62653007,  0.77490795],
         [ 0.97362944,  0.42720348,  0.45379479,  0.75714877]])
      
      [b,c,d,e] = plot(a)
      legend([b,c,d,e], ["b","c","d","e"], loc=1)
      show()
      

      看起来像这样:

      【讨论】:

        【解决方案4】:

        目前最好的解决方案是:

        lineObjects = plt.plot(x, y)  # y describes 3 lines
        plt.legend(['foo', 'bar', 'baz'])
        

        【讨论】:

          【解决方案5】:

          您可以在绘制曲线时给出标签

          import pylab as plt
          
          x = [0, 1, 2, 3, 4]
          y = [ [0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [9, 8, 7, 6, 5] ]
          labels=['foo', 'bar', 'baz']
          colors=['r','g','b']
          
          # loop over data, labels and colors
          for i in range(len(y)):
              plt.plot(x,y[i],'o-',color=colors[i],label=labels[i])
          
          plt.legend()
          plt.show()
          

          【讨论】:

          • 从风格上讲,直接遍历 y 列表可能更符合 Python 风格,同时压缩其他列表(请参阅我的回答)。如果你真的必须这样做,那么最好使用 enumerate(...),而不是使用 range(len(...))。不过你仍然得到 +1 :-)
          • 感谢您指出这一点。在这种情况下,izip、zip 或枚举更有意义。
          【解决方案6】:

          在 numpy 矩阵图的情况下,为每列一次分配多个图例

          我想根据绘制一个包含两列的矩阵来回答这个问题。

          假设你有一个两列矩阵Ret

          然后可以使用此代码一次分配多个标签

          import pandas as pd, numpy as np, matplotlib.pyplot as plt
          pd.DataFrame(Ret).plot()
          
          plt.xlabel('time')
          plt.ylabel('Return')
          plt.legend(['Bond Ret','Equity Ret'], loc=0)
          plt.show()
          

          希望对你有帮助

          【讨论】:

            【解决方案7】:

            当我在数组的列中有一组 x 值和多个 y 值时,我经常会遇到这个问题。我真的不想在循环中绘制数据,多次调用ax.legend/plt.legend 并不是一个真正的选择,因为我想绘制其他东西,通常是同样令人讨厌的格式。

            很遗憾,plt.setp 在这里没有帮助。在较新版本的 matplotlib 中,它只是将整个列表/元组转换为字符串,并将整个内容作为标签分配给所有行。

            因此,我制作了一个实用函数来包装对 ax.plot/plt.plot 的调用:

            def set_labels(artists, labels):
                for artist, label in zip(artists, labels):
                    artist.set_label(label)
            

            你可以这样称呼它

            x = np.arange(5)
            y = np.random.ranint(10, size=(5, 3))
            
            fig, ax = plt.subplots()
            set_labels(ax.plot(x, y), 'ABC')
            

            这样您就可以将所有正常的艺术家参数指定为plot,而无需查看代码中的循环。另一种方法是将整个调用 plot 放入一个仅解包标签的实用程序中,但这需要大量重复才能弄清楚如何解析多个数据集,可能具有不同数量的列,并分布在多个参数中,关键字或其他。

            【讨论】:

              【解决方案8】:

              我使用以下内容显示数据框的标签,而不使用数据框图:

              lines_ = plot(df)
              legend(lines_, df.columns) # df.columns is a list of labels
              

              【讨论】:

                【解决方案9】:

                如果您使用的是 DataFrame,您还可以遍历要绘制的数据的列:

                # Plot figure
                fig, ax = plt.subplots(figsize=(5,5))
                # Data
                data = data
                # Plot
                for i in data.columns:
                    _ = ax.plot(data[i], label=i)
                    _ = ax.legend() 
                plt.show()
                

                【讨论】:

                • 不需要为每个单独的列调用 ax.legend()。因为标签是在绘制 ax.legend() 的单个调用期间设置的,就在 plt.show() 足够之前。
                猜你喜欢
                • 1970-01-01
                • 2021-07-03
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-08-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多