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

多日期时间序列叠加绘图时,如何解决X轴刻度重叠问题?

解决多日24小时测量数据叠加绘图的X轴刻度重叠问题

问题背景

我有一个包含DATE_TIME、DATE、TIME和VALUE1列的数据集,VALUE1记录每个时间点的测量值。同一ID每日有多次测量,且一个ID对应6次不同的24小时测量(由INSPECTION列标识)。尝试将所有测量值叠加绘图(X轴仅显示时间、不含日期,Y轴为VALUE1)时,图表混乱,X轴刻度重叠,显示效果差。曾尝试将X轴的TIME列转为分类变量编码,但未解决问题。期望清晰展示全部6次检查数据,X轴TIME无刻度重叠,Y轴显示VALUE1。

示例数据与尝试代码

import random
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.express as px
import seaborn as sns
import matplotlib.ticker as ticker
from plotly.subplots import make_subplots
from dash import Dash, html, dcc, Input, Output, dash_table, no_update
import plotly.graph_objects as go
random.seed(0)

df = pd.DataFrame({'DATE_TIME': pd.date_range('2022-11-01', '2022-11-06 23:00:00', freq='20min'),
                   'ID': [random.randrange(1, 3) for n in range(430)]})
df['VALUE1'] = [random.uniform(110, 160) for n in range(430)]
df['VALUE2'] = [random.uniform(50, 80) for n in range(430)]
df['INSPECTION'] = df['DATE_TIME'].dt.day
# df['INSPECTION'] = df['INSPECTION'].replace(6, 1)
# df['INSPECTION'] = df['INSPECTION'].replace(3, 1)

df['MODE'] = np.select([df['INSPECTION'] == 1, df['INSPECTION'].isin([2, 3])], ['A', 'B'], 'C')
df['TIME'] = df['DATE_TIME'].dt.time
df['TIME'] = df['TIME'].astype('str')

df['TIMEINTERVAL'] = df.DATE_TIME.diff().astype('timedelta64[m]')
df['TIMEINTERVAL'] = df['TIMEINTERVAL'].fillna(0)


def to_day_period(s):
    bins = ['0', '06:00:00', '13:00:00', '18:00:00', '23:00:00', '24:00:00']
    labels = ['Nighttime', 'Daytime', 'Daytime', 'Nighttime', 'Nighttime']

    return pd.cut(
        pd.to_timedelta(s),
        bins=list(map(pd.Timedelta, bins)),
        labels=labels, right=False, ordered=False
    )


df['TIME_OF_DAY'] = to_day_period(df['TIME'])
df_monthly = df

# ++++++++++++++++++++++++++++++++ sns plot ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
df_id = df[df.ID==1]
sns.set_style('darkgrid')
sns.set(rc={'figure.figsize':(14,8)})
#print(df_id.INSPECTION.unique())
ax = sns.lineplot(data=df_id, x ='TIME', y = 'VALUE1',
                  hue='INSPECTION', palette='viridis',
                  legend='full', lw=3)

ax.xaxis.set_major_locator(ticker.MultipleLocator(4))
plt.legend(bbox_to_anchor=(1, 1))
plt.ylabel('VALUE1')
plt.xlabel('TIME')
plt.show()

解决方案

问题核心是TIME列被转为字符串类型,matplotlib无法识别其时间序列特性,导致刻度排列混乱。以下是两种有效修复方式:

方式1:保留时间的timedelta类型

不要把TIME转为字符串,而是将其处理为timedelta类型,让matplotlib识别为连续的时间轴:

# 替换原TIME列的生成代码
df['TIME'] = df['DATE_TIME'].dt.hour * 3600 + df['DATE_TIME'].dt.minute * 60 + df['DATE_TIME'].dt.second
df['TIME'] = pd.to_timedelta(df['TIME'], unit='s')

# 绘图部分调整
df_id = df[df.ID==1]
sns.set_style('darkgrid')
sns.set(rc={'figure.figsize':(14,8)})
ax = sns.lineplot(data=df_id, x='TIME', y='VALUE1', hue='INSPECTION', palette='viridis', legend='full', lw=3)

# 设置X轴刻度为每2小时显示一次
ax.xaxis.set_major_locator(ticker.MultipleLocator(base=2*3600))
# 格式化刻度显示为HH:MM格式
ax.xaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: str(pd.to_timedelta(x, unit='s')).split()[-1][:5]))

plt.legend(bbox_to_anchor=(1, 1))
plt.ylabel('VALUE1')
plt.xlabel('TIME')
plt.xticks(rotation=45)  # 可选:旋转刻度避免拥挤
plt.tight_layout()  # 自动调整布局
plt.show()

方式2:使用统一虚拟日期的datetime对象

将所有时间点映射到同一个虚拟日期,生成完整的datetime对象,让matplotlib自动处理时间轴:

# 生成虚拟日期的datetime列
df['TIME_DATETIME'] = pd.to_datetime('2020-01-01 ' + df['DATE_TIME'].dt.time.astype(str))

# 绘图部分调整
df_id = df[df.ID==1]
sns.set_style('darkgrid')
sns.set(rc={'figure.figsize':(14,8)})
ax = sns.lineplot(data=df_id, x='TIME_DATETIME', y='VALUE1', hue='INSPECTION', palette='viridis', legend='full', lw=3)

# 设置X轴刻度格式为仅显示时间
ax.xaxis.set_major_formatter(plt.matplotlib.dates.DateFormatter('%H:%M'))
# 设置刻度间隔为2小时
ax.xaxis.set_major_locator(plt.matplotlib.dates.HourLocator(interval=2))

plt.legend(bbox_to_anchor=(1, 1))
plt.ylabel('VALUE1')
plt.xlabel('TIME')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

额外优化建议

  • 如果6次检查的数据差异较大,可使用分面绘图(sns.FacetGrid),每个检查单独一个子图,更易对比:
    g = sns.FacetGrid(df_id, col='INSPECTION', col_wrap=3, height=4, aspect=1.2)
    g.map(sns.lineplot, 'TIME_DATETIME', 'VALUE1', lw=2)
    g.set_axis_labels('TIME', 'VALUE1')
    g.set_titles('Inspection {col_name}')
    for ax in g.axes.flat:
        ax.xaxis.set_major_formatter(plt.matplotlib.dates.DateFormatter('%H:%M'))
        ax.xaxis.set_major_locator(plt.matplotlib.dates.HourLocator(interval=2))
        plt.setp(ax.get_xticklabels(), rotation=45)
    plt.tight_layout()
    plt.show()
    
  • 若使用Plotly代替Seaborn,可获得交互式图表,更方便查看细节:
    fig = px.line(df_id, x='TIME_DATETIME', y='VALUE1', color='INSPECTION', 
                  labels={'TIME_DATETIME':'TIME', 'VALUE1':'VALUE1'},
                  title='24-hour Measurements by Inspection')
    fig.update_xaxes(tickformat='%H:%M', dtick=2*3600*1000)  # 每2小时一个刻度
    fig.show()
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 04:37:50