我正在使用d3.js来将可视化的动物(生物体)家族(一次最多为4000个)视为树形图,尽管数据源也可以是目录列表,也可以是命名空间对象的列表.我的数据看起来像:
- json = {
- organisms:[
- {name: 'Hemiptera.Miridae.Kanakamiris'},{name: 'Hemiptera.Miridae.Neophloeobia.incisa'},{name: 'Lepidoptera.Nymphalidae.Ephinephile.rawnsleyi'},... etc ...
- ]
- }
我的问题是:我正在寻找将上述数据转换为层级的父/子数据结构的最佳方式,如许多d3可视化(如treemap)所使用的(数据示例参见d3 / examples /数据/目录).
以下是所需数据结构的示例:
- {"name": "ROOT","children": [
- {"name": "Hemiptera","children": [
- {"name": "Miridae","children": [
- {"name": "Kanakamiris","children":[]},{"name": "Neophloeobia","children": [
- {"name": "incisa","children":[] }
- ]}
- ]}
- ]},{"name": "Lepidoptera","children": [
- {"name": "Nymphalidae","children": [
- {"name": "Ephinephile","children": [
- {"name": "rawnsleyi","children":[] }
- ]}
- ]}
- ]}
- ]}
- }
编辑:将所有原始的所需数据结构包含在ROOT节点内,以符合只有一个主父节点的d3示例的结构.
我正在寻找一个一般的设计模式,作为一个奖励,我希望看到一些解决方案在javascript,PHP,(甚至python). javascript是我的偏好.
关于PHP:我实际使用的数据来自一个PHP脚本的调用数据库,该脚本将结果编码为json.
PHP脚本中的数据库结果是一个有序数组(见下文),如果这是用于基于PHP的答案的话.
- Array
- (
- [0] => Array
- (
- ['Rank_Order'] => 'Hemiptera'
- ['Rank_Family'] => 'Miridae'
- ['Rank_Genus'] => 'Kanakamiris'
- ['Rank_Species'] => ''
- ) ........
哪里:
‘Rank_Order’isParentOf’Rank_Family’isParentOf’Rank_Genus’isParentOf’Rank_Species’
我问了一个类似的问题,专注于PHP解决方案here,但唯一的答案是不能在我的服务器上工作,我不太明白发生了什么,所以我想从设计模式的角度提出这个问题,并包括参考对我的实际使用是在javascript和d3.js.
解决方法
以下是特定于您提供的结构,它可以相当容易地变得更通用.我确定addChild函数可以简化.希望这些意见是有帮助的.
- function toHeirarchy(obj) {
- // Get the organisms array
- var orgName,orgNames = obj.organisms;
- // Make root object
- var root = {name:'ROOT',children:[]};
- // For each organism,get the name parts
- for (var i=0,iLen=orgNames.length; i<iLen; i++) {
- orgName = orgNames[i].name.split('.');
- // Start from root.children
- children = root.children;
- // For each part of name,get child if already have it
- // or add new object and child if not
- for (var j=0,jLen=orgName.length; j<jLen; j++) {
- children = addChild(children,orgName[j]);
- }
- }
- return root;
- // Helper function,iterates over children looking for
- // name. If found,returns its child array,otherwise adds a new
- // child object and child array and returns it.
- function addChild(children,name) {
- // Look for name in children
- for (var i=0,iLen=children.length; i<iLen; i++) {
- // If find name,return its child array
- if (children[i].name == name) {
- return children[i].children;
- }
- }
- // If didn't find name,add a new object and
- // return its child array
- children.push({'name': name,'children':[]});
- return children[children.length - 1].children;
- }
- }