使用D3.js做複雜資料視覺化(二):處理巢狀資料(nested data with nested selection)

2018-02-27 10:57:41来源:https://weitinglin.com/2018/02/23/使用d3-js做複雜資料視覺化(二):處理巢狀資料n作者:我們的基因體時代人点击

分享

前面有稍微介绍一下d3.js的特性,这边直接以主题开场,在做複杂资料视觉化的时候,资料常常都是巢状的,这边分享一下如何用d3.js处理巢状资料。


何谓巢状资料呢?
const data=[{ name: '1', subdata: [1,2,3] },{ name: '2', subdata: [1,2,3] }]

而我们想要根据在data中的array来添加视觉化的element.


要解决这类问题,要先理解D3一些基本运作原理,其中以d3.select的运作和其如何跟data链结的最为重要,建议可以阅读下面的文章:


How Selection Work


D3开发者mike bostock对于selection的解释

D3 – 深入了解Selection与Data绑定


这篇写的颇棒,奠基在mike bostrock的说明文章,添加自己的想法。


以及下面这篇stackover的回答:


loop through array of arrays in d3

第一步:


d3核心观念就是data-driven document,必须先有巢状的文件结构,来对应资料(你如何设计你的资料结构,会影响到最终的视觉化呈现)。这边以SVG为例,除了svg,g以外,像是rect,circle,path 都无法直接在其内包含其他要件。


第二步


对应上面的资料範例,可以先建构或试想所对应的文件结构,如下:



第三步


使用 d3.selection 和 d3.collection 来做对应资料和文件的关係,最好直接阅读d3文档,因为在不同版本间,d3有许多的改变,如d3v3和d3v4两个版本间的selection, data join, index以及data manipulation就有很大的差异,如今在2018/02又发布了d3v5,可以想见d3开发和修改的速度有多快。


这边一步步来用代码说明解决方式。


首先,先建立一个基于svg要件的select object。


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

如此,我们便取得了svg物件,其为d3.select物件


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

由上面的代码,我们取得layer1物件,其基于在前面建立的svg物件上,使用selectAll来建立第一层的选择,皆则把资料用data()放进去,append g 要件,根据目前data内的物件数,会产生两个。


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

我们取得layer2物件,在layer1上接者chain使用selectAll,来将data物件中的subdata阵列暴露出来,并使用d3.entries将parent index往下递出 。


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');

如此我们便能在layer2物件中,根据subdata来对应相对的视觉化要件(element)如rect,同时,保有每个资料element相对于data内的index和自己阵列中的index,如此便能做出具有巢状结构的视觉化。


最后就能创造出如下的效果



这边是放在 observable的範例 , 欢迎一起切磋巢状资料的处理!


最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台