我正在尝试在 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();
但是,我在控制台中收到错误:
未捕获(承诺中)类型错误:data.filter 不是一个函数(...)
这让我相信这些数据不是一个数组。是这种情况还是我在这里面临其他问题?
另外,如何访问此d3.csv
函数中的列(csv 文件内)?(例如,如果我的 CSV 数据文件包含名为 A 和 B 的两列)。
首先,没有办法使用d3.csv
加载/解析 CSV 的前n
行,恐怕这是不可能的。不幸的是,您必须加载/解析所有文件,如果文件很大,这可能会很不方便,这意味着用户必须等待整个文件加载/解析才能绘制图表。另外,值得一提的是,由于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>
Gerardo Furtado的答案要补充一件事:你的例子是这样的结构:
d3.csv('some_file.csv', someFunction)
在d3.csv
V5 中,如果一个函数在这里作为这样的参数传递,则每行调用一次,传递一个表示该行的对象、其索引和列键数组,从而允许更改行。因此,具体错误是因为此回调中的第一个 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)
}
<script src="https://d3js.org/d3.v5.min.js"></script>