如何在Matplotlib中正确绘制数组中的日期类型X轴值?
修复Matplotlib并列柱状图的X轴日期显示错误及趋势线问题
问题背景
- 定义了Pandas Series对象
x = new_df['month'],包含的日期值如下:
0,2021-01-01 1,2021-02-01 2,2021-03-01 3,2021-04-01 4,2021-05-01 5,2021-06-01 6,2021-07-01 7,2021-08-01 8,2021-09-01 9,2021-10-01 10,2021-11-01 11,2021-12-01 12,2022-01-01 13,2022-02-01 14,2022-03-01 15,2022-04-01 16,2022-05-01 17,2022-06-01 18,2022-07-01 19,2022-08-01 20,2022-09-01 21,2022-10-01 22,2022-11-01
- 编写了绘图函数
side_by_side_bar_chart,代码如下:
import matplotlib.pyplot as plt import matplotlib.ticker as ticker import matplotlib.dates as mdates import numpy as np def side_by_side_bar_chart(x, y, labels, file_name): width = 0.25 # set bar width ind = np.arange(len(x)) # Get the number of x labels fig, ax = plt.subplots(figsize=(10, 8)) # Get average number in order to set labels formatting ymax = int(max([mean(x) for x in y])) plt.xticks(ind, x) # sets x labels with values in x list (months) # These two lines format ax labels dtFmt = mdates.DateFormatter('%b-%y') # define the formatting plt.gca().xaxis.set_major_formatter(dtFmt) plt.savefig("charts/"+ file_name + ".png", dpi = 300)
- 遇到的问题:
- X轴所有刻度显示为
Jan 70,日期格式化错误 - 使用
twinx()绘制带趋势线的并列图表时,数值绘制错误
- X轴所有刻度显示为
问题原因及修复方案
1. X轴日期显示错误的修复
核心错误:用np.arange(len(x))生成整数索引作为X轴位置,再用plt.xticks(ind, x)直接替换标签,而mdates.DateFormatter只识别Matplotlib的日期数值(不是Pandas日期对象或字符串),导致日期被误判为1970年起始的时间戳。
修复后的完整函数:
import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as mdates import numpy as np def side_by_side_bar_chart(x, y, labels, file_name): width = 0.25 fig, ax = plt.subplots(figsize=(10, 8)) # 确保x是datetime类型(若原始数据不是则转换) x = pd.to_datetime(x) # 将日期转换为Matplotlib可识别的数值格式 x_num = mdates.date2num(x) # 绘制并列柱状图:为每个系列偏移宽度 for idx, (y_data, label) in enumerate(zip(y, labels)): ax.bar(x_num + idx * width, y_data, width=width, label=label) # 设置X轴日期格式化 dtFmt = mdates.DateFormatter('%b-%y') ax.xaxis.set_major_formatter(dtFmt) # 自动旋转X轴标签,避免重叠 fig.autofmt_xdate() # 修复ymax计算:替换未导入的mean为max,增加余量避免顶格 ymax = int(max([max(data) for data in y])) + 5 ax.set_ylim(0, ymax) ax.legend() plt.savefig(f"charts/{file_name}.png", dpi=300) plt.close()
2. 带趋势线的双Y轴(twinx)修复
使用twinx()时,需保证两个轴共享X轴的日期坐标,不能重新设置X轴刻度,趋势线要基于日期数值绘制:
扩展后的示例函数:
def side_by_side_bar_with_trend(x, y, labels, trend_data, file_name): width = 0.25 fig, ax1 = plt.subplots(figsize=(10, 8)) x = pd.to_datetime(x) x_num = mdates.date2num(x) # 绘制并列柱状图 for idx, (y_data, label) in enumerate(zip(y, labels)): ax1.bar(x_num + idx * width, y_data, width=width, label=label) # 配置第一个Y轴 ax1.set_ylabel('柱状图数值') dtFmt = mdates.DateFormatter('%b-%y') ax1.xaxis.set_major_formatter(dtFmt) fig.autofmt_xdate() # 创建双Y轴并绘制趋势线 ax2 = ax1.twinx() # 线性拟合趋势线 z = np.polyfit(x_num, trend_data, 1) p = np.poly1d(z) ax2.plot(x_num, p(x_num), color='red', linestyle='--', label='趋势线') ax2.set_ylabel('趋势线数值') # 合并双轴图例 lines1, labels1 = ax1.get_legend_handles_labels() lines2, labels2 = ax2.get_legend_handles_labels() ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left') plt.savefig(f"charts/{file_name}.png", dpi=300) plt.close()
关键注意事项
- 必须确保X轴数据为datetime类型,用
pd.to_datetime()强制转换 - 用
mdates.date2num()将日期转为Matplotlib可处理的数值,用于柱状图位置计算和趋势线拟合 - 禁止混合使用整数索引和日期对象作为X轴数据,否则格式化器会失效
- 使用
twinx()时,两个轴共享X轴坐标空间,所有绘图操作都要基于同一个日期数值集合
内容的提问来源于stack exchange,提问作者yulesst
相关产品推荐
相关产品推荐

