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

如何修复Matplotlib子图时间轴刻度,仅在数据起始日期后显示标签?

问题:Matplotlib子图时间轴刻度标签仅显示数据起始日期之后的内容

尝试在Matplotlib子图中设置时间轴,让x轴刻度标签仅在对应子图的数据起始日期之后显示,编写了如下代码:

import pandas as pd
import numpy as np
from datetime import date

import matplotlib.pyplot as plt
from matplotlib.dates import MonthLocator, num2date
from matplotlib.ticker import FuncFormatter

xs = [pd.date_range(f'{y}-07-01', '2021-12-31', freq='M')
      for y in range(2016, 2019)]
ys = [np.random.rand(len(x)) for x in xs]

fig, axs = plt.subplots(3, 1, figsize=(10, 8))
for ax, x, y in zip(axs, xs, ys):
    ax.plot(x, y)

    # Custom formatting function
    date_min = x[0].date()
    def custom_date_formatter(x, pos):
        dt = num2date(x)
        if dt.date() < date_min:
            return ''
        elif dt.month == 1:
            return dt.strftime('%Y')
        else:
            return dt.strftime('%b').upper()

    ax.xaxis.set_major_locator(MonthLocator((1, 4, 7, 10)))
    ax.xaxis.set_major_formatter(FuncFormatter(custom_date_formatter))
    ax.tick_params(axis='x', labelsize=8)

    ax.set_xlim(date(2016, 7, 1))

运行后所有子图的x轴刻度标签完全相同,不符合预期。预期每个子图的刻度标签如下:

JUL - OCT - 2017 - APR - JUL - OCT - 2018 .....

..... JUL - OCT - 2018 - APR - JUL - OCT - 2019 .....

............ JUL - OCT - 2019 - APR - JUL - OCT - 2020 .....

问题原因

循环中定义custom_date_formatter函数时,存在闭包变量延迟绑定的问题:函数内部的date_min并不会在定义时立即捕获当前循环的变量值,而是在函数实际调用时才会去查找date_min的最终值——也就是循环最后一次迭代的date_min(2018-07-01),导致所有子图都用这个值来判断刻度是否显示。

解决方案

使用functools.partial将当前子图的date_min绑定到格式化函数中,确保每个子图的格式化函数都持有各自的起始日期。修改后的代码如下:

import pandas as pd
import numpy as np
from datetime import date
from functools import partial  # 导入partial

import matplotlib.pyplot as plt
from matplotlib.dates import MonthLocator, num2date
from matplotlib.ticker import FuncFormatter

xs = [pd.date_range(f'{y}-07-01', '2021-12-31', freq='M')
      for y in range(2016, 2019)]
ys = [np.random.rand(len(x)) for x in xs]

fig, axs = plt.subplots(3, 1, figsize=(10, 8))

# 将格式化函数定义在循环外部,接收date_min参数
def custom_date_formatter(date_min, x, pos):
    dt = num2date(x)
    if dt.date() < date_min:
        return ''
    elif dt.month == 1:
        return dt.strftime('%Y')
    else:
        return dt.strftime('%b').upper()

for ax, x, y in zip(axs, xs, ys):
    ax.plot(x, y)
    date_min = x[0].date()
    
    # 使用partial绑定当前子图的date_min
    formatter = FuncFormatter(partial(custom_date_formatter, date_min))
    ax.xaxis.set_major_locator(MonthLocator((1, 4, 7, 10)))
    ax.xaxis.set_major_formatter(formatter)
    ax.tick_params(axis='x', labelsize=8)
    
    # 调整每个子图的x轴范围,只显示当前数据的起始日期及之后
    ax.set_xlim(date_min)

关键修改点

  • 将格式化函数移到循环外:避免每次循环定义新函数导致的闭包问题,同时让函数接收date_min作为参数。
  • 用partial绑定参数:为每个子图的格式化函数绑定对应的date_min,确保每个子图使用自己的起始日期判断刻度是否显示。
  • 调整x轴范围:把固定的起始日期改为当前子图的date_min,让每个子图的x轴从自身数据的起始日期开始,避免显示多余的空白区域。

内容的提问来源于stack exchange,提问作者steven

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:46:03