【问题标题】:d3.js: Access data nested 2 level downd3.js:访问嵌套 2 级的数据
【发布时间】:2016-12-27 20:15:45
【问题描述】:

数据结构:

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因为它在对象中的位置。

我要做的是循环遍历values下的所有objects。我怎样才能做到这一点?

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

谢谢。

【问题讨论】:

    标签: javascript json d3.js


    【解决方案1】:

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

    来自下划线文档:

    展平 _.flatten(array, [shallow]) 展平嵌套数组(嵌套可以到任何深度)。如果你通过浅层,>数组只会被展平一个级别。

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

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

    _.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); })
    

    【讨论】:

    • 谢谢,它可以工作,但是否可以只使用纯 JS 或 d3 而不更改数据?我想提高我的技能:)
    • @shawn 当然可以。 Underscore.js 是开源的,你可以检查事情是如何完成的。这并不难理解。此处的代码:underscorejs.org/underscore.js 在不更改数据的情况下,您无法使用 d3 轻松做到这一点......有一种方法,但没有经过优化。你 quand 做一个 foreach 数据,然后对值做 focus.selectAll 并以这种方式附加你的圈子。
    【解决方案2】:

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

    这是我们要使用的数据。我将在这里制作一个散点图(仅作为示例),所以,让我们为访问第二级数据的尺度设置域(xyvalues):

    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 个组。

    我也用group来设置圈子的颜色:如果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数组中的对象将数据绑定到圆上。

    然后你定位你的圈子。这是全部代码,点击“运行代码sn-p”查看:

    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>

    【讨论】:

      猜你喜欢
      • 2023-03-31
      • 1970-01-01
      • 2015-10-17
      • 1970-01-01
      • 2011-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多