D3 - 如何处理JSON数据结构?

时间:2012-04-10 09:27:55

标签: javascript json svg d3.js

我是D3的新手,花了几个小时才找到处理结构化数据的任何事情,但没有积极的结果。 我想使用下面的数据结构创建一个条形图。 条形图(水平)绘制,但仅适用于用户“jim”。

var data = [{"user":"jim","scores":[40,20,30,24,18,40]},
            {"user":"ray","scores":[24,20,30,41,12,34]}];

var chart = d3.select("div#charts").append("svg")                                   
              .data(data)
              .attr("class","chart")
              .attr("width",800)
              .attr("height",350);

chart.selectAll("rect")    
    .data(function(d){return d3.values(d.scores);})    
    .enter().append("rect")
    .attr("y", function(d,i){return i * 20;})
    .attr("width",function(d){return d;})
    .attr("height", 20);

有人能指出我做错了吗?

2 个答案:

答案 0 :(得分:93)

当您通过join data selection.data进行选择时,数据数组中的元素数量应与选择中的元素数量相匹配。您的数据数组有两个元素(对于Jim和Ray),但是绑定它的选择只有一个SVG元素。您是在尝试创建多个SVG元素,还是将Jim和Ray的得分都放在同一个SVG元素中?

如果要将两个数据元素绑定到单个SVG元素,可以将数据包装在另一个数组中:

var chart = d3.select("#charts").append("svg")
    .data([data])
    .attr("class", "chart")
    …

或者,使用selection.datum,它直接绑定数据而不计算连接:

var chart = d3.select("#charts").append("svg")
    .datum(data)
    .attr("class", "chart")
    …

如果您想为每个人创建多个SVG元素,那么您需要一个数据连接:

var chart = d3.select("#charts").selectAll("svg")
    .data(data)
  .enter().append("svg")
    .attr("class", "chart")
    …

第二个问题是你不应该将d3.values与数组一起使用;该函数用于提取对象的值。假设你每个人想要一个SVG元素(因此,在这个例子中是两个),那么rect的数据就是那个人的相关分数:

var rect = chart.selectAll("rect")
    .data(function(d) { return d.scores; })
  .enter().append("rect")
    …

如果您还没有,我建议您阅读以下教程:

答案 1 :(得分:1)

除了mbostock的正确答案之外,这可能会澄清嵌套方面。

您的数据有2度嵌套。你有一个包含2个对象的数组,每个对象都有一个int数组。如果您希望最终图像反映出这些差异,则需要为每个图像进行连接。

以下是一个解决方案:每个用户都由一个组g元素表示,每个分数由rect表示。您可以通过以下几种方式执行此操作:在svg上使用datum,在每个g上使用身份功能,或者您可以直接加入g上的数据。在data上使用g更为典型,但这里有两种方式:

在svg上使用数据:

var chart = d3.select('body').append('svg')
  .datum(data)             // <---- datum
  .attr('width',800)
  .attr('height',350)
  .selectAll('g')
  .data(function(d){ return d; })  // <----- identity function
  .enter().append('g')
    .attr('class', function(d) { return d.user; })
    .attr('transform', function(d, i) { return 'translate(0, ' + i * 140 + ')'; })
    .selectAll('rect')
    .data(function(d) { return d.scores; })
    .enter().append('rect')
      .attr('y', function(d, i) { return i * 20; })
      .attr('width', function(d) { return d; })
      .attr('height', 20);

使用组(g)元素上的数据:

var chart = d3.select('body').append('svg')
  .attr('width',800)
  .attr('height',350)
  .selectAll('g')
  .data(data)          // <--- attach directly to the g
  .enter().append('g')
    .attr('class', function(d) { return d.user; })
    .attr('transform', function(d, i) { return 'translate(0, ' + i * 140 + ')'; })
    .selectAll('rect')
    .data(function(d) { return d.scores; })
    .enter().append('rect')
      .attr('y', function(d, i) { return i * 20; })
      .attr('width', function(d) { return d; })
      .attr('height', 20);

同样,你不必创建这些g元素,但通过这样做,我现在可以用不同的方式表示用户分数(它们与变换有不同的y),我也可以给它们不同的样式,比如这个:

.jim {
  fill: red;
}
.ray {
  fill: blue;
}