当我使用matplotlib的DateFormatter来格式化x轴上的日期时,为什么会出现“python int too large to convert to C long”的错误?

6

参考 这个答案中的DateFormatter用法,我尝试使用pandas 0.15.0和matplotlib 1.4.2绘制时间序列并将x轴标签设置为年份:

import datetime as dt
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas.io.data as pdio
import scipy as sp

t1 = dt.datetime(1960, 1, 1)
t2 = dt.datetime(2014, 6, 1)
data = pdio.DataReader("GS10", "fred", t1, t2).resample("Q", how=sp.mean)

fig, ax1 = plt.subplots()
ax1.plot(data.index, data.GS10)
ax1.set_xlabel("Year")
ax1.set_ylabel("Rate (%)")
ax1.xaxis.set_major_formatter(mpl.dates.DateFormatter("%Y"))
fig.suptitle("10-yr Treasury Rate", fontsize=14)

fig.savefig('test.eps')

最后一行抛出了一个错误:OverflowError: Python int太大,无法转换为C long,并附带以下追踪信息:
C:\Anaconda3\lib\site-packages\IPython\core\formatters.py:239: FormatterWarning: Exception in image/png formatter: Python int too large to convert to C long FormatterWarning, Traceback (most recent call last): File "", line 1, in runfile('D:/username/latex_template/new_pandas_example.py', wdir='D:/username/latex_template') File "C:\Anaconda3\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 580, in runfile execfile(filename, namespace) File "C:\Anaconda3\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 48, in execfile exec(compile(open(filename, 'rb').read(), filename, 'exec'), namespace) File "D:/username/latex_template/new_pandas_example.py", line 18, in fig.savefig('test.eps') File "C:\Anaconda3\lib\site-packages\matplotlib\figure.py", line 1470, in savefig self.canvas.print_figure(*args, **kwargs) File "C:\Anaconda3\lib\site-packages\matplotlib\backend_bases.py", line 2194, in print_figure **kwargs) File "C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_ps.py", line 992, in print_eps return self._print_ps(outfile, 'eps', *args, **kwargs) File "C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_ps.py", line 1020, in _print_ps **kwargs) File "C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_ps.py", line 1110, in _print_figure self.figure.draw(renderer) File "C:\Anaconda3\lib\site-packages\matplotlib\artist.py", line 59, in draw_wrapper draw(artist, renderer, *args, **kwargs) File "C:\Anaconda3\lib\site-packages\matplotlib\figure.py", line 1079, in draw func(*args) File "C:\Anaconda3\lib\site-packages\matplotlib\artist.py", line 59, in draw_wrapper draw(artist, renderer, *args, **kwargs) File "C:\Anaconda3\lib\site-packages\matplotlib\axes_base.py", line 2092, in draw a.draw(renderer) File "C:\Anaconda3\lib\site-packages\matplotlib\artist.py", line 59, in draw_wrapper draw(artist, renderer, *args, **kwargs) File "C:\Anaconda3\lib\site-packages\matplotlib\axis.py", line 1114, in draw ticks_to_draw = self._update_ticks(renderer) File "C:\Anaconda3\lib\site-packages\matplotlib\axis.py", line 957, in _update_ticks tick_tups = [t for t in self.iter_ticks()] File "C:\Anaconda3\lib\site-packages\matplotlib\axis.py", line 957, in tick_tups = [t for t in self.iter_ticks()] File "C:\Anaconda3\lib\site-packages\matplotlib\axis.py", line 905, in iter_ticks for i, val in enumerate(majorLocs)] File "C:\Anaconda3\lib\site-packages\matplotlib\axis.py", line 905, in for i, val in enumerate(majorLocs)] File "C:\Anaconda3\lib\site-packages\matplotlib\dates.py", line 411, in call dt = num2date(x, self.tz) File "C:\Anaconda3\lib\site-packages\matplotlib\dates.py", line 345, in num2date return _from_ordinalf(x, tz) File "C:\Anaconda3\lib\site-packages\matplotlib\dates.py", line 225, in _from_ordinalf dt = datetime.datetime.fromordinal(ix) OverflowError: Python int too large to convert to C long

我在这里使用 DateFormatter 是否有误?如何轻松地将年份(或任何时间格式,因为我的时间序列可能不同)放在 matplotlib 图形的 x 轴上?

1个回答

12

这是pandas 0.15版本中的“回归”问题(由于索引重构引起),请参见https://github.com/matplotlib/matplotlib/issues/3727https://github.com/pydata/pandas/issues/8614,但在0.15.1中已经修复。


简单来说:matplotlib现在将pandas索引视为datetime64[ns]值的数组(实际上是非常大的int64s),而不是以前版本的pandas中的Timestamps数组(它们是datetime.datetime的子类,并且可以被matplotlib处理)。因此,根本原因是matplotlib没有将datetime64作为日期值处理,而是将其作为整数处理。

对于pandas 0.15.0(但最好升级到新版本),有两个可能的解决方法

  • 注册datetime64类型,这样它也会被matplotlib视为日期:

    units.registry[np.datetime64] = pd.tseries.converter.DatetimeConverter()
    
  • 或者使用to_pydatetime方法将带有datetime64值的DatetimeIndex转换为datetime.datetime值的数组,然后绘制它:

  • ax1.plot(data.index.to_pydatetime(), data.GS10)
    

相关问题: 在pandas 0.15中,使用matplotlib绘制DateTimeIndex时,与0.14相比会创建错误的刻度


感谢您的答案;您说得对,这个问题已经在 pandas 0.15.1 中修复了。我今天早上刚刚更新了,我的原始代码示例现在可以按预期工作了。(也许您可以编辑一下您的问题?) - Michael A
1
是的,这个问题将在即将发布的0.21.1版本中得到修复(请参见http://pandas-docs.github.io/pandas-docs-travis/whatsnew.html#restore-matplotlib-datetime-converter-registration)。 - joris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接