An implementation of a simulated annealing layout, based on "Drawing Graphs
Nicely Using Simulated Annealing" by Davidson and Harel (1996). This
paper describes these criteria as being favourable in a graph layout: (1)
distributing nodes evenly, (2) making edge-lengths uniform, (3)
minimizing cross-crossings, and (4) keeping nodes from coming too close
to edges. These criteria are translated into energy cost functions in the
layout. Nodes or edges breaking these criteria create a larger cost function
, the total cost they contribute related to the extent that they break it.
The idea of the algorithm is to minimise the total system energy. Factors
are assigned to each of the criteria describing how important that
criteria is. Higher factors mean that those criteria are deemed to be
relatively preferable in the final layout. Most of the criteria conflict
with the others to some extent and so the setting of the factors determines
the general look of the resulting graph.
In addition to the four aesthetic criteria the concept of a border line
which induces an energy cost to nodes in proximity to the graph bounds is
introduced to attempt to restrain the graph. All of the 5 factors can be
switched on or off using the isOptimize...
variables.
Simulated Annealing is a force-directed layout and is one of the more
expensive, but generally effective layouts of this type. Layouts like
the spring layout only really factor in edge length and inter-node
distance being the lowest CPU intensive for the most aesthetic gain. The
additional factors are more expensive but can have very attractive results.
The main loop of the algorithm consist of processing the nodes in a
deterministic order. During the processing of each node a circle of radius
moveRadius
is made around the node and split into
triesPerCell
equal segments. Each point between neighbour
segments is determined and the new energy of the system if the node were
moved to that position calculated. Only the necessary nodes and edges are
processed new energy values resulting in quadratic performance, O(VE),
whereas calculating the total system energy would be cubic. The default
implementation only checks 8 points around the radius of the circle, as
opposed to the suggested 30 in the paper. Doubling the number of points
double the CPU load and 8 works almost as well as 30.
The moveRadius
replaces the temperature as the influencing
factor in the way the graph settles in later iterations. If the user does
not set the initial move radius it is set to half the maximum dimension
of the graph. Thus, in 2 iterations a node may traverse the entire graph,
and it is more sensible to find minima this way that uphill moves, which
are little more than an expensive 'tilt' method. The factor by which
the radius is multiplied by after each iteration is important, lowering
it improves performance but raising it towards 1.0 can improve the
resulting graph aesthetics. When the radius hits the minimum move radius
defined, the layout terminates. The minimum move radius should be set
a value where the move distance is too minor to be of interest.
Also, the idea of a fine tuning phase is used, as described in the paper.
This involves only calculating the edge to node distance energy cost
at the end of the algorithm since it is an expensive calculation and
it really an 'optimizating' function. fineTuningRadius
defines the radius value that, when reached, causes the edge to node
distance to be calculated.
There are other special cases that are processed after each iteration.
unchangedEnergyRoundTermination
defines the number of
iterations, after which the layout terminates. If nothing is being moved
it is assumed a good layout has been found. In addition to this if
no nodes are moved during an iteration the move radius is halved, presuming
that a finer granularity is required.