9

寻找一种在 d3 中绘制滚动/移动平均线的方法,而无需提前操纵数据。所以我想通过平均每个数据点和后面的两个来平滑这条线。我的代码是这样的

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

我可以指定movingAverageLine 来计算以下数据点的平均值吗?我想不出在该功能中访问它们的方法。

我在 jsfiddle 上设置了一个示例。http://jsfiddle.net/tjjjohnson/XXFrg/2/#run

4

3 回答 3

12

先前的解决方案导致累积移动平均线。

我修改了John O'Connor制作的小提琴,通过将自定义插值函数传递给来提供n移动平均值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));
于 2014-06-27T06:03:04.040 回答
2

以下行功能应该做你想做的事。基于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/

于 2013-04-07T23:17:42.437 回答
0

不确定“滚动平均值”是什么意思,但如果你只想有一条线来显示数据的平均值,这里有一种方法:

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)

你可以在这里看到 jsfiddle:http: //jsfiddle.net/XXFrg/3/。希望有帮助,

于 2012-08-15T17:17:11.467 回答