使用TimedeltaIndex时matplotlib fill_between绘图报错咨询
matplotlib fill_between触发DTypePromotionError的原因及解决办法
问题场景
使用matplotlib.pyplot.fill_between绘制填充图时,当索引为pandas.TimedeltaIndex且序列值为浮点数时,会抛出DTypePromotionError,示例代码如下:
import pandas as pd import matplotlib.pyplot as plt import numpy as np idx = pd.TimedeltaIndex(['0 days 00:00:00', '0 days 06:00:00', '0 days 12:00:00', '0 days 18:00:00'], dtype='timedelta64[ns]', freq='6H') ts1 = pd.Series(np.array([ 0., 5439.802205, 4506.0691, 640.734375]), index=idx) ts2 = pd.Series(np.array([747., 740.4, 717., 740.4]), index=idx) plt.figure() plt.fill_between(ts1.index, ts1, ts2, where=(ts1 > ts2)) plt.fill_between(ts1.index, ts1, ts2, where=(ts1 <= ts2)) plt.show()
错误信息
DTypePromotionError: The DType <class 'numpy.dtypes.TimeDelta64DType'> could not be promoted by <class 'numpy.dtypes.Float64DType'>. This means that no common DType exists for the given inputs. For example they cannot be stored in a single array unless the dtype is `object`. The full list of DTypes is: (<class 'numpy.dtypes.TimeDelta64DType'>, <class 'numpy.dtypes.Float64DType'>)
可正常运行的对照场景
- 不使用TimedeltaIndex:仅保留浮点数序列,使用默认整数索引时可正常绘图。
- 保留TimedeltaIndex但使用整数序列:将序列值替换为整数范围,绘图无报错。
原因分析
这个问题的核心是numpy的类型提升规则与matplotlib内部处理逻辑的冲突:
- 调用
fill_between时,matplotlib会尝试将传入的索引(TimedeltaIndex本质是timedelta64[ns]类型)和序列值进行内部数值对齐与计算。 - 对于整数序列,
timedelta64类型可以和int64隐式提升(因为时间差本质是整数纳秒计数),因此能兼容处理。 - 但
float64(浮点数序列)与timedelta64之间没有公共的可兼容 dtype——numpy不支持这两种类型的直接转换或提升,除非转为object类型,而matplotlib的内部数值计算逻辑不允许这种低效的object类型操作,因此抛出类型提升错误。 - 当使用默认整数索引时,整数索引可与浮点数序列正常提升为
float64类型,因此不会触发冲突。
解决方案
将TimedeltaIndex转换为matplotlib可直接处理的数值类型(如总小时数、总秒数)即可解决问题,示例代码如下:
import pandas as pd import matplotlib.pyplot as plt import numpy as np idx = pd.TimedeltaIndex(['0 days 00:00:00', '0 days 06:00:00', '0 days 12:00:00', '0 days 18:00:00'], dtype='timedelta64[ns]', freq='6H') # 将TimedeltaIndex转换为总小时数的数值数组 x_values = idx.total_seconds() / 3600 ts1 = pd.Series(np.array([ 0., 5439.802205, 4506.0691, 640.734375]), index=idx) ts2 = pd.Series(np.array([747., 740.4, 717., 740.4]), index=idx) plt.figure() plt.fill_between(x_values, ts1, ts2, where=(ts1 > ts2)) plt.fill_between(x_values, ts1, ts2, where=(ts1 <= ts2)) # 手动设置x轴标签,还原时间差格式 plt.xticks(x_values, idx.astype(str)) plt.show()
内容的提问来源于stack exchange,提问作者CodeNStuff
相关产品推荐
相关产品推荐

