我正在尝试在d3.js中构建一个动态加载条形图,它将从后端部分加载数据。使用d3.csv()
函数,有没有办法从初始绘制的数据中只读取第一个n
行数,然后根据我的JS逻辑加载后续数据?
tl; dr 我想有选择地访问d3.csv()
函数中的数据。
我正在尝试运行以下代码:
var margin = {
top: 20,
bottom: 30,
left: 40,
right: 30
},
width = 600 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var loadData = function() {
d3.csv("test_data.csv", function(data) {
console.log(data.filter(function(d, i) {
return i < 2;
}));
console.log(data.filter(function(d, i) {
return i < 3;
}))
})
}
loadData();
但是,我在控制台中收到错误:
未捕获(承诺)TypeError:data.filter不是函数(...)
这让我相信这个数据不是一个数组。是这种情况还是我在这里遇到其他问题?
另外,如何在d3.csv
函数中访问列(csv文件内)? (例如,如果我的csv数据文件包含两个名为a和b的列。)
答案 0 :(得分:4)
首先,无法仅使用n
加载/解析CSV的第一行d3.csv
,我担心这是不可能的。不幸的是,您将不得不加载/解析所有文件,如果文件很大,这可能会很不方便,这意味着用户必须等待整个文件在绘制图表之前加载/解析。此外,值得一提的是,由于d3.csv
将加载所有文件,后续过滤器无关紧要:只需使用您想要的数据行,不要向浏览器添加更多不必要的任务,只需使用您想要的行绘制图表。
回到你的主要问题:
您的数据是一个数组。这里的问题只是你使用d3.csv
就好像是XHR,这是D3 v4的情况......但是,在D3 v5中,d3.csv
是一个承诺。
所以,必须是:
d3.csv(url).then(callback);
看一下下面的演示:
var csv = URL.createObjectURL(new Blob([
`foo,bar,baz
12,43,21
45,54,21
87,13,17
98,69,17`
]));
d3.csv(csv).then(function(data) {
console.log(data.filter(function(d, i) {
return i < 2;
}));
})
<script src="https://d3js.org/d3.v5.min.js"></script>
关于第二个问题,d3.csv
公开名为columns
的数组属性中的列:
var csv = URL.createObjectURL(new Blob([
`foo,bar,baz
12,43,21
45,54,21
87,13,17
98,69,17`
]));
d3.csv(csv).then(function(data) {
console.log("columns are: " + data.columns)
})
<script src="https://d3js.org/d3.v5.min.js"></script>
答案 1 :(得分:2)
要添加到Gerardo Furtado的答案中有一件事:您的示例结构如下:
d3.csv('some_file.csv', someFunction)
在d3.csv
V5中,如果函数在此处作为参数传递,则每个行 会调用一次,传递 object 表示该行,其索引和列键数组,允许更改行。因此,特定错误是因为此回调中的第一个arg是表示行的对象,而不是表示数据集的数组。
然后,当他们全部完成后,承诺就完成了,并且.then(someFunction)
提供了一个回调。
d3.csv('some_file.csv', transformRow).then(processData)
transformRow
函数是可选的;如果提供了一个,那么每行返回的内容都会替换数据中的那一行。
然后processData
回调获取一个行数组,其属性为columns
,这是原始列名称的数组(因此如果transformRow
返回一个具有不同属性键的对象,data.columns
不匹配每行的属性。)
例如:
var csv = URL.createObjectURL(new Blob([
`name,start,end
SOMETHING,123,321
INVALID,321,123
ANOTHER,111,333`
]));
d3.csv(csv, processRow).then(processData)
function processRow (row, index, columnKeys) {
row[columnKeys[0]] = row[columnKeys[0]].trim().toLowerCase()
row.duration = row.end - row.start // this new property doesn't change data.columns
if (row.end > row.start) return row
}
function processData (data) {
console.log(data, data.columns)
}
&#13;
<script src="https://d3js.org/d3.v5.min.js"></script>
&#13;