2015-09-03 41 views
1

這是問題here的後續問題。如何加載CSV和JSON文件,並使用d3.json,d3.csv和d3.zip將兩個數據集合併爲一個數據集

我想使用d3.csvd3.json加載多個數據集,然後使用d3.zip合併這些數據集。在下面的例子中,我只用了兩個。第一個數據集將存儲在xyData中,第二個存儲在colData中。我的目標是調用像

var combinedData = d3.zip(colData, xyData); 

然而,由於這些數據集僅是d3.csvd3.json範圍內的訪問,分別不起作用。有沒有解決方法?如果有更多的數據集要加載,那麼如何處理呢?

第一個數據集是這樣的:

//xyData.csv 
x,y 
0,0.00e+000 
0.6981317,6.43e-001 
1.3962634,9.85e-001 

JSON數據集如下所示:

//colData.json 
{ 
    "el1": [ 
     {"color": "green"}, 
     {"color": "purple"}, 
     {"color": "brown"} 
    ], 

    "el2": [ 
     {"color": "black"}, 
     {"color": "red"}, 
     {"color": "yellow"} 
    ], 

    "el3":[ 
     {"color": "brown"}, 
     {"color": "yellow"}, 
     {"color": "blue"} 
    ] 
} 

我讀到這些數據集,如下:

//using foreach 
    var xyData = [];  
    d3.csv("xyData.csv", function(myData) { 
     myData.forEach(function(d) { 
      d.x = +d.x; //convert data to numbers 
      d.y = +d.y; 
      }); 
      console.log(myData[1]); 
      xyData = myData; 
      console.log(xyData[1]) 
    }); 
    console.log(xyData) //this will be an empty array 

    //loading the json data 
    var colData = [];   
    d3.json("colData.json", function(error, jsonData) { 
     if (error) return console.warn(error); 
     colData = jsonData; 
     console.log(colData) 
     console.log(colData.el1[0]) 
    }); 
    console.log(colData) //this will be an empty array 

    //my goal would be: 
    //var combinedData = d3.zip(colData, xyData); 

console.log外觀像這樣:

Array [ ] 
Array [ ] 
Object { x: 0.6981317, y: 0.643 } 
Object { x: 0.6981317, y: 0.643 } 
Object { el1: Array[3], el2: Array[3], el3: Array[3] } 
Object { color: "green" } 

這表明加載數據按預期工作。但是,由於這些數據加載器的異步特性,將它們存儲爲全局變量不起作用(因此,這兩個數組仍然是空的)。

我的問題是:將兩個數據集合併到一個數據集的最佳方法是什麼?

+0

見https://stackoverflow.com/questions/21842384/importing -data-from-multiple-csv-files-in-d3或使用[queue.js](https://github.com/mbostock/queue)。 –

+0

您有經典的「如何從異步調用返回數據」問題,答案是 - 您不能。您*必須*在回調中完成所有工作,您不能在回調中設置變量,然後在回調之外進行工作。除了D3之外,你還使用其他庫嗎?哪個? jQuery可能嗎? – Tomalak

+0

@LarsKotthoff:我看到了這個問題,應該提到它。你如何處理兩個以上的輸入文件?你會創建一個巨大的嵌套結構嗎? – Cleb

回答

0

既然你說你有jQuery可用(*),我們可以使用它的Deferred功能來管理你正在查看的兩個異步操作。

我們正在通過將D3基於回調的方法轉換爲基於承諾的方法來實現這一點。

爲此,我們成立了兩個助手函數包D3的.csv.json助手,並返回jQuery的承諾:

d3.csvAsync = function (url, accessor) { 
    var result = $.Deferred(); 

    this.csv(url, accessor, function (data) { 
     if (data) { 
      result.resolve(data); 
     } else { 
      result.reject("failed to load " + url); 
     } 
    }); 
    return result.promise(); 
}; 

d3.jsonAsync = function (url) { 
    var result = $.Deferred(); 

    this.json(url, function (error, data) { 
     if (error) { 
      result.reject("failed to load " + url + ", " + error); 
     } else { 
      result.resolve(data); 
     } 
    }); 
    return result.promise(); 
}; 

現在,我們可以調用並行的請求,並將其存儲在變量。我們可以用.then()轉換上飛的結果,以及:

var colDataReq = d3.jsonAsync("colData.json"); 
var xyDataReq = d3.csvAsync("xyData.csv").then(function (data) { 
    data.forEach(function (d) { 
     d.x = +d.x; 
     d.y = +d.y; 
    }); 
    return data; 
}); 

最後,我們使用$.when() utility function伺候資源和讓他們由一個回調處理。

$.when(xyDataReq, colDataReq).done(function (xyData, colData) { 
    var combinedData = d3.zip(colData, xyData); 

    // now do something with combinedData 
}).fail(function (error) { 
    console.warn(error); 
}); 

這樣我們可以避免嵌套(並因此不必要地序列化)兩個請求。另外,由於請求存儲在變量中,因此我們可以簡單地重新使用它們而不必更改現有的功能。例如,如果你想記錄的請求之一的內容,你可以在任何地方你的代碼做到這一點:

xyDataReq.done(function (data) { 
    console.log(data); 
}); 

,並會盡快xyDataReq已經恢復運行。

這種做法的另一個後果就是 - 既然我們已經使用它脫鉤裝載資源從- 我們很早就進行加載,該頁面的其餘部分已經變得甚至之前。這可以節省更多時間。

+0

非常感謝,我會盡快測試(可能只有明天或週末),並在問題出現後再回復您。我經常聽說當jQuery和D3混合時有時會出現問題。你有沒有經歷過? – Cleb

+0

我不能說,迄今爲止我從未使用過D3。我假設這可能是真實的,如果你使用jQuery做了一半的UI工作,而用D3做了另一半。但在這種情況下,我沒有使用任何jQuery的UI功能,所以應該沒有重疊區域。這就是說,jQuery的Promise實現並不是最好的,如果你認爲這個方法本身值得追求,你可以切換到單獨的承諾實現來實現同樣的目標。我完全用jQuery來做,因爲你說它已經在項目中了。 – Tomalak

+0

好的,謝謝你對此的意見;讓我們看看我是否得到它運行,因爲我仍然需要學習很多關於這個話題。 – Cleb

0

D3.js實際上可以處理JavaScript對象而不是文件。如果用D3.json(myData){...}替換文件名與對象存儲的變量名稱(比方說,一個JSON數據數組),它將有權訪問該數據。假設我們使用jQuery,並且我們還包含一個稱爲Papa Parse的助手庫(它使得生活更輕鬆)。

步驟1.打開CSV數據轉換成JSON數據並將其存儲在一個變量A:

var A = Papa.parse(yourCSV); 

第2步:讀你的JSON數據並將其存儲在一個稱爲B

var B; 
$(document).ready(function() { 
$.getJSON('yourJSON.json', function(json){ 
    B = json; 
}); 
變量

});

步驟3.將數據集A和B爲重要的變量C:你可能需要格式化存儲在一個將CSV JSON看你如何期望它看起來我們給它之前D3後

var C={}; 
$.extend(C, A, B); 

第4步。給C給D3

d3.json(C, function(error, jsonData) { 
    // Use data here to do stuff 
}); 

我已經在我自己的項目中使用了上述方法。

你也許可以嘗試 D3.csv內調用D3.json ,但我以前沒試過這樣:

d3.csv("A.csv", function(errorA, dataA) { 
    d3.json("B.json", function(errorB, dataB) { 
    // Use data to do stuff 
    }); 
}); 
+0

謝謝格雷斯,我會在明天或週末測試一下。第二種方法是建議[這裏](https://stackoverflow.com/questions/21842384/importing-data-from-multiple-csv-files-in-d3),但這可能會變得凌亂,一旦想要加載更多比兩個數據組。感謝您的努力,歡迎來到stackoverflow :) – Cleb

+0

不客氣!謝謝,@Cleb。如果您遇到任何執行問題,請告訴我。 – Grace