简体   繁体   English

在D3中循环遍历数组

[英]Loop through array of arrays in D3

I have an array of x objects each with an array of y objects like so: 我有一个x对象数组,每个对象都有一个y对象数组,如下所示:

var data = [
    { name: '1', data: [1,2,3] },
    { name: '2', data: [1,2,3] }
]

Is there a way to chain d3 functions in order to iterate through each data[x] and each data[x][y]? 有没有办法链接d3函数,以迭代每个数据[x]和每个数据[x] [y]?

I thought something like this would have helped, but not apparently: 我认为这样的事情会有所帮助,但显然不是:

var svg = d3.selectAll('g')
    .data(data)
    .enter()
    .append('g')
    .selectAll('rect') /* This might be made up, but it makes sense to me :)*/
    .data(data, function (d, i) {
        return data[i].data;
    })
    .enter()
    .append('rect')

Thanks 谢谢

While an explicit .each loop works, the d3 approved way to do this is with a nested selection : 虽然显式的.each循环有效,但d3批准的方法是使用嵌套选择

 var data = [ { name: '1', data: [1,2,3] }, { name: '2', data: [1,2,3] } ] var colourScale = ['red','blue','yellow'] var colourScale2 = ['yellow','pink','black'] var svg = d3.select('body').append('svg').attr('width', 1000).attr('height', 1000); svg.selectAll('rect') .data(data) .enter().append('g') .selectAll('rect') .data(function(d){ return d.data; }) .enter() .append('rect') .attr('x', function(d,i) { return i*100; }) .attr('y', function(d,i,j) { return j*100; }) .attr('width', function() { return 90; }) .attr('height', function() { return 90; }) .attr('fill', function(d,i) { return colourScale2[i]; }) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 

What about something along these lines : //untested 这些方面的内容如何://未经测试

var svg = d3.selectAll('g')
    .data(data)
    .enter()
    .append('g')
    .selectAll('rect') /* This might be made up, but it makes sense to me :)*/
    //.data(data, function (d, i) {
    //   return data[i].data;
    //})
    //.enter()
    //.append('rect')
    .each(function(d){
    d3.select(this).selectAll('rect').data(d.data).append('rect')//and so on
    })

EDIT : 编辑:

Working fiddle : http://jsfiddle.net/reko91/58WJE/34/ 工作小提琴: http//jsfiddle.net/reko91/58WJE/34/

 var data = [ { name: '1', data: [1,2,3] }, { name: '2', data: [1,2,3] } ] var colourScale = ['red','blue','yellow'] var svg = d3.select('body').append('svg').attr('width', 1000).attr('height', 1000); svg.selectAll('rect') .data(data) .enter().append('g') .each(function(d,i){ d3.select(this).selectAll('rect') .data(d.data) .enter().append('rect') .attr('x', function(d,j) { return j*100; }) .attr('y', function() { return i*100; }) .attr('width', function() { return 90; }) .attr('height', function() { return 90; }) .attr('fill', function(d,j) { console.log(d); return colourScale[j]; }) }); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 

This is a good question about " How to nest elements with nested data in d3.js ", which I also encounter recently. 这是一个关于“ 如何在d3.js中嵌套嵌套数据的元素 ”的好问题,我最近也遇到过这个问题。 (also thinking a robust way to deal with these scenario) (也在思考一种处理这些场景的可靠方法)

These articles wrote by Mike Bostock related to the issue: Mike Bostock撰写的这些文章涉及到这个问题:
1. How selection work 1. 如何选择工作
- let you know how data binding to selection - 让您了解数据如何绑定到选择
2. Nested Selection 2. 嵌套选择
- knowing how selection chaining function really happen under the hood - 了解选择链接功能如何真正发生在引擎盖下

Here is how I deal with this problem when using svg (canvas may have other ways). 以下是我在使用svg时处理此问题的方法(canvas可能有其他方法)。

First , the mindset of D3 is 'Data-driven Document'. 首先 ,D3的思维方式是“数据驱动文档”。 To deal with nested data, you have to create nested elements in SVG.(you will find that your design on data structure really matter, it reflect viz result). 要处理嵌套数据,你必须在SVG中创建嵌套元素。(你会发现你的数据结构设计真的很重要,它反映了结果)。 < g > element(g stand for grouping) in SVG can solve this problems, which created for grouping elements under svg like < path > , < rect >, < circle >. SVG中的<g>元素(g代表分组)可以解决这个问题,这些问题是为svg下的元素分组创建的,如<path>,<rect>,<circle>。 You cannot nested element under path, rect, circle but g or svg. 你不能在path,rect,circle但是g或svg下嵌套元素。

Second , you need to imagine the nested structure on document. 其次 ,您需要想象文档上的嵌套结构。 Here for example: 这里举例如下:

<svg>
    <g class="layer1">
        <g class="layer2">
            <rect x="0" y="1" class='layer2'></rect>
        </g>
        <g class="layer2">
            <rect x="1" y="1" class='layer2'></rect>
        </g>
        <g class="layer2">
            <rect x="2" y="1" class='layer2'></rect>
        </g>
    </g>
    <g class="layer1">
        <g class="layer2">
            <rect x="0" y="2" class='layer2'></rect>
        </g>
        <g class="layer2">
            <rect x="1" y="2" class='layer2'></rect>
        </g>
        <g class="layer2">
            <rect x="2" y="2" class='layer2'></rect>
        </g>
    </g>
</svg>

Third , using the d3.collection and d3.select to match the data and document. 第三 ,使用d3.collectiond3.select匹配数据和文档。 Better to read the d3 doc, in case the change of syntax under different d3 version. 如果在不同的d3版本下更改语法,最好阅读d3 doc。 The d3.v4 and v3 had quite a difference under the data join, select, data index, data manipulation and now 2018/02 the d3 go into v5. d3.v4和v3在数据连接,选择,数据索引,数据操作和现在2018/02 d3进入v5之间有很大差异。

Here re-frame the question code. 这里重新构建问题代码。

const svg = d3.select('body')
              .append('svg')
              .attr('width', 1000)
              .attr('height', 1000);

We got the svg , which is d3.select obj, contain the svg element. 我们得到了svg ,它是d3.select obj,包含svg元素。

const layer1 = svg.selectAll('g.layer1')
                  .data(data)
                  .enter()
                  .append('g')
                  .classed('layer1', true);

We got the layer1 , which created by using selectAll and enter our data with .data() and enter(), also append the g element according to the object num of data, which is 2 in this scenario 我们得到了layer1 ,它是通过使用selectAll创建的,并使用.data()和enter()输入我们的数据,也根据数据的对象num附加g元素,在这种情况下为2

const layer2 = layer1.selectAll('g.layer2')
                     .data((d,i,j)=>{
                        let num = d3.entries(j)[i].key
                        return d.data.map((d)=> [d,num])
                                     })
                     .enter()
                     .append('g')
                     .classed('layer2', true);

We got the layer2 element, leveraging the hierarchical selection ability of d3.selection in chaining function and use the d3.enteries to give the layer1 index pass to layer2 (since v4, the data key function will no longer keep parent index, so this is the alternative method i figure out. refer to this discussion ). 我们得到了layer2元素,利用链接函数中d3.selection的层次选择能力,并使用d3.enteries将layer1索引传递给layer2(从v4开始,数据键函数将不再保留父索引,所以这是我想出的替代方法。参考这个讨论 )。 the d3.enteries give the key to each element in array, we use it to store the parent index d3.enteries给出数组中每个元素的键,我们用它来存储父索引

layer2.append('rect')
      .attr('x', (d,i)=> i*60)
      .attr('y', (d,i)=> d[1]*60)
      .attr('width', 50)
      .attr('height', 50)
      .attr('fill', 'blue');

Then, Using layer2 element, we can append rect element according to the array in data.data with the index information of each data element .By the way, in this solution, we let each element in data.data carry the parent index. 然后,使用layer2元素,我们可以根据data.data中的数组附加rect元素和每个数据元素的索引信息。顺便说一句,在这个解决方案中,我们让data.data中的每个元素都带有父索引。

So the result can be following: enter image description here 因此结果如下: 在此输入图像描述

🀆 🀆 🀆
🀆 🀆 🀆  

demo on Observable: 关于Observable的演示:
https://beta.observablehq.com/@weitinglin/simple-case-01-nested-data-with-nested-selection https://beta.observablehq.com/@weitinglin/simple-case-01-nested-data-with-nested-selection

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM