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

自定义非线性Date X轴绘制能耗时序数据的实现求助

自定义时序X轴(按日/周/月粒度分层)解决方案

需求说明

我需要绘制从过去到当前的水、电、气能耗时序数据,且需突出近期数据的重要性,X轴需按如下规则展示:

  • 当日至回溯1周:按日粒度
  • 回溯1周至3周:按周粒度
  • 更早数据:按月粒度
    X轴刻度需大致为2022-05 2022-06 2022-07 2022-07-25 2022-08-01 2022-08-08 2022-08-09 2022-08-10 2022-08-11且等间距分布,以便清晰查看昨日、上周及过往整体情况。但在实现forward和reverse函数及返回值时遇到瓶颈,附上已有代码求示例参考:

已有代码

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

def forward(x):
    return x
def reverse(x):
    return x

rng = pd.date_range(end='2022-08-14', periods=180, freq='D')

df = pd.DataFrame({'Date': rng, 'Val': np.random.randn(len(rng)) }) 
df.set_index("Date",inplace=True)
ax=df.plot()
plt.gca().set_xscale('function', functions=(forward, reverse))

ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.xticks(rotation = 30)
plt.show()

解决方案代码

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import timedelta

# 定义关键时间节点
current_date = pd.to_datetime('2022-08-14')
one_week_ago = current_date - timedelta(weeks=1)
three_weeks_ago = current_date - timedelta(weeks=3)

def forward(x):
    """将日期转换为非线性映射后的数值,放大近期数据的X轴占比"""
    # 将matplotlib日期数值转为pandas datetime对象
    x_dates = pd.to_datetime(mdates.num2date(x))
    
    # 划分三个时间区间的掩码
    mask_recent = x_dates >= one_week_ago
    mask_mid = (x_dates < one_week_ago) & (x_dates >= three_weeks_ago)
    mask_old = x_dates < three_weeks_ago
    
    # 初始化映射结果数组
    mapped = np.zeros_like(x, dtype=np.float64)
    
    # 近期(1周内):分配X轴后40%空间,按日线性映射
    recent_days = (x_dates[mask_recent] - one_week_ago).days
    total_recent_days = (current_date - one_week_ago).days
    mapped[mask_recent] = 0.6 + (recent_days / total_recent_days) * 0.4
    
    # 中期(1-3周):分配X轴20%空间,按周线性映射
    mid_weeks = (one_week_ago - x_dates[mask_mid]).days // 7
    total_mid_weeks = 2  # 共2周区间
    mapped[mask_mid] = 0.4 + (mid_weeks / total_mid_weeks) * 0.2
    
    # 早期(3周前):分配X轴前40%空间,按月线性映射
    old_months = (three_weeks_ago - x_dates[mask_old]).days // 30
    total_old_months = (three_weeks_ago - (current_date - timedelta(days=180))).days // 30
    mapped[mask_old] = (old_months / total_old_months) * 0.4
    
    return mapped

def reverse(x):
    """将映射后的数值逆向转换为原始日期"""
    # 划分映射值对应的三个区间掩码
    mask_recent = x >= 0.6
    mask_mid = (x >= 0.4) & (x < 0.6)
    mask_old = x < 0.4
    
    # 初始化日期数值数组
    reversed_dates = np.zeros_like(x, dtype=np.float64)
    
    # 近期逆向转换
    recent_ratio = (x[mask_recent] - 0.6) / 0.4
    recent_days = recent_ratio * (current_date - one_week_ago).days
    reversed_dates[mask_recent] = mdates.date2num(one_week_ago + timedelta(days=recent_days))
    
    # 中期逆向转换
    mid_ratio = (x[mask_mid] - 0.4) / 0.2
    mid_weeks = mid_ratio * 2
    reversed_dates[mask_mid] = mdates.date2num(one_week_ago - timedelta(weeks=mid_weeks))
    
    # 早期逆向转换
    old_ratio = x[mask_old] / 0.4
    total_old_months = (three_weeks_ago - (current_date - timedelta(days=180))).days // 30
    old_days = old_ratio * total_old_months * 30
    reversed_dates[mask_old] = mdates.date2num(three_weeks_ago - timedelta(days=old_days))
    
    return reversed_dates

# 生成测试时序数据
rng = pd.date_range(end='2022-08-14', periods=180, freq='D')
df = pd.DataFrame({'Date': rng, 'Val': np.random.randn(len(rng))}) 
df.set_index("Date", inplace=True)

# 绘图配置
fig, ax = plt.subplots(figsize=(12, 6))
df.plot(ax=ax)

# 设置自定义非线性X轴缩放
ax.set_xscale('function', functions=(forward, reverse))

# 手动设置目标刻度点,确保符合需求的粒度和间距
target_ticks = [
    '2022-05', '2022-06', '2022-07',
    '2022-07-25', '2022-08-01', '2022-08-08',
    '2022-08-09', '2022-08-10', '2022-08-11'
]
target_dates = pd.to_datetime(target_ticks)
ax.set_xticks([mdates.date2num(d) for d in target_dates])

# 配置日期格式化,自动适配不同粒度显示
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))

plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

关键说明

  1. 非线性映射:forward函数将日期分为三个区间,给近期数据分配最多X轴空间,实现近期数据的视觉突出;reverse函数完成逆向转换,保证坐标轴交互正常。
  2. 刻度控制:手动指定目标刻度点,确保X轴严格按需求的粒度和等间距展示,同时通过日期格式化器自动适配显示格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:24:36