The following global parameters are specific to the IlvAnnealingLabelLayout class:
Label offset
The label offset controls the desired minimum distance between
two neighboring labels (see Label and obstacle offsets, left). To avoid
labels being placed too close to each other, you can increase the
label offset. This conceptually pushes the labels farther apart.
However, depending on the available space, the minimum distance
between labels cannot always be maintained.
Example of specifying label offset
To set the label offset:
In CSS
Add to the
LabelLayout
section:
labelOffset: "25";
In Java™
Call:
layout.setLabelOffset(25f);
Obstacle offset
The obstacle offset controls the desired minimum distance between
a label and an unrelated obstacle. The obstacle offset is usually
more important than the label offset because, if the obstacle
offset is too small, the label may be placed so close to an
unrelated obstacle that it incorrectly appears to be assigned to
that obstacle (see Label and obstacle offsets, right: does,
for example, the green label belong to the upper yellow node or
to the green node?). Increasing the obstacle offset conceptually
pushes the label away from the obstacle. However, depending on
the available space, the minimum distance between label and
obstacle cannot always be maintained.
The obstacle offset should not be set to an unreasonably large
value (such as
Float.MAX_VALUE
) because this can cause computational problems inside quadtree
operations.
Example of specifying node placement
iterations and allowed time (GL algorithm)
To set the obstacle offset:
In CSS
Add to the
LabelLayout
section:
obstacleOffset: "25";
In Java
Call:
layout.setObstacleOffset(25f);
The specified obstacle offset works
globally for all labels.
In Java, it is also possible to specify
a smaller obstacle offset for specific label/obstacle pairs.
You need to install an obstacle offset interface that returns
the obstacle offset for a specified pair:
layout.setObstacleOffsetInterface(new IlvObstacleOffsetInterface() { public float getOffset(IlvLabelingModel m, Object label, Object obstacle) { if (label instanceof IlvZoomableLabel && obstacle instanceof IlvIcon) return 3f; else // use the global obstacle offset return Float.MAX_VALUE; } });
The effective offset is the lower of the values returned by
the obstacle offset interface and the globally specified
offset respectively. Hence, the obstacle offset interface in
the previous example means that IlvZoomableLabel labels can be placed up
to 3 units near IlvIcon obstacles, while they are placed
away from all other obstacles by at least the amount specified
by the call
layout.setObstacleOffset
.
![Picture
illustrating the obstacle offset and the label offset parameters](../../../GraphLayout/_media/Fig6-12online15_default.gif)
Label and obstacle offsets
Label movement policy
The label movement policy is an easy way
to define which labels should be moved by the label layout
algorithm.
Example of specifying label movement
policy
In CSS
It is not possible to specify the label movement policy in
CSS, but you can integrate a label movement policy into the
label layout renderer by subclassing the renderer. An example
showing how to subclass renderers is provided in Writing a new layout renderer to clip
links.
In Java
The following code installs a label
movement policy such that the layout moves only labels with a
height greater than 100:
layout.setLabelMovementPolicy(new IlvLabelMovementPolicy() { public boolean allowMove(IlvLabelingModel labelingModel, Object label) { return (labelingModel.boundingBox(label).height > 100); } });
Labels with smaller heights are not
moved. However, they are also not completely ignored, because
the layout tries to position the movable labels so that they
do not overlap the immovable labels, and the label offset is
respected between movable and immovable labels.
A more general useful example is a movement policy that
prohibits moving labels that initially do not overlap
anything. This predefined movement policy is available through
the class IlvOverlappingLabelMovementPolicy. You
can use this class in applications that have their own label
positioning mechanism and use the Annealing Label layout only
as a postprocessing step to improve the positions of
overlapping labels. To install this policy, call:
layout.setLabelMovementPolicy(new IlvOverlappingLabelMovementPolicy());
Automatic update
After layout, the labels are placed close
to the related obstacle according to the label descriptor. For
instance, a link label is placed close to its link. However, if
you move the link interactively, the label normally stays at the
old position, which may be far away from the link after the
movement. The label loses the connection to the link, and a new
layout is necessary.
Because it is too time-consuming to redo
the layout after each single interactive move, the Annealing
Layout algorithm has a feature that automatically updates the
labels on geometric changes, that is, the label follows the link
when the link moves.
Example of specifying automatic update
To enable this feature:
In CSS
Add to the LabelLayout section:
autoUpdate: "true";
In Java
Call:
layout.setAutoUpdate(true);
If automatic update is enabled, the
algorithm does not perform a full layout of all labels during
each interactive change. It repositions only the label whose
related obstacle has moved in one step. Thus it may produce
more overlaps than a full layout. The automatic update
mechanism is much faster, however, and hence better suitable
for interactions.
Note
The automatic update feature works only if the labeling model
provides LabelingModelEvent objects on each
obstacle movement. The IlvDefaultLabelingModel provides these
events. If you implement your own labeling model, you must
provide these events in order to use the automatic update
feature.
Expert parameters
A few parameters are available for an
advanced use of the Annealing Label Layout.
Quadtree
To speed up the layout, the Annealing
Label Layout algorithm uses a quadtree data structure. The
quadtree enables a very efficient check for overlaps. The
layout algorithm automatically detects from the graph model
whether the quadtree can be used. You can switch it off
explicitly by calling:
layout.setUseQuadtree(false);
Normally, it is not useful to switch the
quadtree off because it slows down label positioning. However,
if you implement your own labeling model, you may want to use
this flag to verify that the labeling model is correct.
Simulated annealing
Simulated annealing is an iterative
mechanism. In each iteration step, all labels are tested for
better positions. Usually, the algorithm is capable of
detecting automatically when to stop. The algorithm stops if:
- The maximum number of iterations is reached.
- After several iterations, no better position was found for any label.
- After several iterations, the quality did not improve by a specified percentage.
In a few cases, it may be necessary to
limit the number of iterations, which can be done by calling:
layout.setAllowedNumberOfIterations(100);
As a general hint, to obtain a
reasonable layout, the allowed number of iterations should not
be considerably lower than the number of labels.
Simulated Annealing stops if, after
several iterations, no better position was found for any label.
Because the search is randomized, this does not necessarily
mean that the best position was already found; however, it
indicates that finding the best position would require too much
layout time. The number of ineffective iterations before
stopping can be changed by calling:
layout.setMaxNumberOfFailIterations(maxNumber);
The default value is 20. If you set it
to a higher value, the layout slows down but may find better
positions for the labels. If you set it to a lower value, the
layout stops sooner, but the label positions may be far from
optimal.
In some cases, the algorithm improves
the quality in each step, but the amount of improvement gets
smaller in each step. In this situation, the previous
fail-iteration criteria does not work well because there is an
improvement in each step, but the amount of the improvement is
so negligibly small that we want to stop. Therefore, it is also
possible to require that the quality must improve in each step
by a minimum percentage.
For example, to specify that the
algorithm must improve over ten rounds by at least 2%, call:
layout.setNumberIterationsForMinImprovement(10); layout.setMinImprovementPercentageToContinue(2);
By default, the layout stops if the
quality did not improve by 0.5% over five iterations. If you
set the required improvement percentage higher or the number of
iterations lower, the layout stops sooner, but the label
positions may be far from optimal. If you set the required
percentage to 0%, this stop criterion is disabled and will no
longer have any effect.