2017-06-17 40 views
0

我通過加載外部.CSV文件來繪製使用d3.js的圖。 我到目前爲止的代碼對於少量數據工作正常,但是當我用數千行加載更大的文件時,它會殺死頁面。優化CSV數據的javascript循環

數據有一個用量欄,它是一整天中每30分鐘一次的值,它將持續幾個月。

請參閱Plunker示例。

var avgClientArr = []; 
var dateArr = []; 
var dateGroupArr = []; 

function csvParseClient() { 
    d3.xhr('client.csv').get(function(err, response) { 
     var dirtyCSV = response.responseText; 
     var initialClientKeys = /TYPE,DATE,START TIME,END TIME,USAGE,UNITS,NOTES/i; 
     var newClientKeys = "TYPE,x,startTime,endTime,y,UNITS,NOTES"; 
     var csvDataClient = dirtyCSV.replace(initialClientKeys, newClientKeys); 
     var validData = csvDataClient.substr(csvDataClient.indexOf(newClientKeys)); 
     var csvData = d3.csv.parse(validData); 

     csvData.customForEach(function(val, i) { 
      // filter data 
      //var keep = ['x', 'startTime', 'endTime', 'UNITS', 'y']; 
      //for (var key in val[i]) { 
      // if (keep.indexOf(key) === -1) { 
      //  delete val[i][key]; 
      // } 
      //} 

      // parse data 
      var date = val.x; 
      var usage = val.y; 
      var startTime = val.startTime; 
      var endTime = val.endTime; 
      var x = new Date(date); 
      var y = parseFloat(usage); 

      dateArr.push({ 
       "date": x, 
       "usage": y 
      }) 
      dateGroupArr = groupBy(dateArr, 'date'); 
     }) 
console.log(dateGroupArr); 
     var objDates = objectValues(dateGroupArr); 

     objDates.customForEach(function(f) { 
       var avg = f.reduce(function(a, b) { 
        return a + b.usage; 
       }, 0)/f.length; 
       var date = f.reduce(function(a, b) { 
        return new Date(b.date); 
       }, 0); 
       avgClientArr.push({ 
        "x": date, 
        "y": avg 
       }) 
      }) 
      //console.log("avgClientArr", avgClientArr); 
     document.getElementById('arrayDiv').innerHTML = '<pre>' + JSON.stringify(avgClientArr, null, 4) + '</pre>'; 
    }) 
} 

function groupBy(arr, key) { 
    var reducer = (grouped, item) => { 
     var group_value = item[key] 
     if (!grouped[group_value]) { 
      grouped[group_value] = [] 
     } 
     grouped[group_value].push(item) 
     return grouped 
    } 
    return arr.reduce(reducer, {}) 
} 

function objectValues(object) { 
    var values = [] 
    for (var property in object) { 
     if (object.hasOwnProperty(property)) { 
      values.push(object[property]) 
     } 
    } 
    return values 
} 

function foreach(fn) { 
    var arr = this; 
    var len = arr.length; 
    for (var i = 0; i < len; ++i) { 
     fn(arr[i], i); 
    } 
} 

Object.defineProperty(Array.prototype, 'customForEach', { 
    enumerable: false, 
    value: foreach 
}); 

var t0 = performance.now(); 
csvParseClient(); 
var t1 = performance.now(); 
console.log("Call csvParseClient() " + (t1 - t0) + " milliseconds."); 

什麼,我需要發生

我需要使用的平均值爲全日返回y和當天的日期返回x的每一天。

的緩慢的過程,我有,因爲是在第幾行無用數據

  1. 啓動從CSV文件指定行循環。
  2. 將唯一日期進行分組並將該日期的每個使用情況值存儲在一個對象中。
  3. 平均每個日期的使用情況值。
  4. 輸出對象數組,其中x爲日期,y爲平均使用值。

如果你可以給我任何幫助,讓如何讓這個運行更快,那將是非常棒的!

+2

將較少的數據放入CSV文件中,即在瀏覽器中處理它之前將其聚合。 –

+0

http://papaparse.com/看起來像一個有用的庫,它具有流式傳輸功能。我試圖學習足夠的clojurescript來解決這個問題,但還沒有到達那裏。 – glallen

回答

0

我解決了這個問題,使用d3 nest()rollup()函數,它的功能簡單快速。

d3.nest() 
.key(function(d) { 
    return d.x; 
}) 
.rollup(function(d) { 
    var avg = d3.mean(d, function(g) {return g.y; }); 
    return avg; 
}).entries(dateArr);