2
votes

I'm using d3 to visualize some data. One of my data sets with the form of:

[[date, value], [date, value], etc...] jumps around a lot, and I'd like to incorporated a moving average.

I found this function from Stack Overflow as a solution to calculating moving average, but I don't feel right using it because (1) I don't understand how it works, and (2), it doesn't seem to work with my data.

Here's the function (taken from d3.js moving average with previous and next data values):

var movingWindowAvg = function(arr, step) {
        return arr.map(function(_, idx) { 
          var wnd = arr.slice(idx - step, idx + step + 1); 
          var result = d3.sum(wnd) / wnd.length; if (isNaN(result)) { result = _; }
          return result;
        });
      };

Line-by-line:

var movingWindowAvg = function(arr, step) {

Create a function with the params of a 1D array and a step that decides how many values you are using to each individual average point.

return arr.map(function(_, idx) { 

Map the array to (something?), I know _ is a wildcard operator, like from OCaml, and idx is the id?

var wnd = arr.slice(idx - step, idx + step + 1);

Seems like wnd stands for window, so finding the subset of the data to use as an averaging window for the first moving average point.

var result = d3.sum(wnd) / wnd.length; if (isNaN(result)) { result = _; }

Actually calculating the average.

Overall: I guess my big question is, going through this function, it seems like it's for finding the moving average of a 1D array. In order to use it, do I have to transform my data into a 1D array, or is there a way to alter the function itself slightly? I'm having a hard time altering the function because syntactically it's a bit confusing.

1

1 Answers

2
votes

I have to agree this code is a bit confusing. If I understand correctly it works with 1D arrays? And you'd like it to work with 2D arrays. I'm guessing you would like to have a movingWindowAvg with 'value'.

.map() is a function that loops through your array. So for the first loop. _ = [0,0] and idx = 0, then for the second loop _ = [1,1] and idx = 1. To get the right value for _ , all you need to do is _ = _[1]'

I made a little conversion function to transform your sliced 2D array wnd to 1D array, since I don't really know how d3 works.

isNaN(result) just checks if the result is not a number, and will give it a number _

var data = [
    [0, 0],
    [1, 1],
    [2, 2],
    [3, 3]
];

var movingWindowAvg = function(arr, step) {
        return arr.map(function(_, idx) { 
          _=_[1];
          var wnd = arr.slice(idx - step, idx + step + 1); 
          alert('wnd: ' + wnd);
          var result = d3.sum(to1D(wnd)) / wnd.length;
          if (isNaN(result))
          { 
              result = _; 
              alert('not a res ' + _);
          }
          return result;
        });
};
console.log(movingWindowAvg(data, 1));

function to1D(wnd)
{
    var nwnd = new Array();
    for(var i = 0; i < wnd.length; i++)
    {
         nwnd.push(wnd[i][1]); //1 to access value   
    }
    return nwnd;

}

Here is a jsfiddle with a working demo: http://jsfiddle.net/Grimbode/6mNWE/1/