【问题标题】:pandas 0.21.0 Timestamp compatibility issue with matplotlibpandas 0.21.0 时间戳与 matplotlib 的兼容性问题
【发布时间】:2018-05-04 10:02:18
【问题描述】:

我刚刚将 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(以纳秒为单位的纪元时间)。

我还有一个自定义光标,通过在 x 值上使用 matplotlib.dates.DateFormatter 报告点击位置,对于 0.21.0 失败:

OverflowError: signed integer is greater than maximum

我可以在调试中看到报告的 x 值在 0.17.1 时约为 736500(即自第 0 年以来的天数),但在 0.21.0 时约为 1.5e18(即纳秒纪元时间)。

我对 matplotlib 和 pandas 之间的兼容性中断感到惊讶,因为它们显然被大多数人一起使用。我在为较新版本调用上面的绘图函数的方式上是否遗漏了什么?

更新 如上所述,我更喜欢使用给定的轴对象直接调用plot,但只是为了它,我尝试调用 DataFrame 本身的 plot 方法df.plot()。完成此操作后,所有后续绘图都会正确识别时间戳在同一 python 会话中。就好像设置了一个环境变量,因为我可以重新加载另一个 DataFrame 或使用subplots 创建另一个轴,而1.5e18 没有出现在哪里。正如最新的 pandas 文档所说的 pandas,这真的闻起来像一个错误:

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

一旦调用了成员 plot,随后在新系列或 DataFrame 上调用 plt.plot 将正确自动格式化,而无需再次调用成员 plot 方法。

【问题讨论】:

    标签: python pandas matplotlib plot


    【解决方案1】:

    issue with pandas datetimes and matplotlib 来自最近发布的 pandas 0.21,它不再在导入时注册其转换器。一旦您(在 pandas 中)使用这些转换器一次,它们就会被注册并被 matplotlib 自动使用。

    一种解决方法是手动注册它们,

    import pandas.plotting._converter as pandacnv
    pandacnv.register()
    

    无论如何,这个问题在 pandas 和 matplotlib 方面都是众所周知的,所以下一个版本会有某种修复。 Pandas 在即将发布的版本中考虑readding the register。所以这个问题可能只是暂时存在。一个选项也是恢复到不应该发生这种情况的 pandas 0.20.x。

    更新:这不再是当前版本的 matplotlib (2.2.2)/pandas(0.23.1) 的问题,而且很可能是自 2017 年 12 月左右发布的许多版本,当时已修复。

    更新 2: 从 pandas 0.24 或更高版本开始,推荐的注册转换器的方法是

    from pandas.plotting import register_matplotlib_converters
    register_matplotlib_converters()
    

    或者如果pandas 已经导入为pd

    pd.plotting.register_matplotlib_converters()
    

    【讨论】:

    • 你是对的,我在 pandas github 上打开的问题上得到了类似的响应。我正在尝试使用的 pandas 网站发布一个稍微正式一点的方法。
    • 你在这里也试过这个方法吗?您能否报告它是否有效(理论上应该,但我无法尝试,如果不是,我最好删除答案)。
    • 我确实尝试过,它也奏效了——我最终使用了 pandas 网站上的两行代码,因为它们更有可能成为未来的证明。
    • 此问题已于 2019 年 5 月 13 日返回。我正在使用 matplotlib (3.0.3) 和 pandas (0.24.2)。显式注册转换器确实可以解决它。希望这可以长期解决。
    • @Ben 是的,我用目前推荐的注册转换器的方式更新了答案。
    【解决方案2】:

    在pandas github上打开issue后,我了解到这确实是pandas和matplotlib之间关于自动注册单位转换器的已知issue。事实上,它被列在我以前没见过的新功能page 上,以及注册转换器的正确方法:

    from pandas.tseries import converter
    converter.register() 
    

    这也是第一次在 Series 或 DataFrame 上调用成员 plot 方法时完成,这解释了我在上面观察到的情况。

    这样做似乎是为了让 matplotlib 实现对 pandas datetime 的一些基本支持,但实际上某种弃用警告可能对这种中断有用。然而,在 matplotlib 真正实现这种支持(或某种惰性注册机制)之前,实际上我总是将这两行放在 pandas 导入中。所以我不确定为什么 pandas 会在 matplotlib 端准备好之前禁用导入时的自动注册。

    【讨论】:

      【解决方案3】:

      看起来这个问题已经在 matplotlib 的未来版本中得到修复。

      尝试运行“pip install --upgrade matplotlib”。

      我遇到了同样的问题“AttributeError: 'numpy.datetime64' object has no attribute 'toordinal'”。升级包 matplotlib 时已修复。

      【讨论】:

        猜你喜欢
        • 2021-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-15
        • 2014-08-22
        • 2016-08-15
        • 2011-05-04
        相关资源
        最近更新 更多