user2753788
user2753788

Reputation: 51

Avoid overlapping of nodes in tree layout in d3.js

I have created a collapsible tree to represent some biological data.

In this tree the size of the node represents the importance of the node. As I have a huge data and also the sizes of the nodes vary,they overlap over each other. I need to specify the distance between the sibling nodes.

I tried tree.separation() method but it didn't work.

Code is as follows :

tree.separation(seperator);

function seperator(a, b)
{
    if(a.parent == b.parent)
    {
        if((a.abundance == (maxAbd)) || (b.abundance == (maxAbd)))
        {
            return 2;
        }
        else
        {
            return 1;
        }
    }
}

This is giving me error saying:

Unexpected value translate(433.33333333333337,NaN) parsing transform attribute.

I understand that that after adding the separation method it is unable to calculate the x coordinate for the nodes. Can anyone please help me with how to do this?

I also tried modifying the source code as suggested in https://groups.google.com/forum/#!topic/d3-js/7Js0dGrnyek but that did not work either.

Please suggest some solution.

Upvotes: 4

Views: 8078

Answers (2)

Xing Shi
Xing Shi

Reputation: 2230

SiegS's answer just works fine!

My situation is that: My node is actually some text, which may have various width, which I don't know in advance. So I need to calculate the width of each nodes first.

I have a JSON object json_data as my data.

var tree = d3.layout.tree()
.sort(null)
.size([500,500])
.children( some_function_identify_children );

var nodes = tree.nodes(json_data); //which doesn't consider the node's size;
var links = tree.links(nodes);

// append a svg;
var layoutRoot = d3.select("body")
.append("svg:svg").attr("width","600").attr("height","600")
.append("svg:g")
.attr("class","container");

var nodeGroup = layoutRoot.selectAll("g.node")
.data(nodes)
.enter().append("text").text(function(d){return d.text;});
// now we knows the text of each node. 

//calculate each nodes's width by getBBox();
nodeGroup.each(function(d,i){d["width"] = this.getBBox().width;})

//set up a new tree layout which consider the node width. 
var newtree = d3.layout.tree()
.size([500,500])
.children(function(d) {return d.children;})
.separation(function(a,b){
  return (a.width+b.width)/2+2;
});

//recalcuate the node's x and y by newtree
newtree.nodes(nodes[0]); //nodes[0] is the root
links = newtree.links(nodes);

//redraw the svg using new nodes and links.
...

Hope this will help.

Upvotes: 4

SpiegS
SpiegS

Reputation: 83

I had the same problem. This is how I solved it. I have width assigned to each node, height for now is the same for all nodes (basically nodes with smaller height than nodeHeight, get centered vertically):

var tree = d3.layout.tree().nodeSize([1, nodeHeight])
           .separation(function(a, b) {
               var width = a.width + b.width,
                   distance = width / 2 + 16; // horizontal distance between nodes = 16
                   return distance;
           }),
    nodes = tree.nodes(data),
    links = tree.links(nodes);

Hope this helps.

Upvotes: 7

Related Questions