d3.js – From tree to cluster and radial projection

Some visualizations seem to be more sophisticated (to implement) than they actual are, specifically the radial projections. Starting from a tree representation with nodes and links it is quite easy to get to the radial version.
Remark: Of course there are more challenging radial diagrams like the bundle, but lets get started with something simple first !

“Standard” Tree
(I added few more nodes to make the visual difference more obvious)

Tree Visualization

We change 1 line of our sourcecode (see previous tutorial for complete code):

var tree = d3.layout.tree().size([300,300]);
to
var tree = d3.layout.cluster().size([300,300]);

Cluster
Same like tree but all end-nodes/leafs at one level.

Cluster

Radial Cluster
With a few changes we can convert this cluster diagram into a radial one.

Change these lines:

The path generator

var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
// to 
var diagonal = d3.svg.diagonal.radial()
.projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });

The nodes

var node = vis.selectAll("g.node")
 .data(nodes)
 .enter().append("svg:g")
 .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
to 
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })

and the text (rotated):
Add this line

.attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; })

You also should change the svg canvas to center everything:

var vis = d3.select("#viz").append("svg:svg")
.attr("width", 400)
.attr("height", 400)
.append("svg:g")
.attr("transform", "translate(200, 200)");

Obviously is visually more appealing with more nodes in place. After all, the new visualization was not done by changing parameters (like using a visualization library) but by applying mathematics and geometry. From here I will explore the more challenging bundle diagram and start to play with interaction.

Remark: This is a very stripped down sample for understanding, in real projects you should use variables for canvas sizes, etc. Also place visual attributes like color, etc in style in a css.

The complete code:

<!DOCTYPE html>
<html>
    <head>
        <title>Radial Cluster Demo</title>
        <script type="text/javascript" src="libnew/d3.v2.min.js"></script>
        <style>
            svg {
                border: solid 1px #ccc;
                font: 10px sans-serif;
            }
            .link {
                fill: none;
                stroke: #ccc;
                stroke-width: 1.5px;
            }
        </style>
    </head>
    <body>

        <div id="viz"></div>

        <script type="text/javascript">

            //JSON object with the data
            var treeData = {"name" : "A", "info" : "tst", "children" : [
                    {"name" : "A1", "children" : [
                            {"name" : "A12" },
                            {"name" : "A13" },
                            {"name" : "A14" },
                            {"name" : "A15" },
                            {"name" : "A16" }
                        ] },
                    {"name" : "A2", "children" : [
                            {"name" : "A21" },
                            {"name" : "A22", "children" : [
                            {"name" : "A221" },
                            {"name" : "A222" },
                            {"name" : "A223" },
                            {"name" : "A22" }
                        ]},
                            {"name" : "A23" },
                            {"name" : "A24" },
                            {"name" : "A25" }] },
                    {"name" : "A3", "children": [
                            {"name" : "A31", "children" :[
                                    {"name" : "A311" },
                                    {"name" : "A312" },
                                    {"name" : "A313" },
                                    {"name" : "A314" },
                                    {"name" : "A315" }
                                ]}] }
                ]};

            // Create a svg canvas
            var vis = d3.select("#viz").append("svg:svg")
            .attr("width", 400)
            .attr("height", 400)
            .append("svg:g")
            .attr("transform", "translate(200, 200)");

            // Create a cluster "canvas"
            var cluster = d3.layout.cluster()
            .size([300,150]);

            var diagonal = d3.svg.diagonal.radial()
            .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });

            var nodes = cluster.nodes(treeData);
            var links = cluster.links(nodes);

            var link = vis.selectAll("pathlink")
            .data(links)
            .enter().append("svg:path")
            .attr("class", "link")
            .attr("d", diagonal)

            var node = vis.selectAll("g.node")
            .data(nodes)
            .enter().append("svg:g")
            .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })

            // Add the dot at every node
            node.append("svg:circle")
            .attr("r", 3.5);

            node.append("svg:text")
            .attr("dx", function(d) { return d.x < 180 ? 8 : -8; })
            .attr("dy", ".31em")
            .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
            .attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; })
            .text(function(d) { return d.name; });
        </script>
    </body>
</html>
Advertisements

7 thoughts on “d3.js – From tree to cluster and radial projection

  1. How you dynamically load the data when expanding the tree?
    I’d like to try this for a large hierarchical data tree stored in Oracle

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s