Hierarchical Layout

Class HierarchicLayouter is a layout algorithm that portraits the precedence relation of directed graphs. It is ideal for many application areas, including, e.g.:

The hierarchical layout algorithm aims to highlight the main direction or flow within a directed graph. Cyclic dependencies of nodes will be automatically detected and resolved. Nodes will be placed in hierarchically arranged layers. Additionally, the ordering of the nodes within each layer is chosen in such a way that the number of line (or edge) crossings is small. Edge routing can be polyline, orthogonal, or in a curved style.

Figure 5.20. Sample layouts produced by class HierarchicLayouter

Sample layouts produced by class HierarchicLayouter
Sample layouts produced by class HierarchicLayouter
Sample layouts produced by class HierarchicLayouter
Problem solving at yWorks (just kidding ;-) Entity-Relationship Diagram. Displays pathways of the brain, layered by stages of visual processing.

Supplemental Layout Data

Class HierarchicLayouter implements interface PortConstraintKeys and uses the data provider keys which are defined therein to retrieve supplemental layout data for a graph's elements. Also used are further data provider keys defined by a number of classes from package y.layout.hierarchic. The data is bound to the graph by means of a data provider, which is registered using a given look-up key. Table 5.17, “Data provider look-up keys” lists all look-up keys for HierarchicLayouter.

Binding supplemental layout data to a graph is described in the section called “Providing Supplemental Layout Data”.

Table 5.17. Data provider look-up keys

Key Element Type Value Type Description
SOURCE_GROUPID_KEY Edge Object For each edge an arbitrary Object indicating the group its source end is affiliated with.
TARGET_GROUPID_KEY Edge Object For each edge an arbitrary Object indicating the group its target end is affiliated with.
SOURCE_PORT_CONSTRAINT_KEY Edge PortConstraint For each edge a PortConstraint object encoding its source end's port constraint.
TARGET_PORT_CONSTRAINT_KEY Edge PortConstraint For each edge a PortConstraint object encoding its target end's port constraint.
CORE_NODES Node boolean For each node a boolean value indicating whether it should be placed into the first layer.
LAYER_ID_KEY Node int For each node an integral value indicating the layer number it should be placed into.
EDGE_LABEL_LAYOUT_KEY Edge LabelLayoutData[] For each edge an array of LabelLayoutData objects that encode size and preferred placement for all labels of the edge.
GROUP_KEY Node Number For each node a Number object encapsulating an integral value that indicates the packed block the node is affiliated with.

Layout Options

HierarchicLayouter can be configured and extended in diverse ways. This section highlights some of the configuration options available for this layouter.

Drawing Style Options

Minimal Layer Distance (see API)

Determines the minimal distance between nodes that reside in adjacent layers.

Minimal Node Distance (see API)

Determines the minimal distance between adjacent nodes that reside in the same layer.

Minimal Edge Distance (see API)

Determines the distance between adjacent pairs of horizontal edge segments, and between horizontal edge segments and nodes.

Minimal First Segment Length (see API)

Determines the minimal length of the first segment in an orthogonal edge routing. This applies to the routing of self-loops, same-layer edges, and orthogonal inter-layer edge routing.

Maximal Duration (see API)

Sets the maximal duration of the layout process in milliseconds. The maximal duration is a soft bound, which may be exceeded in case essential parts of the layout calculation are still missing. Most likely the layout quality will increase with a longer calculation period. In most cases the layouter will consume the complete time assigned to it.

Layout Orientation (see API)

Determines the main layout orientation. The layouter tries to arrange nodes in such a way that all edges point in the main layout direction.

Top to Bottom
The main layout orientation will be from top to bottom. Note that the documentation for the other layout options assumes that this default layout orientation is being used.
Bottom to Top
The main layout orientation will be from bottom to top.
Left to Right
The main layout orientation will be from left to right.
Right to Left
The main layout orientation will be from right to left.

Layout Style (see API)

Influences the horizontal spacing between nodes, the number of bends of the edges, and the overall balance of the layout.

Linear Segments
Nodes will be placed in such a way that edge segments tend to have very few bends. This is a very good choice in combination with "Orthogonal Edge Routing." Disadvantage of this placement policy is that the width of the layout will increase.
Polyline
Nodes will be placed in such a way that the width of the layout gets very small without introducing node overlaps. A drawback of this placement policy is that edges will have a lot of bends.
Pendulum
A sound combination of "Linear Segments" and "Polyline."
Simplex
Produces high quality drawings. This node placer is based on the network simplex approach. Similar to "Linear Segments," the nodes will be placed in such a way that edge segments tend to have very few bends. Additionally, the resulting layout will be more balanced and more compact. This node placer tends to be slower than "Linear Segments."
Median Simplex
This drawer is based on the "Simplex" drawer, but produces slightly different results. It tends to produce more locally symmetric layouts for the sake of a few more bends.
Tree
Produces very nice layouts in case the graph is a tree. If the graph is not a tree, the placement policy "Linear Segments" will be used.

Figure 5.21, “Different hierarchic layout styles” displays the effect of using different layout styles. There is a tradeoff involved between the straightness of edge paths and the compactness of the diagram.

Figure 5.21. Different hierarchic layout styles

Routing Style (see API)

Determines the edge routing style.

Polyline
Edge paths will be routed as a polyline with a certain number of bends.
Orthogonal
Edge paths will be routed in an orthogonal style, i.e., only vertical and horizontal line segments will be used. Orthogonal edge routing increases the height of the layout.

Figure 5.22, “Different routing styles and different edge path realizers” below shows the effect of different routing styles available for class HierarchicLayouter.

Note

The visual representation of an edge (path) is defined by edge realizers, i.e., objects of type EdgeRealizer from the yFiles library package y.view. Both type and configuration of a realizer object determine how to draw an edge given its control points.

See also the section called “Edge Realizers” for descriptions of the yFiles predefined EdgeRealizer implementations.

Figure 5.22. Different routing styles and different edge path realizers

If enabled, all edges that do not point in the main layout direction will be routed as back-loops. Back-loops start at the bottom side of their source node, then turn around 180 degrees, go upward, then turn around 180 degrees again and finally connect to the upper side of their target node.

Layer Assignment Options

HierarchicLayouter assigns the nodes to separate layers. The nodes within each layer will be placed on the same horizontal line. The layers will be numbered from 1 to maxLayer and arranged vertically starting with the small-numbered layers. The rank of a node is the number of the layer it belongs to.

An important layering strategy for the hierarchic layout style is called Hierarchical Layering. A hierarchical layering tries to assign nodes to layers in a way that as much as possible edges of the graph will point to the main layout direction, i.e., the start nodes of the edges will have a smaller rank than the corresponding end nodes. Also, a hierarchical layering will never put two connected nodes in the same layer.

Layering Strategy (see API)

Hierarchical - Topmost
A simple hierarchical layering variant. All nodes with indegree zero will be assigned to the topmost layer of the layout. The number of separate layers will be as small as possible.
Hierarchical - Optimal
An optimal hierarchical layering strategy. The layer distance of an edge is the absolute difference between the layer numbers of its source and target node. Layer assignment will be done in such a way that the overall sum of the layer distances of all edges in the layout is minimal.
Hierarchical - Tight Tree Heuristic
A good heuristic that approximates the ranking done by "Topological - Optimal."
Hierarchical - Downshift Heuristic
An even faster heuristic that approximates the ranking done by "Topological - Optimal" by down-shifting some nodes in the layering. The quality is usually worse than the one produced by "Tight Tree Heuristic."
From Sketch
A very interesting layer assignment strategy that uses the initial y-coordinates of the nodes to determine a node layering. It tries to find a layering that is similar to the one in the input graph. When this layering strategy is used, the layouter may place nodes in the same layer, even though they are connected by an edge. These inner layer edges are always routed in an orthogonal style.
User-Defined Layering
The ranks of the nodes will be given by the user.

To specify the ranks, a data provider holding such supplemental layout data must be bound to the graph. The data provider is expected to be registered with the graph using key LAYER_ID_KEY.

BFS Layering
Layering based on a breadth-first search (BFS). All edges will span at most one layer in the resulting drawing. Edges between nodes that belong to the same layer are possible.

To specify nodes that should be place into the first layer, a data provider holding such supplemental layout data can be bound to the graph. The data provider is expected to be registered with the graph using key CORE_NODES. Note that in the absence of such a data provider all nodes that have no incoming edges are placed into the first layer.

Constrained Layer Assignment

Class ConstraintLayerer is an implementation of the Layerer interface that enables user-defined constrained layering. Nodes can be restricted to be placed either

  • absolute, i.e., into the first or last layer of the layout, or
  • relative to a given reference node into the same layer, a layer preceding that of the reference node, or a layer following that of the reference node.

The remaining nodes, that have no constraints defined, are processed by the core layerer that is set with ConstraintLayerer. By default, the core layerer uses the Tight Tree heuristic.

Figure 5.23, “Constrained hierarchical layering” shows a resulting hierarchical layout where nodes with an absolute constraint specified for them are placed in the topmost layer (note the emphasis on these nodes). Normally, i.e., when no constraints are specified, these nodes are placed in the very center of the graph as can be observed in the original hierarchical layout.

Figure 5.23. Constrained hierarchical layering

Hierarchical layout.
Constraint hierarchical layout.
Original hierarchical layout. Resulting hierarchical layout where the constrained nodes are placed in the topmost layer.

Example 5.19, “Setting the core layerer for ConstraintLayerer” presents how hierarchical layout is set up for constrained layer assignment where the previously configured Layerer implementation is used as ConstraintLayerer's core layerer. Nodes that have no constraints defined will be placed according to the layering strategy of this Layerer.

Example 5.19. Setting the core layerer for ConstraintLayerer

// Instantiate hierarchical layout and, in particular, configure the layerer.
HierarchicLayouter hl = new HierarchicLayouter();
hl.setLayeringStrategy(HierarchicLayouter.LAYERING_HIERARCHICAL_DOWNSHIFT);
// Instantiate a ConstraintLayerer.
ConstraintLayerer cl = new ConstraintLayerer();
// Set the previously configured layerer as ConstraintLayerer's core layerer.
cl.setCoreLayerer(hl.getLayerer());
// Set the ConstraintLayerer as the new layerer for hierarchical layout.
hl.setLayerer(cl);

To express both absolute and relative constraints, ConstraintLayerer offers a so-called "constraint factory" which provides the methods for specifying constraints for the nodes of a graph. API Excerpt 5.6, “Getter method for ConstraintFactory” shows the static getter method for the constraint factory.

API Excerpt 5.6. Getter method for ConstraintFactory

// Getter for the constraint factory.
static ConstraintFactory createConstraintFactory(Graph graph)

The returned constraint factory is specific for the graph given at instantiation. API Excerpt 5.7, “ConstraintFactory methods for specifying constraints” lists the methods that allow to define both absolute and relative constraints for nodes.

API Excerpt 5.7. ConstraintFactory methods for specifying constraints

// Absolute constraints.
void addPlaceNodeAtTopConstraint(Node n)
void addPlaceNodeAtBottomConstraint(Node n)

// Constraints relative to a given reference node.
void addPlaceNodeInSameLayerConstraint(Node reference, Node sameLayer)
void addPlaceNodeAboveConstraint(Node reference, Node above)
void addPlaceNodeBelowConstraint(Node reference, Node below)

Using class ConstraintLayerer in a hierarchical layout and defining constraints for the nodes of a graph is demonstrated in the tutorial demo application ConstraintLayererDemo.java.

Node Order Options

This section describes options that influence the ordering of the nodes within a layer and thus the number of edge crossings of the resulting layout.

Within class HierarchicLayouter an implementation of the interface LayerSequencer is responsible for determining the order of nodes within a layer. The default implementation of this interface is ClassicLayerSequencer. The options below describe some settings of this class.

Weight Heuristic (see API)

Determines the strategy used to find a better node ordering within a layer.

Barycenter
Uses the barycenter method.
Median
Uses the median method.

Use Transposition (see API)

If enabled, a postprocessing further reduces the number of edge crossings. The postprocessing step can be rather time consuming. This feature is disabled by default. It is advisable to activate this processing step for high quality layout results.

Remove False Crossings (see API)

If enabled, a postprocessing step tries to eliminate all false edge crossings. A false edge crossing is an edge crossing between two edges that share a common terminal node.

Advanced Layout Features

Weak Port Constraints (see API)

The hierarchic layout algorithm can be configured to obey port constraints. Using port constraints for both ends of each edge in the graph it is possible to specify at which side of the source and target node an edge path must connect. This feature is supported for all different kinds of edges: ordinary edges, self-loops, and same layer edges.

The algorithm can be instructed to place each port at either the North, East, South, or West side of the node, or to choose the most appropriate side itself.

Figure 5.24. Constraint on which side edges should connect to nodes

Constraint on which side edges should connect to nodes.

Strong Port Constraints (see API)

Opposed to "Weak Port Constraints," using "Strong Port Constraints" it is possible to not only specify the side of the node at which an edge must connect to it, but also the exact port position.

Both strong and weak port constraints can be mixed easily in the drawing. Strong port constraints are supported by all three types of edges.

Figure 5.25, “Constraint at which exact points edges should connect to nodes” demonstrates strong port constraints (the rather "odd" port positions have been set to be "strong").

Figure 5.25. Constraint at which exact points edges should connect to nodes

Constraint at which exact points edges should connect to nodes.

Edge/Port Grouping (Bus-style Edge Routing) (see API and API)

A special feature of the hierarchical layout algorithm is its ability to group multiple ports (edge end points) together to be anchored at the same location. This can be specified for both source ports and target ports.

Edges that belong to the same group at a specific end will additionally be routed in bus-style, i.e., if multiple edges start or end at the same layer and belong to the same group, even if they do not share the same node at that end point, they will be merged together in a bus structure in that layer.

This highly versatile configuration policy can be used to specify different interesting edge routing behaviors. Some of them are shown in Figure 5.26, “Multiple different edge group configurations resulting in bus style edge routings”.

Figure 5.26. Multiple different edge group configurations resulting in bus style edge routings

Multiple different edge group configurations resulting in bus style edge routings.

Packed Blocks

The hierarchical layout algorithm allows to bundle nodes within a layer to a so-called "packed block" of nodes. A packed block will always be placed as an inseparable unit on the layer. Note that this will only influence nodes that lie in the same layer. Figure 5.27, “Packed blocks” shows three packed blocks on different layers of the graph. In the figure, the blocks are emphasized both by an enclosing rectangle and also by different node colors.

Figure 5.27. Packed blocks

Packed blocks.

To specify the packed block a node should be put into, a data provider holding such supplemental layout data can be bound to the graph. The data provider is expected to be registered with the graph using key GROUP_KEY. Note that in the absence of the data provider no packed blocks are created.

Integrated Labeling

Besides the general labeling support as described in the section called “General Labeling”, which is available with all yFiles layout algorithms, the hierarchical layout algorithm additionally features integrated labeling. Integrated labeling is available for edge labels, they are taken into consideration when determining both node placement and edge path generation. With this strategy it is guaranteed that no edge label will overlap other objects in the diagram.

Figure 5.28. Automatic edge labeling methods

Automatic edge labeling methods
Automatic edge labeling methods
General edge labeling as a postprocessing step. Labels may overlap other objects. Edge labeling as part of main layout procedure. Labels only overlap their associated edges.

To specify size and preferred placement of edge labels when using integrated labeling, a data provider holding such supplemental layout data must be bound to the graph. The data provider is expected to be registered with the graph using key EDGE_LABEL_LAYOUT_KEY.

Enabling integrated labeling with HierarchicLayouter and using the services of class LabelLayoutTranslator to conveniently have such a data provider created and bound to the graph is described in the section called “Integrated Labeling”.

Package Structure

Package y.layout.hierarchic contains all classes that constitute hierarchical layout. The main layouter is encapsulated in the class HierarchicLayouter. A variant of this class, that is capable of laying out hierarchically organized graphs, is HierarchicGroupLayouter. The structure of the hierarchical layout implementation follows the Strategy design pattern. It is composed of implementations of the interface classes Layerer, LayerSequencer, and Drawer. Each of which is responsible for a certain phase within the layout process. Programmers can provide their specialized implementations of layout phases and can thus customize and extend layout behavior in a very powerful way.

Figure 5.29. Structure of the hierarchic layout package

Structure of the hierarchic layout package.

Tutorial Demo Code

The following yFiles tutorial demo programs demonstrate how to use class HierarchicLayouter in an application context.