Can we make it 5?

This follows up on the four dimensions in two dimensions post. I updated the graph adding some functionality, increasing the readability and improving the aesthetics. Moreover, the plot can now transition from a visualization with two categorical variables to one with four. The principle guiding the creation of the graph remains the same: to display as much information as possible into a two-dimensional graph without sacrificing interpretability and maintaining (hopefully) pleasing aesthetics. Because of the addition of the transition effect, I thought it was like adding a new dimension to the four which already existed. Below I describe the implementation of these additions. The graph is made in d3.js and the final plot can be admired here.

First of all, I must admit an error in the first visualization of this data. I forgot to use the square root when specifying the dimension of the circles. This mishap misleads the interpretation of the data because the relative size of the object is inaccurate. Fortunately, adjusting the graph is very straightforward. It requires replacing d3.scaleLinear() with d3.scaleSqrt() in teh constructions of the scales:

var sizeValue = function(d) { return d.dotSize;},
        sizeScale = d3.scaleSqrt().range([3, 20]),
        sizeMap = function(d) { return sizeScale(sizeValue(d));};
// which is then passed to the specification of the dot
// size:
svg.selectAll(".dot")
      .data(data)
   .enter().append("circle")
      .attr("class", "dot")
      .attr("r", sizeMap)

I also added a size legend on the right side of the plot. This scale legend helps in interpreting the size of the dots. The legend gives, first of all, an immediate sense of the range spanned by the data displayed. Secondarily it allows a quick and rough comparison between the data points and it gives an idea of the data points’ distribution. The code for the size legend is a bit cumbersome because I found it easier to keep these objects separated from the other objects in the graph rather than updating them.

// create a subsample of the data
var startV = sizeScale.domain()[0];
var endV = sizeScale.domain()[1];
var nSteps = 3;
var step = (endV - startV) / nSteps;
var sizeLegend = svg.selectAll(".sizeLegend")
      .data(d3.range(startV, endV+1, step))
   .enter().append("g")
      .attr("class", "sizeLegend")
      .attr("transform", function(d, i) {
                return "translate(0," + ( (i) * (sizeScale(d)*1.5))+ ")";
                });
// draw legend circles
sizeLegend.append("circle")
      .attr("cx", width - 65)
      .attr("r", function(d){ return sizeScale(d);})
      .attr("stroke", "black")
      .style("fill", "white");

// draw legend text
sizeLegend.append("text")
      .attr("x", width - 37)
      .attr("dy", ".35em")
      .style("text-anchor", "start")
      .text(function(d) { return (Math.round(d) + " (ms)");})

The last significant improvement was the option to visualize the difference using its absolute value or its actual value. Using the absolute value made it easier to translate the amplitude of the difference into the size of the circle because I did not have to bother about representing negative values when the RT difference was negative. However, I bypassed the issue of non-existing negative sizes adding two other colors to the plot. Hopefully, the graph remains interpretable also with the added layer of colored fuzziness.
The code for the animation is a bit too long and maybe uninteresting to be “cut-‘n-pasted” here. Also, since the code for constructing the entire page is available on the GitHub repository I think it is easier to get it from there. However, there is a point which requires a short explanation. It is how I modify the legend’s text in the transition:

legend.enter().append("text")
     ...
     .text(function(d) { 
                d = d.replace(/^1/, '+ ');
                d = d.replace(/1/, ' ');
                return d;})
     ...

Here, the first ‘1’ in the text string is replaced by a plus sign and then all the ‘1’s are replaced by empty spaces. This is because I ‘fabricated’ the distinction between positive and negative differences by adding a column in the JavaScript object containing the data. This column concatenates into a string the sign of the difference (i.e., “-1”, “1”) and the word/non-word attribute (i.e., “word” vs. “non-word”), creating something like [“1word”, “-1word”, …]. I did not like having the 1 in front of the legend, so I removed it.
The code could also be optimized and re-written in a clever way. For example, while updating the legend from a transition to another, I found it easier to remove the objects created with the legend than to update their values. But for now it works like this.

As a last cool note: we managed to display the graph on a poster at a conference. Of course, because the graph is interactive it could not be printed directly on paper. However, we could print on the poster a QR-code which redirected the participants’ mobile devices to the webpage of the interactive visualization. It made the poster presentation almost interactive and that is, in my opinion, pretty pretty cool.

Advertisement
Can we make it 5?

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 )

Connecting to %s