Python 为什么在进行多个绘图时,绘图图例会丢失标记?

Python 为什么在进行多个绘图时,绘图图例会丢失标记?,python,pandas,matplotlib,statsmodels,Python,Pandas,Matplotlib,Statsmodels,简单的熊猫图产生预期输出,图例上有一个圆圈标记: 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

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

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

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

但是,如果我为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()

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


是什么导致第二种情况下的图例丢失其主绘图的圆标记?

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

由于您正在绘制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
,使用
matplotlib.pyplot.legend()
,导入matplotlib.pyplot作为plt

,现在您知道正在绘制3个不同的图形(原始速率、拟合值和预测),对吗?另外,通常,
matplotlib.pyplot
按如下方式导入
import matplotlib.pyplot as plt
。谢谢。我不清楚为什么要修复它:这是matplotlib中的一个bug,还是仅仅是一个设计限制?无论如何,我很高兴:-)我确实看到了使用模块别名的惯例,我个人并不喜欢它;我发现冗长的语法更容易解释。我唯一一次看到使用别名的好处是避免由于性能原因加载整个模块。我无法回答,但这可能是一个有趣的问题。当然,任何最适合你的都可以。:)请记住,如果您在项目上与其他人协作,他们可能希望看到使用的约定(特别是库文档中使用的约定)。