【问题标题】:Why does the plot legend lose markers when doing multiple plots?为什么做多个情节时情节图例会丢失标记?
【发布时间】:2019-07-14 10:29:15
【问题描述】:

一个简单的熊猫图会产生预期的输出,图例上有一个圆形标记:

import io
import pandas
import matplotlib
import statsmodels
import matplotlib.pyplot
import statsmodels.tsa.api

cause = "Malignant neoplasms"
csv_data = """Year,CrudeRate
1999,197.0
2000,196.5
2001,194.3
2002,193.7
2003,192.0
2004,189.2
2005,189.3
2006,187.6
2007,186.9
2008,186.0
2009,185.0
2010,186.2
2011,185.1
2012,185.6
2013,185.0
2014,185.6
2015,185.4
2016,185.1
2017,183.9
"""

df = pandas.read_csv(io.StringIO(csv_data), index_col="Year", parse_dates=True)
df.plot(color="black", marker="o", legend=True)
matplotlib.pyplot.show()

请注意,“CrudeRate”图例项是一条带有正确圆圈标记的直线。

但是,如果我为 Holt 线性指数平滑函数添加一些额外的图,则图例会丢失圆形标记:

import io
import pandas
import matplotlib
import statsmodels
import matplotlib.pyplot
import statsmodels.tsa.api

cause = "Malignant neoplasms"
csv_data = """Year,CrudeRate
1999,197.0
2000,196.5
2001,194.3
2002,193.7
2003,192.0
2004,189.2
2005,189.3
2006,187.6
2007,186.9
2008,186.0
2009,185.0
2010,186.2
2011,185.1
2012,185.6
2013,185.0
2014,185.6
2015,185.4
2016,185.1
2017,183.9
"""

def ets_non_seasonal(df, color, predict, exponential=False, damped=False, damping_slope=0.98):
  fit = statsmodels.tsa.api.Holt(df, exponential=exponential, damped=damped).fit(damping_slope=damping_slope if damped else None)
  fit.fittedvalues.plot(color=color, style="--")
  title = "ETS(A,{}{},N)".format("M" if exponential else "A", "_d" if damped else "")
  forecast = fit.forecast(predict).rename("${}$".format(title))
  forecast.plot(color=color, legend=True, style="--")

df = pandas.read_csv(io.StringIO(csv_data), index_col="Year", parse_dates=True)
df.plot(color="black", marker="o", legend=True)
ets_non_seasonal(df, "red", 5, exponential=False, damped=False, damping_slope=0.98)
matplotlib.pyplot.show()

请注意,“CrudeRate”图例项只是一条没有圆圈标记的直线。

是什么导致第二种情况下的图例失去了主要情节的圆形标记?

【问题讨论】:

  • 使用 matplotlib.pyplot.legend(),现在您知道您正在绘制 3 个不同的图表(粗利率、拟合值和您的预测),对吗?此外,一般情况下,matplotlib.pyplot 导入如下import matplotlib.pyplot as plt

标签: python pandas matplotlib statsmodels


【解决方案1】:

matplotlib.pyplot.show() 之前使用matplotlib.pyplot.legend() 将解决您的问题。

由于您要绘制 3 个图表,并且据我了解,您只需要图例中的 2 个标签,因此我们将 label='_nolegend_' 传递给 fit.fittedvalues.plot()。如果我们不这样做,我们将在图例中有第三个标签,其值为None

import io
import pandas
import matplotlib
import statsmodels
import matplotlib.pyplot
import statsmodels.tsa.api

cause = "Malignant neoplasms"
csv_data = """Year,CrudeRate
1999,197.0
2000,196.5
2001,194.3
2002,193.7
2003,192.0
2004,189.2
2005,189.3
2006,187.6
2007,186.9
2008,186.0
2009,185.0
2010,186.2
2011,185.1
2012,185.6
2013,185.0
2014,185.6
2015,185.4
2016,185.1
2017,183.9
"""

def ets_non_seasonal(df, color, predict, exponential=False, damped=False, damping_slope=0.98):
  fit = statsmodels.tsa.api.Holt(df, exponential=exponential, damped=damped).fit(damping_slope=damping_slope if damped else None)
  fit.fittedvalues.plot(color=color, style="--", label='_nolegend_')
  title = "ETS(A,{}{},N)".format("M" if exponential else "A", "_d" if damped else "")
  forecast = fit.forecast(predict).rename("${}$".format(title))
  forecast.plot(color=color, legend=True, style="--")

df = pandas.read_csv(io.StringIO(csv_data), index_col="Year", parse_dates=True)
df.plot(color="black", marker="o", legend=True)
ets_non_seasonal(df, "red", 5, exponential=False, damped=False, damping_slope=0.98)
matplotlib.pyplot.legend()
matplotlib.pyplot.show()

附带说明,为了让您更轻松地编写代码,导入matplotlib.pyplot 是一个很好的做法,如下import matplotlib.pyplot as plt

【讨论】:

  • 谢谢。我不清楚为什么要修复它:这是 matplotlib 中的错误,还是只是设计限制?无论如何,我很高兴 :-) 我确实看到了使用模块别名的惯例,但我个人并不喜欢它;我发现冗长的语法更不言自明。我看到使用别名的唯一好处是避免出于性能原因加载整个模块。
  • 我无法回答,但这可能是一个有趣的问题。当然,任何最适合您的方法。 :) 请记住,如果您与其他人在项目上合作,他们可能希望看到使用的约定(尤其是库文档中使用的约定)。
猜你喜欢
  • 2021-12-26
  • 2022-12-06
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 2020-03-25
  • 1970-01-01
  • 2021-11-03
  • 2021-05-04
相关资源
最近更新 更多