This chapter was written with the participation of Peter Uhnák (i.uhnak@gmail.com).
A layout is the visualization representation along a two-dimensional plan of elements, typically edges and nodes. A layout makes a visualization not only aesthetic but also comprehensible. Roassal offers numerous different layouts and supports the composition of layouts.
Consider the following example (Figure 0.1):
The script builds some elements and edges that link these elements. Each element is translated to a random location. Applying the RTTreeLayout
layout highlights the structure from the connection between the elements (Figure 0.2):
The layout reveals that the elements form a binary tree and one can distinguish what the top root node is and what the leaves are.
Roassal offers over 30 different layouts, each useful in its own rights.
Element-based layouts are a particular set of layouts in Roassal which do not consider edges to determine element locations. Instead of using edges, an element-based layout uses element size, shape or position within a group. Edges are not forbidden: they are simply not used by the layout.
Circle layouts arrange elements along a geometrical circle. The order of the elements, as with all circle-based layouts, is the same as the collection on which the layout operates.
A circular layout may be parametrized along several properties:
Without any option, the circle layout distributes all the elements evenly along a circle (2pi
/elements size
). Additionally radius can be either set absolutely via initialRadius:
, or as a scalable factor scaleBy:
- then the radius will be elements size * scaleFactor
.
It is important to note that RTCircleLayout
does not take into consideration the size of the elements; this is enough when the elements are uniform, however if their sizes vary, different layouts may be considered.
Variants of the default circle layout, named equidistant and weighted layouts, are also available:
RTEquidistantCircleLayout
makes sure that there is the same distance between each element.RTWeightedCircleLayout
on the other hand adds spacing based on the size of the elements. Thus there will be less space between smaller elements, and more space between large ones.So now if we apply layout on non-uniform elements we get:
A flow layout arranges elements in a 'flowing' manner. While we could consider circle layouts to be also a flow in a clockwise direction, layouts presented here provide flow by lines and columns.
The flow layout arranges elements in lines, each line flowing from left to right; Horizontal flow on the other hand is in columns, flowing from top to bottom.
Flow layouts vertically line up elements according to their size. The layout may be configured with a maximum total width (maxWidth:
). For Grid and Cell layout this limit is instead number of items in the line (lineItemsCount:
).
By default a flow layout try to fill a roughly rectangular area, while a grid layout approximate the golden ratio.
Cells in Flow layouts can be aligned:
To align RTHorizontalFlowLayout
use alignTop
for left, and alignBottom
for right alignment.
Two line layouts are offered: RTVerticalLineLayout
and RTHorizontalLineLayout
to layout, vertically and horizontally, respectively (Figure 1.6).
Here is an example of the horizontal line layout:
Replacing RTHorizontalLineLayout
by RTVerticalLineLayout
triggers the vertical line layout instead.
Edge-driven layouts determine the location of an element based on the edges linking these elements.
The beginning of this chapter gives an example of using the tree layout.
Note that in the picture above the horizontalGap is applied only to the leaves of the tree; distance between parents is then accommodated automatically, so no overlapping or crossing occurs. The tree Layout orients the tree vertically, while the RTHorizontalTreeLayout
uses an original orientation, from left to right.
One problem with trees is that they tend to have many leaves which often results in very wide visualizations. One way to deal with this problem is to present the tree circularly. Since each new layer increases the radius of the circle, the overall element structure accommodates the space better.
Note that RTRadialTreeLayout
may produce an odd result in the presence of edge cycles.
This layout is especially useful for visualizing dependencies and flow charts, since it organizes elements in such a manner that the flow of the graph is emphasized.
Cluster is visually similar to radial tree; it groups related elements together (Figure 2.4:.
The difference between the cluster and radial layouts has to do with the layers forming circles.
Sugiyama layout is a hierarchical layered layout. It places elements in hierarchical order such that edges goes from higher layer to lower layer. At the same time the layout minimizes the amount of layers and edge crossings (Figure 2.5).
Force Based Layout applies force between related elements similar to electrical charge. Thus related elements will repulse each other. The charge
is usually negative since it represents repulsion.
Additionally to charge:
you can also specify strength:
, which is the strength of the bonds (edges) between elements.
The force based layout is appealing due to its simplicity of use and nice results that it produces. However, it badly scales. Performing a force based layout on hundreds of nodes and edges may take hours (literally). Before performing this layout on a large graph, one may want to try it on a reduced graph.
RTRectanglePackLayout
packs all the elements as tightly as possible. It uses an element's bounding box, so using circles or polygons instead of boxes will have no effect. One use for this layout is to provide comparative views of some elements — name clouds, source code size of classes, etc.
RTNameCloud
also internally uses RTRectanglePackLayout
The class RTLayoutBuilder
offers expressive ways to build and compose layouts. The layout builder is offered by Mondrian. Consider the following Mondrian script (Figure 3.1):
The script represents each subclass of RTShape
as a box. Edges represents dependencies between classes, without considering inheritance. We made this example to produce lonely classes. It often happens that lonely classes need a particular layout.
The message ifNotConnectedThen:
takes as argument a layout (i.e., an instance of a subclass of RTLayout
). The provided layout is applied only to elements that are not connected (i.e., with no incoming or outgoing edges).
Using the composition of layout and the layout builder (Figure 3.3):
Several layouts are available:
force
for a force based layout (also called spring layout)horizontalLine
for the horizontal line layoutverticalLine
to vertically line up elementstree
to have a vertical treehorizontalTree
for an horizontal tree, roots are on the left-hand side and leaves on the right-hand sidecluster
and radial
for radial-based layoutsugiyama
for the Sugiyama layout, which is a vertical tree layout that minimizes edges crossingIf you want to add your own layout you just need to subclass RTLayout
and implement RTLayout>>doExecute: elements
.
For more fine-graded control you have three main methods available.
doInitialize:
can be used for element preprocessing, if needed. For example RTAbstractGraphLayout
uses this for removing cycles from the graph, so the layouts can work only with trees.doExecute:
is the main method, and the only method that must be implemented. Perform your layout here.doPost:
allows one to insert post-processing actions.