Matplotlib set_major_formatter设置日期格式部分数据集不生效
问题根因
格式化规则失效的核心原因是代码执行顺序与pandas的默认机制冲突:你在调用df.plot()之前就手动设置了x轴格式化器,但pandas对DatetimeIndex类型的x轴自带自适应优化逻辑——当检测到时间序列是规整间隔(比如第二版测试数据刚好是整6小时间隔、时间点全部落在整点),df.plot()会自动重设x轴的刻度定位器和格式化器,直接覆盖你之前手动配置的规则。第一版非整点数据没触发pandas的自动优化判定,所以配置能生效,第二版整点规整数据触发了覆盖逻辑,格式就偏离了设定值。
可靠固定格式方案
以下两种方案都可以保证无论传入什么时间序列数据,x轴日期格式都固定为yyyy-mm-dd hh:mm,不会被自动修改:
方案1:调整代码顺序,plot完成后再设置格式化规则
这是成本最低的改法,把格式化配置挪到df.plot()执行之后,此时pandas的自动轴配置已经完成,后续手动设置的规则不会被覆盖,修正后的可运行代码如下:
import pandas as pd from matplotlib import pyplot as plt from matplotlib import dates as mdates df = pd.DataFrame( [['2022-01-01 01:00', 5], ['2022-01-01 07:00', 10], ['2022-01-01 13:00', 15], ['2022-01-01 19:00', 10]], columns=['Time', 'Variable']) df['Time'] = pd.to_datetime(df['Time']) df = df.set_index('Time') fig, ax = plt.subplots() # 先执行plot,让pandas完成自动轴初始化 df.plot(ax=ax) # 最后手动设置格式化规则,不会被覆盖 ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M')) ax.xaxis.set_minor_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M')) ax.tick_params(axis='x', labelrotation=45) plt.show()
方案2:关闭pandas自动时间轴适配
如果不想调整代码顺序,可以在调用df.plot()时传入参数x_compat=True,强制pandas使用标准matplotlib时间轴逻辑,禁止自动替换刻度格式化配置,此时你提前写的格式化规则就可以正常生效:
import pandas as pd from matplotlib import pyplot as plt from matplotlib import dates as mdates df = pd.DataFrame( [['2022-01-01 01:00', 5], ['2022-01-01 07:00', 10], ['2022-01-01 13:00', 15], ['2022-01-01 19:00', 10]], columns=['Time', 'Variable']) df['Time'] = pd.to_datetime(df['Time']) df = df.set_index('Time') fig, ax = plt.subplots() ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M')) ax.xaxis.set_minor_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M')) # 传入x_compat=True关闭自动时间轴优化 df.plot(ax=ax, x_compat=True) ax.tick_params(axis='x', labelrotation=45) plt.show()
进阶固定配置
如果需要连刻度间隔也完全固定,不随数据时间范围自动变化,可以搭配matplotlib的刻度定位器使用,完全接管x轴配置:
- 固定每6小时显示一个主刻度:添加代码
ax.xaxis.set_major_locator(mdates.HourLocator(interval=6)) - 固定每30分钟显示一个主刻度:添加代码
ax.xaxis.set_major_locator(mdates.MinuteLocator(byminute=[0,30])) - 固定每天显示一个主刻度:添加代码
ax.xaxis.set_major_locator(mdates.DayLocator(interval=1))
上述配置和格式化规则搭配使用后,无论传入什么时间范围的数据集,x轴的刻度位置、显示格式都不会自动变更。
内容的提问来源于stack exchange,提问作者Bob
相关产品推荐
相关产品推荐

