Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smooth transitioning between tree, cluster, radial tree, and radial cluster layouts

For a project, I need to interactively change hierarchical data layout of a visualization - without any change of the underlying data whatsoever. The layouts capable of switching between themselves should be tree, cluster, radial tree, and radial cluster. And transitioning should be preferably an animation.

I thought that would be relatively easy task with D3. I started, but I got lost in translations and rotations, data bindings, and similar, so I am asking you for help. Also, probably I am doing something not in the spirit of D3, which is bad since I am seeking a clean solution.

I put together a jsfidle, but it is just a starting point, with added radio buttons, convenient small data set, and initial cluster layout - just to help anybody who wants to take a look at this. Thanks in advance!

UPDATE:

I wanted to focus on links only, so I temporary disabled other elements. Building on @AmeliaBR method, following animations are obtained:

enter image description here

Here is updated jsfiddle.

UPDATE 2:

Now with circles: (excuse my choice of colors)

{doom-duba-doom}

enter image description here

Here is one more updated jsfiddle.

like image 221
VividD Avatar asked Jan 05 '14 05:01

VividD


2 Answers

I don't see why it would be that hard so long as all your layouts have the same overall structure of link-paths, circle nodes and text labels.

Just make sure all your objects, including your link paths, have a good data-key that is independent of the data attributes created by the layout functions. Then for each transition, update the data with the results of the appropriate layout function and draw that layout.

I've got the transition to radial tree implemented here: http://jsfiddle.net/YV2XX/5/

Key code:

//Radial Tree layout//
var diameter = 500;
var radialTree = d3.layout.tree()
    .size([360, diameter / 2 ])
    .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
var radialDiagonal = d3.svg.diagonal.radial()
    .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
function transitionToRadialTree() {
  var nodes = radialTree.nodes(root), //recalculate layout
      links = radialTree.links(nodes);

    svg.transition().duration(1500)
       .attr("transform", "translate(" + (diameter/2)
                 + "," + (diameter/2) + ")");
             //set appropriate translation (origin in middle of svg)

    link.data(links, function(d){
              return d.source.name + d.target.name;})
      .transition().duration(1500)
      .attr("d", radialDiagonal); //get the new radial path

  node.data(nodes, function(d){
              return d.name ;})
      .transition().duration(1500)
      .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; }) 

  node.select("circle")
      .transition().duration(1500)
      .attr("r", 4.5);

  node.select("text")
      .transition().duration(1500)
      .attr("dy", ".31em")
      .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
      .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; });
};

The layout code is all from http://bl.ocks.org/mbostock/4063550, I've just changed it to be an update instead of an initialization.

Also note that I have moved the variable declaration for root outside of the data-reading method, so it can be re-accessed by the transition functions.

Layout still needs some finessing, but you get the idea.

Now, if you wanted one of the transitions to be a partition, treemap or other layout that doesn't use the node-link structure, they it gets more complicated...

like image 141
AmeliaBR Avatar answered Nov 07 '22 01:11

AmeliaBR


I don't have enough reputation to make a comment...so, I am just giving this tiny contribution as a pseudo-answer. After looking at this post, and based on @VividD's perfect comment on how simple the transitions turned out to be, I simply added the Tree Vertical option to the transformations in this fiddle.

The addition is simply this:

var diagonalVertical = d3.svg.diagonal()
    .projection(function (d) { 
        return [d.x, d.y]; 
    });

Anyways, I have bookmarked this highly instructional interaction.

like image 30
FernOfTheAndes Avatar answered Nov 07 '22 01:11

FernOfTheAndes