我正在使用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; } }