我正在尝试根据标题制作一排高度和宽度相等的条形图。数组包含100个对象,每个对象都包含一个称为 results 的 key ,它本身以及其他20个对象的数组,因此最终结果必须是一排2000条,但是我只得到20条:
Codepen:https://codepen.io/ekilja01/pen/RdJqGO
数据是一个对象数组,具有名为 结果 的对象数组,格式如下:
0:
page: 1
results: Array(20)
0: {vote_count: 17968, id: 19995, video: false, vote_average: 7.4, title: "Avatar", …}
...
length: 20
1: {page: 2, total_results: 406130, total_pages: 20307, results: Array(20)}
2: {page: 3, total_results: 406130, total_pages: 20307, results: Array(20)}
这是我的方法:
d3.json('data.json').then(data => {
console.log(data);
for (let i = 0; i < data.length; i++) {
//x and y domain
xScale.domain(data[i].results.map(d => d.title));
yScale.domain(data[i].results.map(d => d.original_title));
svg.selectAll('rect')
.data(data[i].results)
.enter()
.append('rect')
.style('fill', 'red')
.attr('width', xScale.bandwidth())
.attr('height', 70)
.attr('x', function (d) {
return xScale(d.title);
})
.attr('y', function (d) {
return yScale.bandwidth() + 175;
});
}
}).catch(error => console.log(error));
答案 0 :(得分:2)
好的问题描述和CodePen-可以轻松帮助您!
我为您的CodePen link作了一个简短修改的版本
基本上,发生的事情是对于for循环中的每个迭代,您将选择匹配rect
元素的前x个(在您的情况下为20个)。这意味着,在第一次迭代之后,每次迭代都将用当前迭代的20个数据条目替换与相同的20个rect
元素的数据绑定。
我进行了两项更改以解决此问题:
svg.selectAll('rect')
更改为svg.selectAll('.rect_${i}')
,以选择具有相应类(.rect_0
,.rect_1
等)的所有元素。这样做可以防止覆盖先前的rect
元素。+ xScale.range()[1] * i
添加到.attr('x')
的回调函数中。这样会将每20个rect
元素移到右侧,以确保rect
元素不会相互重叠。第2点的确可以绘制出非常宽的图表。如果您希望各行之间彼此相邻,我使用了rect
元素的高度添加了功能(在注释中)。
让我知道这是否对您有帮助!
答案 1 :(得分:2)
在循环中,您仅在循环中第一次添加元素:数据数组中有20个项目,svg中没有矩形,因此输入了全部20个项目。第二次数据数组中有20个项目,svg中有20个矩形,因此enter选择为空,新数据仅绑定到20个现有矩形。
作为另一个答案的替代方法,您的数据似乎不是分层的,但是您具有分层的结构。如果您的数据结构与DOM结构相同,那么这将更加简单。让我们对数据进行一些重组:
var combined = [];
for (let i = 0; i < data.length; i++) {
combined.push(...data[i].results);
}
现在我们的数据是:
[
{vote_count: 17968, id: 19995, video: false, vote_average: 7.4, title: "Avatar", …,}
{...},
{...},
...
所有要映射的对象都在一个数组中,该数组中的一项,一个要添加到图表中的元素。现在我们可以做一个简单的输入循环:
svg.selectAll('rect')
.data(combined)
.enter()
.append('rect')
.style('fill', 'red')
.attr('width', xScale.bandwidth())
.attr('height', 70)
.attr('x', function (d) {
return xScale(d.title);
})
.attr('y', function (d) {
return yScale.bandwidth() + 175;
});
通常,如果需要循环以在DOM中输入元素,则不会使用惯用的d3。通过避免for循环输入元素,缩放也变得更加容易,因为在遍历父数组时我们不会不断更新它。比例域和范围只需设置一次。
这是更新的codepen。
现在,2000个元素将生成非常小的矩形,可能小于一个像素宽,我不确定为什么要像这样缩放条形的高度,但这是不同的问题。 / em>