d3js:将CSV行与“g”元素配对

时间:2014-10-19 10:21:32

标签: d3.js

我正在努力重新创建this population pyramid by Mike Bostock。我有一个关于.data()如何运作的基本问题。

我在CSV文件中有数据如下:

enter image description here

所以,每个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); });

我最终得到了这个:

enter image description here

也就是说,我最终得到了50个g所有数据的元素,并且只为每个性别区域对创建了完整的条形图(男性来自多多马,女性来自多多马;来自Tanga的男性,来自Tanga的女性等)。因此,整个图表被重新绘制了50次。我有25个地区,因此我想要25个g元素,该地区的男性/女性数字。

我认为这可能都在.data()中。但我不知道如何告诉d3我想按区域对观察进行分组,最终每rectsg

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是如何解释这一点的。

enter image description here

2 个答案:

答案 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