我正在努力重新创建this population pyramid by Mike Bostock。我有一个关于.data()
如何运作的基本问题。
我在CSV文件中有数据如下:
所以,每个region
(多多马,阿鲁沙等)都有男性和女性的数量。按照迈克的例子,我想创建一个条形图,其中男性和女性占据不同的rects
,与80%opacity
重叠。我希望region
成为我的x轴,并将人数作为我的y轴。这是我的x轴和y轴刻度:
var x = d3.scale.ordinal()
.rangeRoundBands([0, w], 0.05);
var y = d3.scale.linear()
.range([0, h-padding]);
我的尝试是将男性和女性分组到每个地区:
var regions = svg.append("g")
.classed("regions", true);
var region = regions.selectAll(".region")
.data(dataset)
.enter()
.append("g")
.attr("class", "region")
.attr("transform", function(region) { return "translate(" + x(region) + ",0)"; });
region.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return x(i);
})
.attr("y", function(d) { return h - y(d.people_0); })
.attr("width", barWidth)
.attr("height", function(d) { return y(d.people_0); });
我最终得到了这个:
也就是说,我最终得到了50个g
个所有数据的元素,并且只为每个性别区域对创建了完整的条形图(男性来自多多马,女性来自多多马;来自Tanga的男性,来自Tanga的女性等)。因此,整个图表被重新绘制了50次。我有25个地区,因此我想要25个g
元素,仅该地区的男性/女性数字。
我认为这可能都在.data()
中。但我不知道如何告诉d3我想按区域对观察进行分组,最终每rects
个g
。
Here's my JSFiddle(虽然我不知道如何加载我的外部数据 - 所以没有显示任何内容;任何提示都会受到赞赏)。
已编辑添加:
鉴于本杰明的评论,我已尝试使用.nest
。所以我得到了:
dataset = d3.nest()
.key(function(d) { return d.round; })
.key(function(d) { return d.region; })
.rollup(function(v) { return v.map(function(d) { return d.people_0; }); })
.map(dataset);
我现在正在调用我的rects
:
region.selectAll("rect")
.data(function(region) { return data[round][region]; })
.enter()
.append("rect")
.attr("x", function(d, i) {
return x(i);
})
.attr("y", function(d) { return h - y(d.people_0); })
.attr("width", barWidth)
.attr("height", function(d) { return y(d.people_0); });
没有运气。 FWIW,console.log(dataset)
告诉我数据确实已经汇总了。但是我仍然无法调用它并将其与我的g.region
元素相关联。
有人可以解释data[round][region]
的作用吗?我不明白d3是如何解释这一点的。
答案 0 :(得分:1)
http://bost.ocks.org/mike/selection/解释了d3中数据的工作原理。如果你调用它一次,它会将每个数据条目“绑定”到你指定的元素。
在你的情况下,你必须按区域嵌套(),你得到一个看起来像这样的对象数组:
['regionA' : [{region, sex, people}, {region, sex, people}], 'regionB' : [{region, sex, people}, {region, sex, people}]
然后,你会对数据进行双重迭代。所以你先调用.data()
(这次是一个区域数组,即regionA)并将其绑定在一个名为region的组中
然后再次绑定data()
(这次是一个区域的对象数组,即[{region,sex,people},{region,sex,people}])矩形。
答案 1 :(得分:1)
有几种方法可以做到这一点。我的方法是按地区,然后按性别为数据创建一个两级嵌套:
dataset = d3.nest()
.key(function(d) {
return d.region;
})
.sortKeys(d3.ascending)
.key(function(d) {
return d.sex;
})
.entries(dataset);
这将为您提供一个易于使用的结构,它看起来像这样:
key: "dodoma"
values:
key: "female"
values:
people_0: "43"
region: "dodoma"
sex: "female"
key: "male
values:
people_0: "77"
region: "dodoma"
sex: "male"
key: "killimanj"
values: ...
这非常冗长,可以简化一点(例如使用.map
)。 This is a great nest tutorial page了解更多信息。
从那时起,只需要进行一些更改即可绘制rect
。请参阅此插件:http://embed.plnkr.co/PPLbQER4FERA6D7T4m9P/preview。
如果你想顺便链接外部数据,那么Plunker(http://plnkr.co/)是jsfiddle的一个很好的替代品。
一些变化与Mike的原始示例不同,包括在CSS中使用class="male"
\ "female"
获取蓝色/粉红色,而不是使用rect:first-child