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

如何在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)
  • 遇到的问题:
    1. X轴所有刻度显示为Jan 70,日期格式化错误
    2. 使用twinx()绘制带趋势线的并列图表时,数值绘制错误

问题原因及修复方案

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 20:20:55