1

I am using angular and plotly to plot either the raw data or a moving average. I have the moving average working but I am running into an issue with assigning variables. I retrieve an array of user objects which each have an x and y key with arrays associated with them.

$scope.init=function(){
   $rootScope.page='companyResults';
   $scope.isPlotlyDone = false;
   $scope.moving = false;

   var refresh = function () {
     incidentService.dayWiseTripsByUser(...).then(function (plotArray){
        $scope.unaffectedPlot = plotArray;
        $scope.movingAveragePlot = allMoving(plotArray);
        console.log($scope.unaffectedPlot[0].y);
        console.log($scope.movingAveragePlot[0].y);

     });
   };

   refresh();
 }

Im that code block, I would expect that $scope.unaffectedPlot[0].y and $scope.movingAveragePlot[0].y would have different arrays since I ran the latter through the following set of functions. The curious thing is that both $scope variables are synced, so if I run the second through allMoving the unaffectedPlot variable also gets smoothed and neither get synced obviously if I don't call allMoving. What am I missing about Angular? What is a good way to have a moving average work with a toggle? My plan is to show one variable or the other depending on if a button is clicked.

var d3_numeric = function(x) {
  return !isNaN(x);
}

var d3sum = function(array, f) {
  var s = 0,
      n = array.length,
      a,
      i = -1;
  if (arguments.length === 1) {
   // zero and null are equivalent
    while (++i < n) if (d3_numeric(a = +array[i])) s += a;
  } else {
    while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
  }
  return s;
};

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

var allMoving = function(pltArray) {
  var movingArray = [];
  pltArray.forEach(function(plot){
    var oneMoving = plot;
    oneMoving.y = movingWindowAvg(plot.y, 5);
    movingArray.push(oneMoving);

  });
  return movingArray;
}
Coherent
  • 1,933
  • 5
  • 24
  • 33

1 Answers1

2

This actually isn't an angular issue. I had to test it some since I didn't see what was going on either.

When you wrote

oneMoving.y = blah

you were actually altering the contents of plot for each element and in turn altering the contents of plotArray unintentionally (since plot is an object) So you are only creating a reference variable when you say 'var onMoving = plot' )

To outright solve your problem you can clone plot but that isn't so clean of a process

One easy yet dirty way is

JSON.parse(JSON.stringify(obj))

from this thread

I threw together a shotty example that captures what was going wrong for you

var array = [{one:1, two:2},{one:1, two:2},{one:1, two:2}],
    copyArray = array,
    newArr = doStuff(array)
function doStuff(a) {
    var otherNewArr = []
    a.forEach(function(ae) {
        var aVar = ae
        aVar.one = 5
        otherNewArr.push(aVar)
    })
    return otherNewArr
}
console.log(copyArray,newArr)

And to fix it just replace

var aVar = ae

with

var aVar = JSON.parse(JSON.stringify(ae))
Community
  • 1
  • 1
Dal
  • 165
  • 10
  • Thank you so much! Your solution totally solved the problem and I appreciate the example that you wrote. Javascript is a little funny sometimes, huh? – Coherent Nov 30 '16 at 04:28
  • 1
    no problem! glad that fixed it, too bad there isn't a clean and easy way to deep copy javascript objects – Dal Nov 30 '16 at 04:37