如何使用D3.js将时间线图表转换为积分图表
D3.js 时序数据转积分图表实现方案
时序数据的积分图表通常分为两类:
- 累计求和积分:仅对采样点的数值做累加,适合采样间隔均匀的统计类场景
- 时间加权积分:对函数f(t)在时间维度做积分,适合需要计算时间维度累计总量的物理、业务统计场景
第一步:数据预处理
首先先对原始数据按时间戳升序排序,再根据需求选择对应积分计算逻辑:
累计求和积分转换代码
// 先按时间戳升序排序,避免原始数据时序乱序 const sortedData = array1.sort((a,b) => a.ts - b.ts) // 累计求和计算积分值 const cumulativeIntegral = sortedData.reduce((result, current, index) => { const prevSum = index === 0 ? 0 : result[index-1].integralValue result.push({ ts: current.ts, originalValue: current.value, integralValue: prevSum + current.value }) return result }, [])
时间加权积分转换代码(梯形法计算,结果更平滑准确)
const sortedData = array1.sort((a,b) => a.ts - b.ts) const timeWeightedIntegral = sortedData.reduce((result, current, index) => { if (index === 0) { // 第一个采样点初始积分值设为0 result.push({ ts: current.ts, originalValue: current.value, integralValue: 0 }) return result } const prevItem = sortedData[index-1] // 计算两个采样点的时间差,单位和ts单位一致,示例中为秒 const timeDelta = current.ts - prevItem.ts // 梯形法计算区间积分:(前值+现值)/2 * 时间差 const intervalIntegral = (prevItem.value + current.value) / 2 * timeDelta result.push({ ts: current.ts, originalValue: current.value, integralValue: result[index-1].integralValue + intervalIntegral }) return result }, [])
第二步:D3.js 渲染积分图表
积分图表的渲染逻辑和普通时序折线图基本一致,仅需要将y轴绑定的数值替换为计算得到的integralValue即可,核心渲染代码示例:
// 定义画布尺寸 const width = 800, height = 400, margin = {top: 20, right: 20, bottom: 30, left: 50} const svg = d3.select('svg') .attr('width', width) .attr('height', height) // 定义x轴时间比例尺 const xScale = d3.scaleTime() .domain(d3.extent(cumulativeIntegral, d => new Date(d.ts * 1000))) // 秒级时间戳转Date对象 .range([margin.left, width - margin.right]) // 定义y轴积分值比例尺 const yScale = d3.scaleLinear() .domain(d3.extent(cumulativeIntegral, d => d.integralValue)) .range([height - margin.bottom, margin.top]) // 生成折线路径 const linePath = d3.line() .x(d => xScale(new Date(d.ts * 1000))) .y(d => yScale(d.integralValue)) .curve(d3.curveLinear) // 可替换为d3.curveMonotoneX实现平滑曲线效果 // 渲染折线 svg.append('path') .datum(cumulativeIntegral) .attr('fill', 'none') .attr('stroke', 'steelblue') .attr('stroke-width', 2) .attr('d', linePath) // 渲染x、y轴和网格线等其余元素逻辑和普通时序图完全一致
注意事项
- 若原始数据采样间隔不均匀,优先使用时间加权积分,结果更符合积分的数学定义
- 累计求和积分仅适用采样间隔完全相等的场景,否则会出现统计偏差
- 可根据业务需求调整积分初始值,仅需要修改reduce方法中第一个点的初始积分值即可
内容的提问来源于stack exchange,提问作者Dev M
相关产品推荐
相关产品推荐

