【问题标题】:redundant legends in python matplot libpython matplotlib中的冗余图例
【发布时间】:2018-06-21 19:31:40
【问题描述】:

我正在绘制两个条件并且只想要两个图例。但是我的数据中有重复,每个重复我都得到一个单独的图例。为什么?如果之前已经解决了这个问题,我深表歉意,但我在这方面花费了令人尴尬的时间,而且我发现的大部分内容对于我的情况来说似乎过于复杂。任何帮助,将不胜感激。

import matplotlib.pyplot as plt
import pandas as pd

#####read and organize data
alldata = pd.read_csv('Fig_1.csv')

CondtionA = list(zip(alldata.iloc[:,1],alldata.iloc[:,2]))
ConditionB = list(zip(alldata.iloc[:,7],alldata.iloc[:,8]))

### make the figure
fig, ax = plt.subplots()

plt.plot(alldata['Temperature'],ConditionA,linewidth = 1,c='k', linestyle = '--',label = 'ConditionA')
plt.plot(alldata['Temperature'],ConditionB,linewidth = 1,c='k', label = "ConditonB")
ax.legend(numpoints=1)

plt.show()

【问题讨论】:

  • 了解 Fig_1.csv 的样子会有所帮助 (*.com/help/mcve)
  • @Noah 你是对的,这应该是问题的一部分。但由于显然 OP 没有意识到这一点,我在下面的答案中创建了一个 minimal reproducible example,您可以使用它来重现这种情况。
  • @ImportanceOfBeingErnest 你的回答已经超越了你,我为你的好意和有用的回答投了你的票:)

标签: python matplotlib legend


【解决方案1】:

a) 使用返回的行

您应该能够仅从每个 plot 调用的返回行的第一项创建图例。

lines1 = plt.plot(...)
lines2 = plt.plot(...)

plt.legend(handles=(lines1[0], lines2[0]), labels=("Label A", "Label B"))

这里的缺点是您需要再次手动命名标签。

b) 每隔一秒选择一次图例句柄/标签

如果不希望这样做,但如果反过来您知道要使用最初创建的图例中的每一秒句柄和标签,则可以通过get_legend_handles_labels() 获取这些句柄和标签。

handles, labels = plt.gca().get_legend_handles_labels()
plt.legend(handles[::2], labels[::2])


可重现的例子:
import numpy as np; np.random.seed(10)
import matplotlib.pyplot as plt

x=np.arange(10)

a = np.cumsum(np.cumsum(np.random.randn(10,2), axis=0), axis=1)
b = np.cumsum(np.cumsum(np.random.randn(10,2), axis=0), axis=1)+6


lines1 = plt.plot(x,a, label="Label A", color="k")
lines2 = plt.plot(x,b, label="Label B", color="k", linestyle="--")

# either:
plt.legend(handles=(lines1[0], lines2[0]), labels=("Label A", "Label B"))

# or alternatively:
handles, labels = plt.gca().get_legend_handles_labels()
plt.legend(handles[::2], labels[::2])

plt.show()

【讨论】:

  • 我明天需要多玩这个。我试了一下,得到了一个有趣的结果,其中图例标题为“---Line2D(ConditionA)”和“---Line2D(ConditionB)”。不确定“Line2D”部分来自哪里......所以还没有,但这种方法听起来很合理。再次感谢您的帮助,我会在有时间进一步研究时回复。
  • 我明白了。我花时间制作了minimal reproducible example 并提供了两个经过测试的解决方案。请注意,创建这样的示例很烦人,这应该是提问者的职责,而不是回答者的职责。
  • 我很抱歉没有包含数据,现在看看我是如何无意中让人们更难回答我提出的问题的。将来我会确保遵守最小、完整的可验证标准。感谢您超越。我能够得到两个工作的答案。再次感谢您的帮助,我真的很感激。
【解决方案2】:

如果你删除

ax.legend(numpoints=1)

并添加

plt.legend(handles=[p1,p2], bbox_to_anchor=(0.75, 1), loc=2, borderaxespad=0.)

你只会得到一个图例。

所以你的代码看起来像

import matplotlib.pyplot as plt
import pandas as pd

#####read and organize data
alldata = pd.read_csv('Fig_1.csv')

CondtionA = list(zip(alldata.iloc[:,1],alldata.iloc[:,2]))
ConditionB = list(zip(alldata.iloc[:,7],alldata.iloc[:,8]))

### make the figure
fig, ax = plt.subplots()

p1 = plt.plot(alldata['Temperature'],ConditionA,linewidth = 1,c='k', linestyle = '--',label = 'ConditionA')
p2 = plt.plot(alldata['Temperature'],ConditionB,linewidth = 1,c='k', label = "ConditonB")
#ax.legend(numpoints=1)
plt.legend(handles=[p1,p2], bbox_to_anchor=(0.75, 1), loc=2, borderaxespad=0.)


plt.show()

【讨论】:

  • 我认为问题不在于留下部分绘制的数据,而是将数据绘制成如图所示,但限制图例不显示重复项。
  • 感谢您花时间考虑我的问题,但正如@ImportanceOfBeingErnest 建议的那样,我希望在存在条件时保留两个副本,但避免多余的图例。
  • 更新答案的问题是图例标题是按顺序应用于数据的,因此“条件A”和“条件B”图例显示相同的虚线。
  • 你可以试试这个。您在哪里指定哪些行应该显示图例以及在哪里。 plt.legend(handles=[p1,p2], bbox_to_anchor=(0.75, 1), loc=2, borderaxespad=0.)