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

如何用ChartJS在同一图表中绘制两组时间序列数据?

解决ChartJS同时展示历史与预测时间序列的问题

核心问题分析

你当前代码的问题在于用了固定的月份标签作为X轴,且未将两组数据的实际日期与数值绑定,导致历史数据的位置和日期不匹配,出现异常。ChartJS的时间序列图表要求每个数据点都关联对应日期,而非依赖统一的labels数组。

正确配置步骤

1. 转换数据格式

将历史数据(data)和预测数据(data_pred)都转换成包含x(日期)和y(价格/预测值)的对象数组:

// 处理历史数据,将ISO日期转为Date对象
const formattedHistory = data.map(item => ({
  x: new Date(item.datetime),
  y: item.close
}));

// 处理预测数据
const formattedForecast = data_pred.map(item => ({
  x: new Date(item.datetime),
  y: item.mean
}));

2. 修改Chart配置

移除原有的labels数组,直接在每个数据集里使用格式化后的带日期数据:

myChart = new Chart(canvasRef.current, {
  type: 'line',
  data: {
    datasets: [
      {
        label: '历史价格',
        data: formattedHistory,
        backgroundColor: 'rgba(255, 99, 132, 0.2)',
        borderColor: 'rgba(255, 99, 132, 1)',
        tension: 0.4
      },
      {
        label: '30天预测',
        data: formattedForecast,
        backgroundColor: 'rgba(54, 162, 235, 0.2)',
        borderColor: 'rgba(54, 162, 235, 1)',
        tension: 0.4,
        // 可选:给预测线添加虚线样式,区分历史数据
        borderDash: [5, 5]
      }
    ]
  },
  options: {
    scales: {
      x: {
        type: 'time', // 注意:ChartJS时间轴的正确类型是'time'而非'timeseries'
        time: {
          unit: 'day', // 根据数据粒度调整,可选day/month等
          displayFormats: {
            day: 'MM-dd', // 自定义日期显示格式
            month: 'MMM'
          }
        },
        title: {
          display: true,
          text: '日期'
        }
      },
      y: {
        title: {
          display: true,
          text: '价格'
        }
      }
    }
  }
});

3. 关键注意事项

  • 确保Postgres返回的ISO日期字符串能被new Date()正确解析,若格式有问题,可使用moment.js或date-fns等工具库处理。
  • 无需统一的labels数组,每个数据点自带x轴日期后,ChartJS会自动排序并渲染覆盖历史+预测的完整时间范围。

额外优化建议

  • 给预测数据添加虚线样式,让两组数据的视觉区分度更高。
  • 若数据量过大,可在options.scales.x.time中设置min和max来限定显示的时间范围。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:45:19