Monday, 18 March 2013

Directional Force Layout Diagram (varying link opacity)


The following post is a portion of the D3 Tips and Tricks document which is free to download. To use this post in context, consider it with the others in the blog or just download the pdf  and / or the examples from the downloads page:-)
-------------------------------------------------------


The next variation to our force layout diagram is the addition of variation in the link to represent different values (think of the number of packets passed or the amount of money transferred). It follows on from the Directional Force Layout Diagram (Node Highlighting).

There are a few different ways to do this, but by virtue of the inherent close linkages between the arrowhead marker and the link line, altering both in synchronicity proved to be beyond my meagre talents. However, I did find a couple of suitable alternatives and I will go through one here.

In this example we will take the value associated in the loaded data with the link and we will adjust the opacity of the link line in a staged way according to the range of values.

For example, in a range of link strengths from 0 to 100, the bottom 25% will be at opacity 0.25, from 25 to 50 will be 0.25, 50 to 75 will be 0.75 and above 75 will have an opacity of 1. So the final result looks a little like this;

The changes to the code to create this effect are focused on creating an appropriate range for the values associated with the links and then applying the opacity according to that range in discrete steps.

The first change to the node highlighting code that we make is to the style section. The following elements are added;
path.link.twofive {
  opacity: 0.25;
}

path.link.fivezero {
  opacity: 0.50;
}

path.link.sevenfive {
  opacity: 0.75;
}

path.link.onezerozero {
  opacity: 1.0;
}
 This provides our four different 'classes' of opacity.

Then in a  block of code that comes just after the declaration of the `force` properties we have the following;
var v = d3.scale.linear().range([0, 100]);

v.domain([0, d3.max(links, function(d) { return d.value; })]);

links.forEach(function(link) {
    if (v(link.value) <= 25) {
        link.type = "twofive";
    } else if (v(link.value) <= 50 && v(link.value) > 25) {
        link.type = "fivezero";
    } else if (v(link.value) <= 75 && v(link.value) > 50) {
        link.type = "sevenfive";
    } else if (v(link.value) <= 100 && v(link.value) > 75) {
        link.type = "onezerozero";
    }
});
 Here we set the scale and the range for the variable `v` (`var v = d3.scale.linear().range([0, 100]);`). We then set the domain for v to go from 0 to the maximum `value` that we have in our link data.

The final block above uses a cascading set of if statements to assign a label to the `type` parameter of each link. This label is the linkage back to the styles we defined previously.

The final change is to take the line where we assigned a class of `link` to each link previously...
    .attr("class", "link")
 ...to add in our `type` parameter as well;
    .attr("class", function(d) { return "link " + d.type; })
 Obviously if we wanted a greater number of opacity levels we would add in further style blocks (with the appropriate values) and modify our cascading if statements. I'm not convinced that this solution is very elegant for what I'm trying to do (it was a much better fit for the application that Mike Bostock applied it to originally where he designated different types of law suits) but I'll take the result as a suitable way of demonstrating variation of value.

The code and data for this example can be found as Directional Force Layout Diagram with varying link opacity on bl.ocks.org.

The above description (and heaps of other stuff) is in the D3 Tips and Tricks book that can be downloaded for free (or donate if you really want to :-)).

No comments:

Post a Comment