You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

datetime64作x轴绘渐变填充图报isfinite不支持类型错误

渐变填充折线图datetime64类型横轴报错问题

问题复现代码

需要实现带渐变填充效果的折线图,测试代码如下:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.patches import Polygon

def main():
    # float类型x可正常运行
    # x = np.array([0,1,2])

    # datetime64类型x触发报错
    x = np.array('2015-12-23 12:51:00',dtype='datetime64[ns]') 
    x = np.insert(x, 0, ('2015-12-24 12:51:00'))
    x = np.insert(x, 0, ('2015-12-25 12:51:00'))
    
    y = np.array([1,2,99])
    gradient_fill(x, y)
    plt.show()


def gradient_fill(x, y, fill_color=None, ax=None, **kwargs):
    """
    绘制折线,折线下方填充线性透明度渐变效果

    参数说明
    ----------
    x, y : 类数组结构
        折线对应的数据点
    fill_color : matplotlib支持的颜色格式(字符串、元组)或None
        填充色,若为None则默认使用折线本身的颜色
    ax : matplotlib Axes实例
        绘图使用的坐标轴,若为None则使用当前pyplot默认坐标轴
    其余参数会直接透传给matplotlib的``plot``方法

    返回值
    -------
    line : Line2D实例
        绘制得到的折线对象
    im : AxesImage实例
        被裁剪到折线下方区域的透明渐变层对象
    """
    if ax is None:
        ax = plt.gca()

    line, = ax.plot(x, y, **kwargs)
    if fill_color is None:
        fill_color = line.get_color()

    zorder = line.get_zorder()
    alpha = line.get_alpha()
    alpha = 1.0 if alpha is None else alpha

    z = np.empty((100, 1, 4), dtype=float)
    rgb = mcolors.colorConverter.to_rgb(fill_color)
    z[:,:,:3] = rgb
    z[:,:,-1] = np.linspace(0, alpha, 100)[:,None]

    xmin, xmax, ymin, ymax = x.min(), x.max(), y.min(), y.max()
    im = ax.imshow(z, aspect='auto', extent=[xmin, xmax, ymin, ymax],
                origin='lower', zorder=zorder)

    xy = np.column_stack([x, y])
    xy = np.vstack([[xmin, ymin], xy, [xmax, ymin], [xmin, ymin]])
    clip_path = Polygon(xy, facecolor='none', edgecolor='none', closed=True)
    ax.add_patch(clip_path)
    im.set_clip_path(clip_path)

    ax.autoscale(True)
    return line, im

main()

报错信息

x为float类型时代码运行正常,使用datetime64类型作为横轴数据时,抛出如下错误:

if not np.any(np.isfinite(xys)):
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'' 

报错原因

NumPy 1.17之后确实已经支持直接对datetime64数组调用np.isfinite,当前报错和NumPy的版本修复无关,核心问题出在坐标拼接逻辑:

  • 用np.column_stack([x, y])拼接datetime64类型的x数组和float类型的y数组时,numpy无法找到兼容的通用数据类型,会把拼接后的数组降级为object类型
  • Matplotlib初始化Polygon对象时,会对传入的坐标数组调用np.isfinite做有效性校验,而np.isfinite不支持object类型数组的逐元素判断,因此抛出类型错误。

解决方法

只需要修改gradient_fill函数中构造渐变层和裁剪路径的逻辑,将datetime类型的x转换为Matplotlib内部使用的数值型日期表示即可,不需要调整绘图的主逻辑,也不需要升降级依赖版本,操作步骤如下:

  • 首先在文件头部导入Matplotlib的日期转换工具:
from matplotlib.dates import date2num
  • 替换gradient_fill函数中构造imshow范围和裁剪路径的代码段,将原始datetime64的x转换为数值型日期值再参与拼接:
# 将datetime64转换为matplotlib内部使用的数值日期格式
x_num = date2num(x)
xmin, xmax = x_num.min(), x_num.max()
ymin, ymax = y.min(), y.max()
im = ax.imshow(z, aspect='auto', extent=[xmin, xmax, ymin, ymax],
            origin='lower', zorder=zorder)

xy = np.column_stack([x_num, y])
xy = np.vstack([[xmin, ymin], xy, [xmax, ymin], [xmin, ymin]])
clip_path = Polygon(xy, facecolor='none', edgecolor='none', closed=True)

注意:ax.plot(x, y, **kwargs)这行不需要修改,直接传入原始datetime64格式的x即可,Matplotlib会自动完成日期轴的刻度识别和格式化显示,不会影响最终的轴展示效果。

内容的提问来源于stack exchange,提问作者Freude

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 19:24:23