Force directed graph: link forces

There’s two types of forces in the d3-force module – preshipped forces and custom forces.

Preshipped forces have already been written for you. Custom forces you write yourself.

In this post we cover the force that links nodes together - forceLink().  This is the force that pushes linked nodes together or pulls them apart.

Parameters Link to heading

Like the other forces, there’s a number of parameters you can tweak to customise your force directed graph.

In this case there are five parameters: links, id, distance, strength and iterations.

links: used to set the the links the force is applied on.

You either specify the links here or in the argument for forceLink(), like this:

var link_force =  d3.forceLink(links_data);
simulation.force("links",link_force);

Each link has a minimum of three properties:

  • source: source node for the link. One of the two nodes connected.
  • target: target node for the link. The other of the two nodes connected.
  • index: id for the link. This starts at 0 for the first link specified and counts up for every link in the simulation.

Link attributes also appear here as well. Taking the example from the last post, we see that type is an attribute of every link, and takes the value of either “A” or “E”.

id: Used to tell the simulation what node attribute to look out for when joining nodes together.

For example: say we have two nodes we want to join:

var nodes_data =  [
    {"name": "Lillian", "sex": "F"},
    {"name": "Gordon", "sex": "M"}
]

We specify a link:

var links_data = [
	{"source": "Lillian", "target": "Gordon", "type":"A" }
]

We would use the id parameter in forceLink() to indicate that we should search in the name attribute in the nodes when linking the two nodes together. This would look like this:

var link_force =  d3.forceLink(links_data)
                        .id(function(d) { return d.name; });

Here’s another example. Suppose we had multiple attributes in our nodes data:

var nodes_data =  [
    {"name": "Lillian", "hair_colour": "brown", "sex": "F"},
    {"name": "Gordon", "hair_colour": "blond",  "sex": "M"}
]

We could link the two nodes together by hair_colour rather than by name, as long as we specify it in the id parameter of forceLink().

var links_data = [
	{"source": "brown", "target": "blond", "type":"A"}
]

var link_force =  d3.forceLink(links_data)
                        .id(function(d) { return d.hair_colour; });

distance: specifies how long the links should be. Default is 30.

This is an approximate value only - setting this to 50 doesn’t mean that each link will be 50 pixels apart. But each link should be longer than it would if you set this to 30.

It’s understandable enough that the force layout can only approximate our link distance, not guarantee it. For starters it has to satisfy the charge constraint from the nodes, as well as any other forces we apply to the simulation. Approximate distance is the best we can hope for.

Need more details? Here’s a nice explanation of linkDistance.

strength: controls the effect of linkDistance.

Setting this to 1 would mean that the full effect of the linkDistance parameter applies. By setting this to less than 1, you can relax the link distance constraint.

Setting this close to 0 results in all nodes floating outwards from each other. It’s like you don’t really have a link force at all.

iterations: from what I can make out from the documentation, it’s the number of applications of the link force per tick of the simulation.

You can use this to improve the rigidity of the graph for a runtime cost.

Constructing lattices is one application for modifying the iterations parameter.


Hope you found that useful! Click here to view to the rest of the force directed graph series.