2012-08-15 85 views
7

寻找一种方法来绘制d3中的滚动/移动平均值,而无需事先操作数据。所以我想通过平均每个数据点与之后的两个数据点来消除这条线。我的代码是这样的d3.js中的绘图滚动/移动平均值

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

回答

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/。希望有帮助,

+0

编辑问题澄清一点。通过“滚动”,我的意思是每天使用几个点的平均值,例如三天平均。这是为了消除这条线。 – tjjjohnson 2012-08-16 04:41:00

+0

我认为你将不得不改变数据 - 当你将数组传递给d3函数时,它将一次迭代1项。任何原因你不能创建另一个数组传递? – mike 2012-08-16 09:35:17

+0

没理由我无法修改数据,我只是想知道是否有一些狡猾的D3可以做得很好 – tjjjohnson 2012-08-17 10:38:11

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

8

先前的溶液导致累积移动平均值。

I modified the fiddle通过John O'Connor提出通过传递一个自定义插值功能d3.svg.line()提供一个n-moving average

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

那里有很棒的工作。但是,我不能使它与另一个插值(如“单调”)一起工作。任何想法如何去与那? – Cystack 2014-10-16 17:07:21

+0

@Cystack注意更新的小提琴:http://jsfiddle.net/plmrry/ktLtN/ – 2014-10-17 18:05:54

+1

嗨,未来的人。这里是d3 v4的更新。请谢谢答复者。 http://stackoverflow.com/questions/41386083/plot-rolling-moving-average-in-d3-js-v4/41388581#41388581 – swyx 2017-01-01 05:04:08