如何在 matplotlib 中一次分配多个标签?

我有以下数据集:

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()方法就可以优雅地分配多个标签吗?

132049 次浏览

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

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

enter image description here

您可以在行对象列表上迭代,因此标签是单独分配的。内置 python iter函数的一个示例:

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

编辑: 在更新到 matplotlib 1.1.1之后,使用 y 作为列表列表的 plt.plot(x, y)(如问题的作者所提供的)看起来不再工作了。在将 y 作为 numpy.array传递之后(假设(numpy)[ http://numpy.scipy.org/]与之前导入的一样) ,仍然可以考虑不对 y 数组进行迭代的一步绘图。

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

编辑2: 正如@pelson 所指出的(参见下面的注释) ,iter函数是不必要的,一个简单的 plt.legend(lineObjects, ('foo', 'bar', 'baz'))工作得很完美

不可能直接将这两个数组重新绘制到彼此之间(至少版本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 的回答和评论。

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

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

看起来像这样: enter image description here

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

我想在绘制一个有两列的矩阵的基础上回答这个问题。

假设你有一个2列矩阵 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()

希望这个能帮上忙

我使用了以下方法来显示数据帧的标签,而没有使用数据帧图:

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

目前最好的解决办法是:

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

如果使用 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()

当我在一个数组的列中有一组 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,而不必看到代码中的循环。另一种方法是将整个绘图调用放入一个实用程序中,该实用程序只是解包标签,但这将需要大量的重复,以弄清如何解析多个数据集,可能具有不同数量的列,并分散在多个参数、关键字或其他方面。