Clustering Force Diagrams With Latent Links

Recently I found myself wanting to display some simple diagrams that visualize relationships between nodes in a graph. After searching online, I decided that d3's force layout provided what I was looking for. Unfortunately, the naive implementation of only defining links that encode the relationships in the graph led to unintuitive diagrams where the dependencies and prerequisties of a node distribute themselves equally around that node. Ideally, I wanted the dependencies of a node in one cluster, and the prerequisites of the same node in another cluster. This was achievable through defining latent links between dependent nodes, and latent links between prerequisite nodes.

To make this possible, I needed to store more information in links. For example, is a link a latent link or not? If a link is latent, then its link strength should be greater, and link distance smaller, to pull the latently linked nodes together. For example, this is how I define my link distance and link strength functions I pass to d3's force layout:
 
    var calculateLinkStrength = function (link) {
        return link.isLatent ? .5 : .2;
    };
    
    var calculateLinkDistance = function (link) {
        return link.isLatent ? 8 : 100;
    };
I also store more information on the nodes, such as the number of incoming and outgoing links, that allows for a richer charge and node radius functions.

My Force Layout API

If you would like to use or leverage this work, it available on my github (along with usage documentation). Here is gist of it:
 
// Draws force diagram utilizing d3's force layout (see https://github.com/mbostock/d3/wiki/Force-Layout)
//
// graph: a mapping of strings to list of strings, encoding the visible links in graph
// hiddenGraph: a mapping of strings to list of strings, encoding latent links in the graph
// width: the width of the diagram
// height: the height of the diagram
// id: the id of the element to place the diagram
// nodeClick: the node on click function
// nodeClass: the function that defines the class of each node
// layoutParameters: a dictionary of parameters that are passed to d3's force layout. If not provided, the d3.js defaults are used. The allowed keys are:
//    "calculateNodeRadius" - calculates the radius of each node
//    "calculateNodeCharge" - calculates the charge of each node
//    "calculateLinkDistance" - calculates/influences the distance of each link
//    "calculateLinkStrength" - calculates/influences the strength of each link
//    "friction" - See d3 documentation, value between 0 and 1 inclusive
//    "gravity" -  See d3 documentation, value greater than or equal to 0
//
function drawForceDiagram(graph, hiddenGraph, width, height, id, nodeClick, nodeClass, layoutParameters);

Examples

Nodes are represented by circles. Hover over a node to see its relationship with other nodes.

Purple circles represent nodes that have no dependencies.
Green circles represent nodes which no other nodes depends on.
A red connection from selected node to target node indicates the target node depends on the selected node.
A blue connection from selected node to target node indicates the target node is dependent on the selected node.

Below are three side-by-side examples where the left diagram does not utilize latent links and the right diagram does.

Without Latent Links

With Latent Links