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

Posted

技术标签:

【中文标题】D3 - 如何处理 JSON 数据结构?【英文标题】:D3 - how to deal with JSON data structures? 【发布时间】:2012-04-22 14:11:00 【问题描述】:

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

谁能指出我做错了什么?

【问题讨论】:

【参考方案1】:

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

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

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

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

【讨论】:

【参考方案2】:

当您通过selection.data 选择join 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")
    …

如果您还没有,我建议您阅读这些教程:

Thinking with Joins Nested Selections

【讨论】:

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

以上是关于D3 - 如何处理 JSON 数据结构?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理需要反透视的 JSON 数据?

如何处理特定的 json 文件以获得数据框

如何处理反序列化变化的 JSON 数据?

如何处理 JSON 中常见的嵌套数据?哪种结构最好?

易语言如何处理json数据

前台如何处理后台返回的json数据