我有两个单独的CSV文件,共享一个属性:
文件1
name,total
Frank,13
Mary,24
Jim,46
文件2
name,desc
Frank,yellow
Mary,blue
Jim,green
我如何将<{em>}属性desc
映射到文件1,所以,当我将鼠标悬停在Frank上时,我会看到“13”和“黄色”?
目前,我的代码看起来像这样:
d3.csv("data/csv/bilancio-missioni-desc.csv", function(descrizione) {
data = descrizione.map(function(data){
div.html("<h3>" + d.name + "</h3>" + "<p>" + data.desc + "</p>")
})
问题是d.name
和data.desc
(来自文件1和文件2)不匹配 - 我可以理解它是因为我没有将它们组合起来因此它们可以共享< / em>公共属性name
,但我不知道如何编写正确的代码。
更新 到目前为止我的代码:
d3.csv("data/csv/bilancio-tipologiedispesa-nest.csv", function(data1) {
d3.csv("data/csv/bilancio-missioni-desc.csv", function(data2) {
//code that depends on both data1 and data2
data1.forEach(d => {
data2.forEach(e => {
if (d.name === e.name) {
d.desc = e.desc;
}
});
});
// Fade all the segments.
d3.selectAll("path")
.style("opacity", .3);
vis.selectAll("path")
.filter(function(node) {
return (sequenceArray.indexOf(node) >= 0);
})
.style("opacity", 1);
div.transition()
.duration(200)
.style("opacity", .9);
div.html("<h3>" + d.name + "</h3>" + "<p>" + d.desc + "</p>");
});
});
}
如果我是console.log(data1),则将“desc”(来自data2)附加到data1(yay!)。但是“d.desc”在HTML中返回“unidefined”。
答案 0 :(得分:2)
加载多个CSV有两种主要方法:使用d3.queue()
或嵌套它们:
d3.csv("file1.csv", function(data1) {
d3.csv("file2.csv", function(data2) {
//code that depends on both data1 and data2
})
});
data1
是来自&#34; file1.csv&#34;的数组。 data2
是来自&#34; file2.csv&#34;的数组。
然后,我们将根据它们的属性合并两个数组。
您可以创建第三个数组或在两个原始数组之一中推送值。在这里,我会做第二个选项(实际上,第二个选项是你提出的问题:&#34;我如何&#34; map&#34;属性&#39; desc&#39;到文件1&#34; )。
请记住,这是一个 ad hoc 解决方案,我专门解决了您的问题(它不适用于其他数据结构):
data1.forEach(d => {
data2.forEach(e => {
if (d.name === e.name) {
d.desc = e.desc
}
})
})
现在,data1
包含您想要的所有信息:name,total和desc。
这是一个演示,请在控制台中查看数据(在此演示中,我使用<pre>
元素加载数据,因为我无法在代码段中使用CSV):
var data1 = d3.csvParse(d3.select("#file1").text());
var data2 = d3.csvParse(d3.select("#file2").text());
data1.forEach(d => {
data2.forEach(e => {
if (d.name === e.name) {
d.desc = e.desc
}
})
})
console.log(data1);
&#13;
pre {
display: none;
}
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="file1">name,total
Frank,13
Jim,46
Mary,24</pre>
<pre id="file2">name,desc
Frank,yellow
Mary,blue
Jim,green</pre>
&#13;
PS :如果您的文件太大,请在下面的评论中查看@altocumulus替代代码。
答案 1 :(得分:1)
正如Gerardo Furtado已经在answer中提出的那样,您将不得不使用d3.queue
或d3.csv
的嵌套版本来继续加载数据。当使用D3的两个内置功能时,可以优化嵌套方法,使您无法在初始加载后进行显式嵌套循环。
使用D3 Map可以name
属性快速访问您的数据。
使用row conversion function作为第二个可选参数传递给d3.csv(url[[, row], callback])
:
如果指定了行转换函数,则会为每一行调用指定的函数,并传递一个表示当前行的对象(
d
)...
这特别方便,因为在解析文件内容时,内部将迭代遍历行。您可以使用行转换功能作为挂钩,通过操作该函数中的映射,将第二个文件的数据同步到第一个文件的数据。
我设置Block演示了这种方法:
d3.csv("file1.csv", function(data1) {
// 1. Build a D3 map from your first file's contents
var map = d3.map(data1, function(d) { return d.name; });
d3.csv("file2.csv", function(row) {
// 2. Use the row function of the second file to match your data.
map.get(row.name).desc = row.desc; // 3. Sync data
return null; // 4. Don't append any row to the array.
}, function() { // 5. There is no parameter present; all data has been synced into data1.
// Just logging below
console.log(data1); // [{ name: "Frank", total: "13", desc: "yellow"}, ...]
})
});
让我一步一步地告诉你:
我们使用name
属性作为密钥,根据您第一个文件中的已解析数据构建地图。
在执行第二个文件的内部加载时,我们将行转换指定为第二个参数。通常,这将用于进行一些数据转换等,并返回一些表示实际行数据的转换对象。然而,在我们的场景中,我们对转换本身并不感兴趣,而是在隐式迭代和对行数据的访问中。
现在,我们已准备好通过getting从地图中对应此行name
的对象同步数据。
从行转换函数返回null
将避免为第二个文件构建数组,因为我们对内容的独立版本不感兴趣:
如果返回的值为null或未定义,则跳过该行并将从数组中省略...
在内部d3.csv()
的回调中,您的数据已准备就绪并已同步。请注意,我们没有将任何参数传递给此回调,因为我们将通过data1
访问同步数据。我们甚至不用再烦扰地图了,这只是一种允许从第一个文件快速访问我们的数据的方法。由于地图存储了对数据对象的引用,因此我们更新了data1
中用于构建地图的实际对象。
作为一种改进,你可能想要添加一些ES6糖,这使得它更简洁(ES6 Block):
d3.csv("file1.csv", data1 => {
let map = d3.map(data1, d => d.name);
d3.csv("file2.csv",
row => (map.get(row.name).desc = row.desc, null),
() => {console.log(data1)} // Merged data available at this point.
);
});
答案 2 :(得分:0)
如another answer中所述,您可以嵌套csv加载函数以异步加载文件。然后你可以将它们组合在一起:
var file1 = "data/csv/bilancio-missioni-desc.csv";
var file2 = "data/csv/bilancio-missioni-info.csv"; // I named it info just as an example
var div = d3.select('#my-div');
var data = {};
d3.csv(file1, function(descrizione) {
d3.csv(file2, function(info) {
processData(descrizione, info);
})
})
function processData(descrizione, info) {
descrizione.forEach(d => data[d.name] = d);
info.forEach(i => data[i.name] && data[i.name]['desc'] = i.desc);
appendData();
}
function appendData() {
div.data(data).append(d => '<h3>' + d.name + ' (' + d.total ')</h3> <p>' + d.desc + '</p>');
}
如果没有一些调整,这段代码可能无法正常工作,但我希望你能理解。如果没有,请告诉我你有什么不清楚的地方。祝你好运!