2012-06-15 52 views
18

D3具有多種佈局向圖有嚴格的樹木,如下列:如何佈置一個非樹層次結構與D3

A 
|\ 
B C 
/\ 
D E 

我需要繪製節點的層次結構,是不是一棵樹,但是是一個有向無環圖。這是一個樹佈局的問題,因爲幾個分支會聚:

A 
|\ 
B C 
\| 
    D 

有人知道D3佈局的一般層次?或者,對現有的treelayout進行一些巧妙的修改?我注意到GraphVis很好地處理了這種情況,但是D3產生了一個更適合這裏需求的圖。

+0

您可能想看看有力的圖形佈局。 –

回答

1

一般說到的樹木和數據層次,你只需要擁有「d」在孩子列表B和C.

創建您的節點列表,請確保您有返回,這樣一個獨特的ID 「D」不會出現兩次。

vis.selectAll("g.node").data(nodes, function(d) { return d.id; }); 

然後當你調用

var links = tree.links(nodes) 

你應該得到d顯示爲「目標」兩次(B和C爲「源」分別),這導致兩行到單個節點「d」。

+0

我能夠以您描述的方式組裝樹,但TreeLayout似乎無法處理它。我有機會以某種方式搞砸了;你有幸得到一個佈局運行這種方式?與此同時,我在服務器端使用GraphViz管理了一個非常合適的解決方法。 GraphViz將爲每個節點以(x,y)位置進行DOT格式的很好的分層佈局和輸出。從那裏,將這些信息打包到頁面並使用D3進行繪製相對比較容易。 感謝您的幫助,我感謝您的努力! –

+0

我玩過它,它很瘋狂。根據父母的不同,它有時會在d3內失敗:「vom未定義:6444」和其他時候會渲染,但是把孩子放在一個醜陋的地方。所以簡短的回答是,你是對的。案件中的樹形佈局是問題所在。 – Glenn

10

您可以創建自己的代碼,而不必依靠D3佈局來完成它。我提供了example in a jsFiddle。這個例子非常簡單,需要稍加處理以適應更復雜的例子。

這個例子可以重新處理,以相對較少的努力來處理分層數據。

這是我在的jsfiddle使用的代碼:

// Sample data set 
var json = { 
    nodes: [{ 
     name: 'A'}, 
    { 
     name: 'B'}, 
    { 
     name: 'C'}, 
    { 
     name: 'D'}], 
    links: [{ 
     source: 'A', 
     target: 'B'}, 
    { 
     source: 'A', 
     target: 'C'}, 
    { 
     source: 'B', 
     target: 'D'}, 
    { 
     source: 'C', 
     target: 'D'} 
                        ] 

}; 

var vis = d3.select('#vis').attr('transform', 'translate(20, 20)'); 

// Build initial link elements - Build first so they are under the nodes 
var links = vis.selectAll('line.link').data(json.links); 
links.enter().append('line').attr('class', 'link').attr('stroke', '#000'); 

// Build initial node elements 
var nodes = vis.selectAll('g.node').data(json.nodes); 
nodes.enter().append('g').attr('class', 'node').append('circle').attr('r', 10).append('title').text(function(d) { 
    return d.name; 
}); 

// Store nodes in a hash by name 
var nodesByName = {}; 
nodes.each(function(d) { 
    nodesByName[d.name] = d; 
}); 

// Convert link references to objects 
links.each(function(link) { 
    link.source = nodesByName[link.source]; 
    link.target = nodesByName[link.target]; 
    if (!link.source.links) { 
     link.source.links = []; 
    } 
    link.source.links.push(link.target); 
    if (!link.target.links) { 
     link.target.links = []; 
    } 
    link.target.links.push(link.source); 
}); 

// Compute positions based on distance from root 
var setPosition = function(node, i, depth) { 
    if (!depth) { 
     depth = 0; 
    } 
    if (!node.x) { 
     node.x = (i + 1) * 40; 
     node.y = (depth + 1) * 40; 
     if (depth <= 1) { 
      node.links.each(function(d, i2) { 
       setPosition(d, i2, depth + 1); 
      }); 
     } 

    } 

}; 
nodes.each(setPosition); 

// Update inserted elements with computed positions 
nodes.attr('transform', function(d) { 
    return 'translate(' + d.x + ', ' + d.y + ')'; 
}); 

links.attr('x1', function(d) { 
    return d.source.x; 
}).attr('y1', function(d) { 
    return d.source.y; 
}).attr('x2', function(d) { 
    return d.target.x; 
}).attr('y2', function(d) { 
    return d.target.y; 
}); 
+3

感謝這個例子,菲爾!我結束了一些非常相似的事情。事實證明,我真正想要的佈局算法是在GraphViz中實現的。它有python綁定,但它們不起作用。相反,我做了以下內容: 1)型圖形爲DOT語言(http://www.graphviz.org/content/dot-language) 2)通圖通過命令行的graphviz的圓點命令,這的確佈局和看跌期權(X,Y)座標轉換成DOT 3)重新格式化成DOT javascript對象,嵌入到 第4頁)使用D3放置節點根據(X,Y)座標中DOT。 這個作品真的很好用非常大的圖形。 –

7

正如這個例子:「Force Directed Trees」說明存在,往往工作的伎倆。在這個例子中,力的方向的行爲是在每個滴答時進行調整的,以便節點根據鏈接的方向稍微向上或向下漂移。如圖所示,這對樹木來說是一項很好的工作,但我發現它也適用於非循環圖。沒有承諾,但可能有所幫助。