d3.js:访问数据嵌套2级

时间:2016-08-21 00:30:26

标签: javascript json d3.js

数据结构:

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

我想要访问的值是data [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。我怎样才能做到这一点?

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

感谢。

2 个答案:

答案 0 :(得分:4)

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

来自下划线文档:

  

展平 _.flatten(数组,[浅])   展平嵌套数组(嵌套可以是任何深度)。如果你传递浅,>数组将只被压平一个级别。

var pairList = {
    key1: 'variableType1',
    key2: 'variableType2',
    // more pairs
};
var bleh = function(obj) {
    for (var pair in pairList) {
        var key = pair;
        var type = pairList[pair];
        if (typeof obj[key] != type) {
            return false;
        }
    }
    return true;
}
     

地图 _.map(list,iteratee,[context])别名:collect   通过一个>转换函数(iteratee)映射列表中的每个值,生成一个新的值数组。迭代器传递三个参数:>值,然后是迭代的索引(或键),最后是对>整个列表的引用。

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

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

Underscore documentation

在您的代码中,您可以执行以下操作:

_.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]

答案 1 :(得分:4)

有几种方法可以只使用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}]
    }
];

这是我们要使用的数据。我将在这里制作一个散点图(仅作为示例),因此,让我们为访问第二级数据的比例设置域(xy内的values) :

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])
	.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 xAxis = d3.axisBottom(xScale).tickSizeInner(-360);
var yAxis = d3.axisLeft(yScale).tickSizeInner(-360);

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

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