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

IT技术 javascript json svg d3.js
2021-03-16 13:07:13

我是 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个回答

当您通过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")
    …

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

@Ray 将此视为您问题的解决方案吗?
2021-04-26 13:07:13
很高兴我能帮上忙。如果这回答了您的问题,请添加复选标记以解决它。谢谢!
2021-04-27 13:07:13
再次您好,该解决方案不起作用。这次完全没有图像:\
2021-05-02 13:07:13
实际上,为了学习进入-更新-退出模式,我更喜欢 Mike 的“3 个小圆圈”,这是一个最近的教程,它使一切变得非常清楚。bost.ocks.org/mike/circles
2021-05-12 13:07:13
嗨迈克,我很荣幸能得到你的帮助 :) 在这个例子中我想要的是获取单个 SVG 图像。似乎我的错误不是使用 .data([data]),而是使用 .data(data)。不幸的是,我无法立即检查,但我今晚会检查。我之前浏览过“嵌套选择”。这似乎没有涵盖这个主题,但既然你推荐了它,我将深入研究这些教程。我会更新这个帖子。谢谢!
2021-05-15 13:07:13

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

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

这是一个解决方案:每个用户由一个组g元素表示,每个分数由一个rect. 您可以通过以下几种方式执行此操作:datum在 svg 上使用,然后在 each 上使用标识函数g,或者您可以直接在g. 使用dataong是更典型的,但这里有两种方式:

在 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;
}