Search code examples
javascriptdygraphs

How can I transform my objects with data to input for dygraphs?


I have a list of timeserieses. Each timeseries conists of objects that contain a timestamp and a value. The timestamps of the different timeserieses may or may not overlap. I want to plot these timeserieses in one DyGraph.

An example:

    data["first series"]  = [{timestamp: 1, value: 10.3},
                             {timestamp: 3, value: 12.5}]
    data["second series"] = [{timestamp: 2, value: 11.5},
                             {timestamp: 3, value: 13.0},
                             {timestamp: 4, value: 14.3}]

What's the most efficent way to transform my input data to a form suitable for DyGraph?


Solution

  • I had to do the exact same for a dygraphs project recently. At a high level, you will need to create a combined dataset so that there is one row per unique x value across all of your series. For the columns/series that do not have a value at given x, you can insert a null.

    I'll paste the general code I used here. This is a quick copy-paste and has been heavily modified, variables renamed, etc. It likely has a few minor errors. I was also using min/max with dygraph's customBars, which is why this code as pasted is using arrays for columns even where it probably isn't necessary.

    function combineSeries(seriesArr) {
    
      var dyDataRows = [];
    
      for (var seriesIdx = 0; seriesIdx < seriesArr.length; seriesIdx++) {
    
        var seriesData = seriesArr[seriesIdx];
    
        var newDyDataRows = [];
    
        var nextDataRowInsertIdx = 0;
        for (var dpIdx = 0; dpIdx < seriesData.length; dpIdx++) {
          var dp = seriesData[dpIdx];
    
          if (nextDataRowInsertIdx < dyDataRows.length) {
            var nextDataRowCols = dyDataRows[nextDataRowInsertIdx];
            var nextDataRowX = nextDataRowCols[0].getTime();
          }
    
          if (nextDataRowInsertIdx >= dyDataRows.length || dp.x < nextDataRowX) {
            var newDataRowCols = [new Date(dp.x)];
            for (var colIdx = 0; colIdx < seriesIdx; colIdx++) {
              newDataRowCols.push([null]);
            }
            newDataRowCols.push([dp.y]);
            newDyDataRows.push(newDataRowCols);
          }
          else if (dp.x > nextDataRowX) {
            var newDataRowCols = nextDataRowCols.slice(0);
            newDataRowCols.push([null]);
            newDyDataRows.push(newDataRowCols);
            nextDataRowInsertIdx++;
            dpIdx--;
          }
          else {//(dp.x == nextDataRowX) {
            var newDataRowCols = nextDataRowCols.slice(0);
            newDataRowCols.push([dp.y]);
            newDyDataRows.push(newDataRowCols);
            nextDataRowInsertIdx++;
          }
    
        }
    
        //insert any remaining existing rows
        for (var i = nextDataRowInsertIdx; i < dyDataRows.length; i++) {
          var nextDataRowCols = dyDataRows[i];
          var nextDataRowDateTm = nextDataRowCols[0];
    
          var newDataRowCols = nextDataRowCols.slice(0);
          newDataRowCols.push([null]);
          newDyDataRows.push(newDataRowCols);
        }
    
        dyDataRows = newDyDataRows;
      }
    
      return dyDataRows;
    };
    

    This is brute force approach, and there are likely more efficient JavaScript coding techniques. It worked for me though.