Moving / Moving Average in d3.js

Looking for a way to build a moving / moving average in d3 without having to manipulate the data in advance. So I want to smooth the line by averaging each data point with two after it. My code is like this

var data = [3, 66, 2, 76, 5, 20, 1, 3, 8, 90, 2, 5, 70]; var w = 20, h = 80; var x = d3.scale.linear() .domain([0, 1]) .range([0, w]); var y = d3.scale.linear() .domain([0, 100]) .rangeRound([h, 0]); var chart = d3.select("body").append("svg") .attr("class", "chart") .attr("width", w * data.length -1) .attr("height", h); var line = d3.svg.line() .x(function(d,i) { return x(i); }) .y(function(d) { return y(d); }) var movingAverageLine = d3.svg.line() .x(function(d,i) { return x(i); }) .y(function(d) { return y(d); }) chart.append("svg:path").attr("d", line(data)); chart.append("svg:path").attr("d", movingAverageLine(data)); 

Can I specify moveAverageLine to calculate the average of the following data points? I cannot think of a way to access them in this function.

I installed the example on jsfiddle. http://jsfiddle.net/tjjjohnson/XXFrg/2/#run

+7
source share
3 answers

The previous solution leads to a cumulative moving average.

I modified the fiddle made by John O'Connor to provide an n-moving average by passing the custom interpolation function d3.svg.line() :

 movingAvg = function(n) { return function (points) { points = points.map(function(each, index, array) { var to = index + n - 1; var subSeq, sum; if (to < points.length) { subSeq = array.slice(index, to + 1); sum = subSeq.reduce(function(a,b) { return [a[0] + b[0], a[1] + b[1]]; }); return sum.map(function(each) { return each / n; }); } return undefined; }); points = points.filter(function(each) { return typeof each !== 'undefined' }) // Note that one could re-interpolate the points // to form a basis curve (I think...) return points.join("L"); } } var movingAverageLine = d3.svg.line() .x(function(d,i) { return x(i); }) .y(function(d,i) { return y(d); }) .interpolate(movingAvg(6)); 
+8
source

The next line function should do what you want. The formula is based on http://en.wikipedia.org/wiki/Moving_average#Cumulative_moving_average .

 var _movingSum; var movingAverageLine = d3.svg.line() .x(function(d,i) { return x(i); }) .y(function(d,i) { if (i == 0) { return _movingSum = 0; } else { _movingSum += d; } return y(_movingSum / i); }) .interpolate("basis"); 

http://jsfiddle.net/XXFrg/12/

+2
source

Not sure what you mean by "moving average", but if you just want to have a row that shows the average of your data, here is the approach:

 chart.append("svg:line") .attr("x1", x(0)) .attr("x2", x(1)) .attr("y1", d3.mean(data)) .attr("y2", d3.mean(data)) .style('stroke', 'blue') .style('stroke-width', 1) 

Here you can see jsfiddle: http://jsfiddle.net/XXFrg/3/ . Hope this helps,

0
source

All Articles