skip to main content
Programmer's documentation > Using graph layout algorithms > Nested layouts > Layout of nested graphs in code
 
Layout of nested graphs in code
Describes how to perform a layout on nested graphs.
*The classes that support nested graphs
*Explains how layouts are performed on nested graphs.
*Order of layouts in recursive layouts
*Explains the order in which recursive layouts are applied on nested graphs.
*Simple recursion: applying the same layout to all subgraphs
*Describes how to obtain a nested graph with the same layout throughout.
*Advanced recursion: mixing different layouts in a nested graph
*Describes the case where you want to mix different layouts in one nested graph.
The classes that support nested graphs
The IlvGrapher class provided by Rogue Wave®  JViews Framework allows nested graphs to be represented. This facility is useful for applications that are not based on Rogue Wave JViews Diagrammer or on styling.
In an application that works directly on an instance of IlvGrapher, a recursive layout must be performed explicitly. Additional steps are required to perform a layout on nested graphers.
For more information, see Nested graphers.
The mechanism uses the auxiliary classes IlvRecursiveLayout and IlvMultipleLayout internally. They are explained in detail in Recursive layout and Multiple layout.
Order of layouts in recursive layouts
Assume grapher 1 contains two subgraphers L 1.1 and L1.2, and subgrapher 1.1 contains two subgraphers L 1.1.1 and L 1.1.2, as shown in the following figure. The recursive layout needs to be applied in reverse order, as follows:
1. Layout on L 1.1.1
2. Layout on L1.1.2
3. Layout on L1.1
4. Layout on L1.2
5. Layout on L1
Nested graph with recursive layouts
This means that the layout is applied to the graph after all the layouts of its subgraphs have been applied.
In this example, all layouts of subgrapher L 1.1 are finished before the layout of grapher L 1 starts. It is the correct order for a recursive layout. This order ensures that the layout of a subgraph does not invalidate the layout of its parent graphs.
Simple recursion: applying the same layout to all subgraphs
You can apply the same layout where both the following conditions hold:
*The same layout algorithm needs to be applied to the topmost graph and all its subgraphs.
*The settings of the layout algorithm (that is, the layout parameters) need to be the same for the topmost graph as for all the subgraphs.
The following figure shows an example where a Tree Layout is applied to the topmost graph as well as to all its subgraphs. Moreover, the settings of the Tree Layout algorithm are the same for all the graphs: the application does not need, for example, one flow direction in the topmost graph and a different one in the subgraphs.
Example of a recursive layout of a nested graph
Obtaining such recursive layouts is easy. The class IlvGraphLayout provides a special version of the performLayout method:
 
performLayout(boolean force, boolean redraw, boolean traverse)
When the last boolean argument is set to true, the layout is applied not only to the graph attached to the layout instance, but also, in a recursive way, to its subgraphs.
Internal mechanism
The internal mechanism is based on the principle that a layout instance is used for only one graph and is not reused for its subgraphs. Therefore, the Tree Layout instance is automatically “cloned” using the copy method of the class IlvGraphLayout.
The graph layout is applied to a graph model, and the same principle holds for the graph models (see Using the graph model): a graph model instance is used for only one graph and is not reused for subgraphs.
The graph models for the subgraphs are created by calls to the getGraphModel method of the class IlvGraphLayout, which in turn creates the graph model using the method createGraphModel of the class IlvGraphModel.
All these operations are done automatically, in a transparent way. All you have to do is to call the method performLayout with the traverse argument set to true.
If needed, you can get the layout instances applied on the subgraphs by calling the following method on IlvGraphLayout:
 
Enumeration getLayouts(boolean preOrder)
This method returns an enumeration of instances of IlvGraphLayout. If the preOrder flag is true, the layout of the parent graph occurs before the layout of its child nodes in the enumeration. If the preorder flag is false, the layout of the parent graph occurs after the layout of its child nodes. For example, in the graph of Nesting structure in a graph, the call getLayouts(true) returns the layouts for the subgraphs in this order: L1, L1.1, L1.1.1, L1.1.2, L1.2. The call getLayouts(false) returns the layouts for the subgraphs in this order: L1.1.1, L1.1.2, L1.1, L1.2, L1.
Java code sample
The following Java™ code sample illustrates how to apply a single layout algorithm to a nested graph:
 
...
IlvGrapher grapherA = new IlvGrapher();
IlvGrapher grapherB = new IlvGrapher();
 
// Fill the graphers with nodes and links
...
// grapherB is added as a subgraph of grapherA
grapherA.addNode(grapherB, false);
 
// Create the layout instance
IlvTreeLayout layout = new IlvTreeLayout();
 
// Attach the topmost grapher to the layout
layout.attach(grapherA);
 
// Perform the recursive layout
try {
        int code = layout.performLayout(true, true, true);
 
        System.out.println("Layout completed (code " +
          code + ")");
}
catch (IlvGraphLayoutException e) {
        System.err.println(e.getMessage());
}
...
// Detach the grapher when layout no more needed
layout.detach();
...
For experts
In this first variant, the grapher adapter (the graph model of IlvGrapher) is handled internally. If a grapher adapter is explicitly allocated, it must be disposed of when no longer necessary. However, all grapher adapters that are created internally are always disposed of automatically. Here is an equivalent variant that shows how to use the grapher adapter:
 
...
IlvGrapher grapherA = new IlvGrapher();
IlvGrapher grapherB = new IlvGrapher();
 
// Fill the graphers with nodes and links
...
// grapherB is added as a subgraph of grapherA
grapherA.addNode(grapherB, false);
 
// Create the layout instance
IlvTreeLayout layout = new IlvTreeLayout();
 
// Create a grapher adapter for the topmost grapher
IlvGrapherAdapter adapter = new IlvGrapherAdapter(grapherA);
 
// Attach the adapter to the layout
layout.attach(adapter);
 
// Perform the recursive layout
try {
        // perform the layout with argument traverse = true
        int code = layout.performLayout(true, true, true);
 
        System.out.println("Layout completed (code " +
          code + ")");
}
catch (IlvGraphLayoutException e) {
        System.err.println(e.getMessage());
}
...
// Detach the adapter when layout no more needed
layout.detach();
...
Layout parameters
Section Internal mechanism explains that, when applying the same layout algorithm in a recursive way, the layout instances for the subgraphs are obtained by “cloning” the layout instance attached to the topmost graph.
The layout parameters of the “clone” are the same as the parameters of the topmost layout, except for the parameters that are specific to a node or a link. Such parameters are not copied when the layouts are cloned and need to be set separately for each layout instance.
For example, if you need to declare a node node1 contained in the subgraph grapherB of the topmost graph grapherA as fixed (seePreserve fixed nodes), you can use the following code:
 
...
IlvGrapher grapherA = new IlvGrapher();
IlvGrapher grapherB = new IlvGrapher();
 
// fill the graphers with nodes and links;
// grapherB is added as a subgraph of grapherA
grapherA.addNode(grapherB, false);
 
// Create the layout instance
IlvTreeLayout layout = new IlvTreeLayout();
 
// Attach the topmost grapher to the layout
layout.attach(grapherA);
 
// Ask the layout algorithm to not move the nodes
// specified as fixed. This settings is automatically
// copied on the sublayouts. Do not specify this global
// settings directly on the sublayout, because it gets automatically
// the same settings as the topmost layout
layout.setPreserveFixedNodes(true);
 
// Search the layout instance used for grapherB
IlvGraphLayout subLayout = null;
Enumeration layouts = layout.getLayouts(true);
while (layouts.hasMoreElements()) {
       subLayout = (IlvGraphLayout)layouts.nextElement();
       if (subLayout.getGraphModel().getGrapher() == grapherB)
              break;
}
 
// Specify node1 (contained in grapherB) as fixed
subLayout.setFixed(node1, true);
 
// Now perform the recursive layout. The node node1 will be considered as fixed
// by the layout applied to grapherB
...
NOTE You should not try to change any global settings of the layouts applied to the subgraphs (that is, settings that are not specific to a node or a link). These settings are copied anyway from the layout instance of the topmost grapher, so your changes would be erased just before the recursive layout runs.
Advanced recursion: mixing different layouts in a nested graph
The need for mixing layouts arises when at least one of the following conditions is met:
*The layout algorithm to be applied on subgraphs is not the same as the algorithm needed for the topmost graph.
*Different layouts need to be applied to different subgraphs.
*The same layout algorithm needs to be applied to different graphs but with different settings.
In these cases of advanced recursion, where you want to apply different layouts to different subgraphs, you must specify which layout must be used for which subgraph. You must start the layouts in the correct order. This is called recursive layout.
The class IlvRecursiveLayout is a subclass of IlvGraphLayout, but it is not a real layout algorithm. It is rather a facility to apply other layout algorithms recursively on a nested graph.
The class IlvRecursiveLayout can also be used to apply the same layout to all subgraphs. In fact, when using the API explained in subsection Simple recursion: applying the same layout to all subgraphs, an instance of IlvRecursiveLayout is used internally.
The class IlvRecursiveLayout can be used to apply multiple layouts to the same nested graph. This is necessary if for each subgraph, a node layout and a separate link layout must be applied.
Further details and code samples of the class IlvRecursiveLayout are explained in the following section Recursive layout.
To apply layout algorithms recursively:
1. Allocate and attach an instance of IlvRecursiveLayout. Since it is a subclass of IlvGraphLayout, you use the same mechanism as for all other graph layout classes:
 
IlvRecursiveLayout recLayout = new IlvRecursiveLayout();
IlvGrapher topLevelGrapher = ...
recLayout.attach(topLevelGrapher);
2. Specify which layout style should be used for each subgraph.
You must allocate an individual instance of IlvGraphLayout for each subgraph.
 
recLayout.setLayout(subgraph1, new IlvTreeLayout());
recLayout.setLayout(subgraph2, new IlvBusLayout());
recLayout.setLayout(subgraph3, new IlvGridLayout());
3. Set the layout parameters of these individual layouts of the subgraphs as needed.
4. Apply the recursive layout to the top-level grapher. This automatically applies the sublayouts to the subgraphs as well. You use the same method as for all other graph layout classes, because IlvRecursiveLayout is a subclass of IlvGraphLayout.
 
try {
        recLayout.performLayout();
}
catch (IlvGraphLayoutException e) {
        System.err.println(e.getMessage());
}
5. Detach the recursive layout from the top-level grapher when it is no longer needed. This automatically detaches all sublayouts from all subgraphers.
 
recLayout.detach();

Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.