2012-08-15 82 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