【问题标题】:MatPlotLib, datetimes, and TypeError: ufunc 'isfinite' not supported for the input types…MatPlotLib、日期时间和 TypeError:输入类型不支持 ufunc 'isfinite'...
【发布时间】:2018-01-08 00:29:16
【问题描述】:

这是一小段代码,它在图表的两条线之间产生一个填充区域:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(0.0, 2, 0.01)
y1 = np.sin(2 * np.pi * x)
y2 = 1.2 * np.sin(4 * np.pi * x)

fig, ax1 = plt.subplots(1, 1, sharex=True)

# Test support for masked arrays.
ax1.fill_between(x, 0, y1)
ax1.set_ylabel('between y1 and 0')
y2 = np.ma.masked_greater(y2, 1.0)
ax1.plot(x, y1, x, y2, color='black')
ax1.fill_between(
    x, y1, y2, where=y2 >= y1,
    facecolor='green',
    interpolate=True)
ax1.fill_between(x, y1, y2, where=y2 <= y1, facecolor='red', interpolate=True)
ax1.set_title('Now regions with y2>1 are masked')

# Show the plot.
plt.show()

看起来像这样:

现在,更改开始以使 x 现在是日期时间对象的集合,如下所示:

import datetime

x1 = np.arange(0.0, 2, 0.01)
now = np.datetime64(datetime.datetime.now())
x = np.array([now - np.timedelta64(datetime.timedelta(seconds=i)) for i in range(200)])
y1 = np.sin(2 * np.pi * x1)
y2 = 1.2 * np.sin(4 * np.pi * x1)

产量:

Traceback (most recent call last):                                                File "fill_between_demo.py", line 21, in <module>                             
    ax1.fill_between(x, 0, y1)                                                  
  File "/home/usr/.virtualenvs/raiju/lib/python3.6/site-packages/matplotlib/__init__.py", line 1898, in inner                                                  
    return func(ax, *args, **kwargs)                                            
  File "/home/usr/.virtualenvs/raiju/lib/python3.6/site-packages/matplotlib/axes/_axes.py", line 4778, in fill_between                                         
    x = ma.masked_invalid(self.convert_xunits(x))                               
  File "/home/usr/.virtualenvs/raiju/lib/python3.6/site-packages/numpy/ma/core.py", line 2388, in masked_invalid                                               
    condition = ~(np.isfinite(a))                                               
TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''     

为什么会发生这种情况以及如何解决?

请注意,绘制数据(也就是不使用fill*)可以正常工作。

【问题讨论】:

    标签: python python-3.x datetime numpy matplotlib


    【解决方案1】:

    问题是,numpy ufunc isfinite 没有为 numpy.datetime64 dtype 定义。不过,我们正在努力改变这一点。此issue on numpy's github 正在此pull-request 中处理,但只要未完成并合并,您将无法在该dtype 上使用isfinite。这是一个问题,因为 matplotlib.pyplot.fill_between 在调用 numpy.ma.masked_invalid 以屏蔽输入数组的所有无效条目时隐式使用此函数。

    不过有一个变通方法。正如在answer 中指出的关于fill_between 绘制datetime64 类型的pandas Series 的类似问题,pandas 使用matplotlib 为datetime64 dtype 的(以及其他)numpy 数组注册了一个自定义转换器。要使用它,您只需导入 pandas:

    import numpy as np
    import matplotlib.pyplot as plt
    import datetime
    # import pandas for its converter that is then used in pyplot!
    import pandas
    
    x1 = np.arange(0.0, 2, 0.01)
    now = np.datetime64(datetime.datetime.now())
    x = np.array([now - np.timedelta64(datetime.timedelta(seconds=i))
                  for i in range(200)])
    y1 = np.sin(2 * np.pi * x1)
    y2 = 1.2 * np.sin(4 * np.pi * x1)
    
    fig, ax1 = plt.subplots(1, 1, sharex=True)
    
    # Test support for masked arrays.
    ax1.fill_between(x, 0, y1)
    ax1.set_ylabel('between y1 and 0')
    y2 = np.ma.masked_greater(y2, 1.0)
    ax1.plot(x, y1, x, y2, color='black')
    ax1.fill_between(
        x, y1, y2, where=y2 >= y1,
        facecolor='green',
        interpolate=True)
    ax1.fill_between(x, y1, y2, where=y2 <= y1, facecolor='red', interpolate=True)
    ax1.set_title('Now regions with y2>1 are masked')
    
    # Show the plot.
    plt.show()
    

    将起作用并为您提供所需的输出:

    【讨论】:

      【解决方案2】:

      我在使用 ax.setxlims 时遇到了类似的问题,因为我忘记将一些日期时间转换为 np.datetime。

      >>> import datetime
      >>> import numpy
      >>> a = datetime.datetime.now()
      >>> numpy.isfinite(a)
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
      >>> a = numpy.datetime64(a)
      >>> numpy.isfinite(a)
      True
      

      看来不再需要导入pandas了

      【讨论】:

        猜你喜欢
        • 2020-09-29
        • 2020-02-16
        • 2019-11-04
        • 1970-01-01
        • 1970-01-01
        • 2020-07-28
        • 2022-12-17
        • 1970-01-01
        • 2020-07-21
        相关资源
        最近更新 更多