2016-08-21 59 views
5

数据结构:d3.js:访问数据嵌套2电平向下

var data = [ 
    {name: "male", 
    values: [ 
    { count: 12345, 
     date: Date 2015-xxx, 
     name: "male" }, 
    {...} 
    ] 
    }, 
    {name: "female", 
    values: [ 
    { count: 6789, 
     date: Date 2015-xxx, 
     name: "female" }, 
    {...} 
    ] 
    } 
] 

,我想访问的值是数据并[a] .values并[b] .Count之间

的值用于以画圈圈我的阴谋

代码圈剧情:

focus.selectAll(".dot") 
    .data(data) 
    .enter().append("circle") 
    .attr("class", "dot") 
    .attr("cx", function(d,i) { return x(d.values[i].date); }) 
    .attr("cy", function(d,i) { return y(d.values[i].count); }) 
    .attr("r", 4) 
    .style("fill", function(d,i) { return color(d.values[i].name); }) 

的问题是,i = 1因为...它在物体中的位置。

我想要做的是循环所有objects根据values。我怎样才能做到这一点?

编辑:我想学习如何在不改变数据的情况下做到这一点,以提高我的技能。

谢谢。

回答

4

最简单的方法是使用像underscore.js这样的库来编辑数据数组。

来自下划线文档:

弄平 _.flatten(数组,[浅]) 展平嵌套阵列(嵌套可以是任何深度)。如果你传递的是浅的话,那么这个数组只会被平化为一个单一的等级。

_.flatten([1, [2], [3, [[4]]]]); 
-> [1, 2, 3, 4]; 

_.flatten([1, [2], [3, [[4]]]], true); 
-> [1, 2, 3, [[4]]]; 

地图 _.map(列表,iteratee,[上下文])别名:收集 通过经由>变换函数(iteratee)映射在列表中的每个值将产生的值的一个新的数组。迭代器传递三个参数:>值,然后是迭代的索引(或键),最后是对>整个列表的引用。

_.map([1, 2, 3], function(num){ return num * 3; }); 
=> [3, 6, 9] 
_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; }); 
=> [3, 6, 9] 
_.map([[1, 2], [3, 4]], _.first); 
=> [1, 3] 

Underscore documentation

在你的代码,你可以做这样的事情:

var flatData = _.flatten(_.map(data, (d)=>d.values)); 
focus.selectAll(".dot") 
    .data(data) 
    .enter().append("circle") 
    .attr("class", "dot") 
    .attr("cx", function(d,i) { return x(d.date); }) 
    .attr("cy", function(d,i) { return y(d.count); }) 
    .attr("r", 4) 
.style("fill", function(d,i) { return color(d.name); }) 
+2

感谢,它的工作原理,但有可能只用纯JS或D3做到这一点不改变数据?我想提高我的技能:) – Shawn

+0

@shawn当然可以。 Underscore.js是开源的,你可以检查事情是如何完成的。这并不难理解。代码在这里:http://underscorejs.org/underscore.js 你不能轻易地做到这一点与D3没有改变数据......有一种方法,但它没有优化。你quand做一个foreach数据,然后做焦点。选择所有值,并以这种方式追加你的圈子。 – rm4

1

有几种方法你只想使用D3做什么,没有任何其他图书馆和无改变数据。其中之一是使用groups来处理“更高”的数据级别(关于嵌套数据)。让我们来看看它在此代码:

首先,我嘲笑了一个数据集,就像你:

var data = [ 
    {name: "male", 
    values: [{ x: 123,y: 234}, 
     { x: 432,y: 221}, 
     { x: 199,y: 56}] 
    }, 
    {name: "female", 
    values: [{ x: 223,y: 111}, 
     { x: 67,y: 288}, 
     { x: 19, y: 387}] 
    } 
]; 

这是数据我们要去使用。我要让散点图这里(只是作为一个例子),所以,让我们设置的域访问数据的(内部valuesxy)第二级的尺度:

var xScale = d3.scaleLinear().range([20, 380]) 
    .domain([0, d3.max(data, function(d){ 
     return d3.max(d.values, function(d){ 
      return d.x; 
     }) 
})]); 

var yScale = d3.scaleLinear().range([20, 380]) 
    .domain([0, d3.max(data, function(d){ 
     return d3.max(d.values, function(d){ 
      return d.y; 
     }) 
})]); 

现在到了最重要的部分:我们要绑定的数据“组”,而不是圆的元素:

var circlesGroups = svg.selectAll(".circlesGroups") 
    .data(data) 
    .enter() 
    .append("g") 
    .attr("fill", function(d){ return (d.name == "male") ? "blue" : "red"}); 

一旦数据的第一个层次,我们有2个对象,D3将创建2组给我们。

我还使用了组设置圆的颜色:如果name是“男性”,该圆圈为蓝色,否则它是红色:现在

.attr("fill", function(d){ return (d.name == "male") ? "blue" : "red"}); 

,与组创建,我们建立社交圈根据每个组的数据的values,结合数据,如下所示:

var circles = circlesGroups.selectAll(".circles") 
     .data(function(d){ return d.values}) 
     .enter() 
     .append("circle"); 

这里,function(d){ return d.values}将根据values阵列内的对象的数据绑定到的社交圈。

然后你定位你的圈子。这是整个代码,点击“运行代码片断”可以看到:

var data = [ 
 
    {name: "male", 
 
    values: [{ x: 123,y: 234}, 
 
     { x: 432,y: 221}, 
 
     { x: 199,y: 56}] 
 
    }, 
 
    {name: "female", 
 
    values: [{ x: 223,y: 111}, 
 
     { x: 67,y: 288}, 
 
     { x: 19, y: 387}] 
 
    } 
 
]; 
 

 
var xScale = d3.scaleLinear().range([20, 380]) 
 
\t .domain([0, d3.max(data, function(d){ 
 
\t \t \t return d3.max(d.values, function(d){ 
 
\t \t \t \t return d.x; 
 
\t \t }) 
 
\t })]); 
 
\t \t 
 

 

 
var yScale = d3.scaleLinear().range([20, 380]) 
 
    .domain([0, d3.max(data, function(d){ 
 
\t \t \t return d3.max(d.values, function(d){ 
 
\t \t \t \t return d.y; 
 
\t \t }) 
 
\t })]); 
 

 
var xAxis = d3.axisBottom(xScale).tickSizeInner(-360); 
 
var yAxis = d3.axisLeft(yScale).tickSizeInner(-360); 
 

 
var svg = d3.select("body") 
 
\t .append("svg") 
 
\t .attr("width", 400) 
 
\t .attr("height", 400); 
 

 
svg.append("g") 
 
\t .attr("class", "x axis") 
 
\t .attr("transform", "translate(0,380)") 
 
\t .call(xAxis); 
 
\t 
 
svg.append("g") 
 
\t .attr("class", "y axis") 
 
\t .attr("transform", "translate(20,0)") 
 
\t .call(yAxis); 
 
\t 
 
var circlesGroups = svg.selectAll(".circlesGroups") 
 
\t .data(data) 
 
\t .enter() 
 
\t .append("g") 
 
\t .attr("fill", function(d){ return (d.name == "male") ? "blue" : "red"}); 
 
\t 
 
var circles = circlesGroups.selectAll(".circles") 
 
\t .data(function(d){ return d.values}) 
 
\t .enter() 
 
\t .append("circle"); 
 
\t \t 
 
circles.attr("r", 10) 
 
\t .attr("cx", function(d){ return xScale(d.x)}) 
 
\t .attr("cy", function(d){ return yScale(d.y)});
.axis path, line{ 
 
\t stroke: gainsboro; 
 
}
<script src="https://d3js.org/d3.v4.min.js"></script>

+0

谢谢,这是一个非常明确的例子,我学到了新东西:) – Shawn