Force-Directed graph layout approximation part II
In this article I'll describe the different calculations that we have to do in Repulsive and Attraction methods to calculate the position of the different nodes. As I published yesterday in part I, I'll focus on the Hooke's and Coulomb's laws and the integration inside the platform.
Anyway, in order to do this, I've had to change a little the TBox Class, now I need this new information:
Now the Tbox class manages information concerned to the Node class (in this image is all mixed together, and the code is still in refactoring process). However, for calculating the layout we need to know the Coulomb's force, the Hooke's force, the mass and the Speed. Notice that every one of this properties is a TForce class, this class lets me work with extended values in a pleasantly way.
To accomplish this functionality I've made a model in Delphi that looks like this:
At the end of the post, you can watch a little video of the running of the application.
Images from ffden-2.
For every node, we need to calculate the same as in the previous part. In each node will appear a repulsion force because every node has a positive charge. With this phenomenon all the nodes will try to spread out in different directions, but thanks to the edges modelling springs, will stop this repulsion movement applying an attraction force until they reach the equilibrium.
In the following video from derekowens, we can see a little introduction to the Coulomb's law:
The method for calculating the repulsive force for each node:
After calculating the different forces the graph will reorganize itself to show a human readable graph:
We can even add edges in runtime and the system will recalculate the new connections. This video shows the result of applying the algorithm to the first graph:
Hooke's law simulation.
- Hooke's Law (attractive force):
Anyway, in order to do this, I've had to change a little the TBox Class, now I need this new information:
Now the Tbox class manages information concerned to the Node class (in this image is all mixed together, and the code is still in refactoring process). However, for calculating the layout we need to know the Coulomb's force, the Hooke's force, the mass and the Speed. Notice that every one of this properties is a TForce class, this class lets me work with extended values in a pleasantly way.
To accomplish this functionality I've made a model in Delphi that looks like this:
procedure AttractiveForce()
var
i, j : integer;
node, node2 : TBox;
radius, Hooke, vector : Extended;
offset : TPointR;
begin
for i := 0 to Boxlist.Count - 1 do
begin
node := Boxlist.items[i];
node.HookeForce.setVal(0, 0);
for j := 0 to High(node.FNeighbour) do
begin
node2 := Boxlist.GetBox(node.FNeighbour[j]);
radius = distanceNodes(node, node2, offset);
if Compare(radius, 0.0, '<>') then
begin
vector := PointR(-(offset.X / radius),-(offset.Y / radius));
Hooke.X := (vector.X * sqr(radius) / (Epsilon * node.mass));
Hooke.Y := (vector.Y * sqr(radius) / (Epsilon * node.mass));
end;
node.HookeForce.sr0(node.HookeForce.r0 + Hooke.X);
node.HookeForce.sR1(node.HookeForce.r1 + Hooke.Y);
new_kinetic_energie := new_kinetic_energie + (sqr(radius) / (Epsilon * node.mass));
end;
end;
end;
At the end of the post, you can watch a little video of the running of the application.
- Coulomb's Law (repulsive force)
Images from ffden-2.
For every node, we need to calculate the same as in the previous part. In each node will appear a repulsion force because every node has a positive charge. With this phenomenon all the nodes will try to spread out in different directions, but thanks to the edges modelling springs, will stop this repulsion movement applying an attraction force until they reach the equilibrium.
In the following video from derekowens, we can see a little introduction to the Coulomb's law:
The method for calculating the repulsive force for each node:
procedure RepulsiveForce()
var
i, j : integer;
node, node2 : TBox;
radius, vector : Extended;
offset : TPointR;
begin
for i := 0 to Boxlist.Count - 1 do
begin
node := Boxlist.items[i];
node.CoulombForce.setVal(0, 0);
for j := 0 to Boxlist.Count - 1 do
begin
node2 := Boxlist.items[j];
if (node.id <> node2.id) then
begin
radius = distanceNodes(node, node2, offset);
if Compare(radius, 0.0, '<>') then
begin
vector := PointR(offset.X / radius,offset.Y / radius);
node.CoulombForce.sr0(node.CoulombForce.r0 + ((Epsilon * node.mass * vector.X) / radius));
node.CoulombForce.sR1(node.CoulombForce.r1 + ((Epsilon * node.mass * vector.Y) / radius));
new_kinetic_energie := new_kinetic_energie + (Epsilon * node.mass / radius);
end;
end;
end;
end;
end;
After calculating the different forces the graph will reorganize itself to show a human readable graph:
We can even add edges in runtime and the system will recalculate the new connections. This video shows the result of applying the algorithm to the first graph:
- Related links:
Hooke's law simulation.
Updated material:
ReplyDeleteJohn Grindall
BioInformatics Force graph layout Python