我刚刚将 pandas 从 0.17.1 更新到 0.21.0 以利用一些新功能,并遇到了与 matplotlib 的兼容性问题(我也将其更新到最新的 2.1.0)。特别是 Timestamp 对象似乎发生了重大变化。
我碰巧有另一台机器仍在运行旧版本的 pandas(0.17.1)/matplotlib(1.5.1),我用来比较差异:
两个版本都显示我的 DataFrame 索引是dtype='datetime64[ns]
DatetimeIndex(['2017-03-13', '2017-03-14', ... '2017-11-17'], type='datetime64[ns]', name='dates', length=170, freq=None)
但是打电话的时候type(df.index[0])
, 0.17.1 给出pandas.tslib.Timestamp
0.21.0 给出pandas._libs.tslib.Timestamp
.
当绘图时df.index
作为 x 轴:
plt.plot(df.index, df['data'])
matplotlibs 默认将 x 轴标签格式化为 pandas 0.17.1 的日期,但无法识别 pandas 0.21.0 的日期,并且仅给出原始数字1.5e18
(纪元时间,以纳秒为单位)。
我还有一个自定义的光标,通过使用报告在图表上单击的位置matplotlib.dates.DateFormatter
对于 0.21.0 失败的 x 值:
OverflowError: signed integer is greater than maximum
我可以在调试中看到,对于 0.17.1,报告的 x 值约为 736500(即自 0 年以来的天数),而对于 0.21.0,则约为 1.5e18(即纳秒纪元时间)。
我对 matplotlib 和 pandas 之间的兼容性中断感到惊讶,因为它们显然被大多数人一起使用。我在为新版本调用上面的绘图函数的方式中是否遗漏了一些东西?
Update正如我上面提到的,我更喜欢直接打电话plot
使用给定的坐标区对象,但只是为了它,我尝试调用 DataFrame 本身的绘图方法df.plot()
。完成此操作后,所有后续绘图都会正确识别时间戳在同一个 python 会话中。这就好像设置了一个环境变量,因为我可以重新加载另一个 DataFrame 或创建另一个轴subplots
并且没有在哪里1.5e18
出现。正如最新的 pandas 文档所说,这确实闻起来像一个错误pandas https://pandas.pydata.org/pandas-docs/stable/visualization.html#basic-plotting-plot:
The plot method on Series and DataFrame is just a simple wrapper around plt.plot()
但显然它对 python 会话做了一些事情,以便后续的绘图正确处理时间戳索引。
事实上,只需运行上面的 pandas 链接中的示例即可:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
取决于是否ts.plot()
无论是否被调用,下面的图要么正确地将 x 轴格式设置为日期,要么不正确:
plt.plot(ts.index,ts)
plt.show()
一旦调用成员图,随后调用plt.plot
新的 Series 或 DataFrame 将正确自动格式化,无需再次调用成员绘图方法。