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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10086167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 23:47:38  来源:igfitidea点击:

D3 - how to deal with JSON data structures?

javascriptjsonsvgd3.js

提问by Ray

I'm new to D3, and spent already a few hours to find out anything about dealing with structured data, but without positive result. I want to create a bar chart using data structure below. Bars are drawn (horizontally), but only for user "jim".

我是 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);

Could anyone point what I did wrong?

谁能指出我做错了什么?

回答by mbostock

When you join datato a selection via selection.data, the number of elements in your data array should match the number of elements in the selection. Your data array has two elements (for Jim and Ray), but the selection you are binding it to only has one SVG element. Are you trying to create multiple SVG elements, or put the score rects for both Jim and Ray in the same SVG element?

当您通过selection.data将数据连接选择时,数据数组中的元素数应与选择中的元素数相匹配。您的数据数组有两个元素(对于 Jim 和 Ray),但是您将其绑定到的选择只有一个 SVG 元素。您是要创建多个 SVG 元素,还是将 Jim 和 Ray 的得分矩形放在同一个 SVG 元素中?

If you want to bind both data elements to the singular SVG element, you can wrap the data in another array:

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

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

Alternatively, use selection.datum, which binds data directly without computing a join:

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

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

If you want to create multiple SVG elements for each person, then you'll need a data-join:

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

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

A second problem is that you shouldn't use d3.valueswith an array; that function is for extracting the values of an object. Assuming you wanted one SVG element per person (so, two in this example), then the data for the rect is simply that person's associated scores:

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

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

If you haven't already, I recommend reading these tutorials:

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

回答by Tristan Reid

This may clarify the nested aspect, in addition to mbostock's fine answer.

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

Your data has 2 degrees of nesting. You have an array of 2 objects, each has an array of ints. If you want your final image to reflect these differences, you need to do a join for each.

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

Here's one solution: Each user is represented by a group gelement, with each score represented by a rect. You can do this a couple of ways: Either use datumon the svg, then an identity function on each g, or you can directly join the data on the g. Using dataon the gis more typical, but here are both ways:

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

Using datum on the svg:

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

Using data on the group (g) element:

使用组 ( 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);

Again, you don't have to create these g elements, but by doing so I can now represent the user scores differently (they have different y from the transform) and I can also give them different styles, like this:

同样,您不必创建这些 g 元素,但是通过这样做,我现在可以以不同的方式表示用户分数(它们具有与变换不同的 y),并且我还可以为它们提供不同的样式,如下所示:

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