Interactive Brain Graph Visualization (5): Force-directed layout with fisheye distortion

Interactive Brain Graph Visualization (5): Force-directed layout with fisheye distortion

Note: All the codes are available in my Github https://github.com/astro1860/visualization_project/tree/master/brain_fisheye

In this section, we are going to visualize with a powerful tool: D3.js. D3.js is a JavaScript library for manipulating documents based on data using HTML, SVG and CSS.http://d3js.org/ We would like to manipulating the json file we just created with a force-directed layout and also with fisheye distortion. Providing the reference of force layout documentation https://github.com/mbostock/d3/wiki/Force-Layout, we can easily construct the javascript code.

A flexible force-directed graph layout implementation using position Verlet integration to allow simple constraints. This implementation uses a quadtree to accelerate charge interaction using the Barnes–Hut approximation. In addition to the repulsive charge force, a pseudo-gravity force keeps nodes centered in the visible area and avoids expulsion of disconnected subgraphs, while links are fixed-distance geometric constraints. Additional custom forces and constraints may be applied on the “tick” event, simply by updating the x and y attributes of nodes.

While for fisheye distortion, we could refer to the documentation of d3.js http://bost.ocks.org/mike/fisheye/ 

My visualization of brain data is a combination of force-directed layout and fisheye distortion.

Firstly, we specify the radius and distortion factor of fisheye distortion:

 var fisheye = d3.fisheye.circular()
.radius(120)
.distortion(4);

Then, we update the focal point of the distortion on mouse over:

svg.on("mousemove", function() {
fisheye.focus(d3.mouse(this));
});

The distortion operator takes as input an object with x and y attributes, and returns a new object with x, y and z attributes. The returned object represents the distorted position of the input object; the z property is a scaling factor so that you can optionally distort the size of elements as well. To apply fisheye distortion to a force layout, stash the distorted positions in a display property on each node, and then use the distorted positions to update the nodes and links:

svg.on("mousemove", function() {
fisheye.focus(d3.mouse(this));
node.each(function(d) { d.fisheye = fisheye(d); })
.attr("cx", function(d) { return d.fisheye.x; })
.attr("cy", function(d) { return d.fisheye.y; })
.attr("r", function(d) { return d.fisheye.z * 10; });
link.attr("x1", function(d) { return d.source.fisheye.x; })
.attr("y1", function(d) { return d.source.fisheye.y; })
.attr("x2", function(d) { return d.target.fisheye.x; })
.attr("y2", function(d) { return d.target.fisheye.y; });
});

Finally, we need to bound our json data to the force-directly layout:

- configure the properties:

var force = d3.layout.force()
.charge(-500)
.linkDistance(200)
.gravity(0.05)
.size([width, height]);

- bound the json file and call a start

d3.json("graph_data.json", function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();

- set node and link attributes

var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 12)
.style("fill", function(d) { return color(d.eigen_cent); })
.call(force.drag);
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });

The visualization is as follows. Please note that I didn’t use colored scaled node for this visualization.

Visualization with fisheye distorition

Figure. Visualization with fisheye distorition

Leave a Reply