Pandas与Matplotlib DateTime绘图坐标不一致及最佳实践问询
这个问题我之前踩过坑!核心原因是Pandas和Matplotlib对datetime类型的x轴采用了完全不同的数值表示系统,导致混合绘图时坐标不匹配。下面给你拆解原因和几种公认的最佳实践:
问题根源
- Pandas默认绘图时,会把
DatetimeIndex转换成纳秒级时间戳(就是你看到的25247280.0这类数值,本质是datetime64[ns]类型的整数表示转换为浮点数) - Matplotlib原生绘图则使用date2num格式:把日期转换成从公元1年1月1日以来的天数(比如
736695.727,对应2018-01-01 20:00:00)
两种格式数值范围差了好几个数量级,混合使用自然会导致其中一个图的内容被压缩到完全看不见。
最佳实践
方案1:强制Pandas使用Matplotlib的日期系统(推荐混合绘图时用)
在Pandas的plot()方法里添加x_compat=True参数,这样Pandas会改用Matplotlib的date2num格式处理x轴,和原生绘图完全兼容。
修改你的示例代码如下:
import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as mdates start = '2018-01-02 03:00:00' end = '2018-01-02 11:00:00' data = pd.DataFrame({'DateTime': pd.date_range(start=start, end=end, freq='1H'), 'x': [1,2,3,4,5,4,3,2,1], 'y': [5,4,3,2,1,2,3,4,5]}) data = data.set_index('DateTime') ax0 = plt.subplot(211) ax1 = plt.subplot(212, sharex=ax0) # Pandas绘图时启用x_compat,对齐Matplotlib的日期格式 data['x'].plot(ax=ax0, x_compat=True) # Matplotlib原生绘图直接用DatetimeIndex即可(自动转成date2num格式) ax1.plot(data.index, data['y']) # 如果要添加broken_barh,这样转换坐标: start_bar = pd.to_datetime('2018-01-02 04:00:00') end_bar = pd.to_datetime('2018-01-02 08:00:00') # 把持续时间转换成date2num的单位(天) duration_days = (end_bar - start_bar).total_seconds() / (3600*24) ax1.broken_barh([(mdates.date2num(start_bar), duration_days)], (0, 5), facecolor='red', alpha=0.3) plt.tight_layout() plt.savefig('test_fixed.png')
修改后两个子图的x轴坐标系统完全一致,sharex能正常工作,broken_barh也能准确显示在对应时间段。
方案2:强制Matplotlib使用Pandas的时间戳格式
如果你更习惯用Pandas的默认格式,可以把Matplotlib绘图的x轴数据转换成Pandas的纳秒级时间戳:
# 把DatetimeIndex转成Pandas绘图使用的时间戳数值(秒级) ax1.plot(data.index.view('int64') / 1e9, data['y'])
不过这种方法的缺点是后续调整x轴日期刻度会比较麻烦,需要手动转换回datetime对象,所以不如方案1便捷。
额外提示
如果需要调整x轴的日期显示格式(比如显示成%Y-%m-%d %H:%M),可以在方案1的基础上添加:
date_format = mdates.DateFormatter('%Y-%m-%d %H:%M') ax0.xaxis.set_major_formatter(date_format) ax1.xaxis.set_major_formatter(date_format) plt.xticks(rotation=45)
这样就能得到格式清晰的日期刻度了。
内容的提问来源于stack exchange,提问作者Scott B
相关产品推荐
相关产品推荐

