D3 Moving Average

by plmrry

HTML

<script src="https://raw.github.com/mbostock/d3/af2af6ac9080529d102aacfa57807371fd983d2b/d3.v2.js"></script>

CSS

path {
    stroke: black;
    fill: none;
}
.avg {
    stroke: #ff0000;    
}

JavaScript

var data = [3, 66, 2, 76, 5, 20, 1, 30, 50, 9, 80, 5, 7];

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 + 200);

var line = d3.svg.line()
    .x(function(d,i) { return x(i); })
    .y(function(d) { return y(d); })

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' });
        // Transform the points into a basis line
        pathDesc = d3.svg.line().interpolate("basis")(points)
        // Remove the extra "M"
        return pathDesc.slice(1, pathDesc.length);
    }
}

var _movingSum;
var movingAverageLine = d3.svg.line()
    .x(function(d,i) { return x(i); })
    .y(function(d,i) { return y(d); })
    .interpolate(movingAvg(3));

chart.append('svg:path').attr('class', 'avg').attr("d", movingAverageLine(data));
chart.append("svg:path").attr("d", line(data));