Getting the force directed graph functional in d3 was a good start, but it clearly needs some tuning up.
For starters, the uniform fill color needs to be changed. Network graphs are interesting visualizations but mean very little without some differentiation between the nodes. Mapping the degree value to the node size expresses one dimension of this information, but there is a lot more information to be expressed and color is one of the simplest and notable ways to do so.
Color scales are simple to create in d3; it’s simply a matter of taking one of d3’s built in scale functions and mapping colors to the scale’s range, like so:
Var colorScale = d3.scaleOrdinal() .domain(data.ourXvariable) .range([“#FFF”,”#666”,”#000”])
Colors are expressed as an array of “bins” to be matched to the values in the domain. The colors can then be called when the objects are drawn.
In the case of this network graph, I wanted to use a color scale to represent the annual budget of each node’s parent organization. The animal rights movement is championed by several organizations with budgets that far exceed that of other organizations, and this information might be interesting to compare to their presence at the animal rights national conference (Do larger organizations have some clout that bolsters their presence at these events? Does the sheer breadth of smaller organizations obfuscate their participation).
In this case, I decided to use a quantized scale to partition the Organization Budget values in 9 domains. A continuous scale may also be fitting, since Budget is a continuous variable, however if the intention is to visually describe similarity or difference between nodes using color, many different shades of many different colors may obfuscate larger trends in the data.
Quantize scales are somewhere in between ordinal and linear scales in the d3 library. Whereas ordinal scales create “bins” based on (typically) nominal or categorical variables, quantize scales take a continuous variable and partition it into equal, discrete “bins” bound to a given domain; in this case
The tooltips were then appended to include the actual Organization Budget of each node, pulled from the row of the nodes dataset while the circles are being drawn.
Another prominent issue with the visualization is that the node x and y positioning is not currently bound to the width and height of the svg canvas. As a result, some nodes fly out of the visual bounds and are not visible to the user. D3 creator Michael Bostock has a proposed solution here, however implementing this in my own code has proven problematic. The gist is that, when the x and y coordinates are pulled, the library is told to put the nodes within the range of [radius, cavaswidth-radius] for the x coordinate, and the range of [radius, canvasheight-radius] for the y coordinate.
The reason the code seems to be breaking is that the variable radius, as it appears in Bostock’s code, is a set integer, whereas in my code, radius is a function of the node’s degree centrality value. In trying to call the variable radius, my code is trying to look for a value that isn’t present in the current data which is being built by the force function. As such, I set an arbitrary value of 20 in place of Bostock’s use of radius.
The result is a graph that still fits the bounds of the box and has a bit more of a visual distinction between the types of nodes. Pretty cool! A key still needs to be implemented to explain what the colors actually mean, of course. Another concern is that the nodes still gravitate towards one another quite arbitrarily, rather than the nice subgroups that are emblematic of network graphs. This week I plan to take a deeper dive into the d3.force function to see how these forces can be used to replicate such results.