Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
Calling Layout Algorithms

Hierarchical layout

This example shows how to read a graph from a file and use a layout algorithm to retrieve a hierarchical visualization of it.

using namespace ogdf;
int main()
{
Graph G;
GraphAttributes::nodeGraphics |
GraphAttributes::edgeGraphics |
GraphAttributes::nodeLabel |
GraphAttributes::edgeStyle |
GraphAttributes::nodeStyle |
GraphAttributes::nodeTemplate);
if (!GraphIO::read(GA, G, "unix-history.gml", GraphIO::readGML)) {
std::cerr << "Could not load unix-history.gml" << std::endl;
return 1;
}
SL.setCrossMin(new MedianHeuristic);
ohl->nodeDistance(25.0);
ohl->weightBalancing(0.8);
SL.setLayout(ohl);
SL.call(GA);
GraphIO::write(GA, "output-unix-history-hierarchical.gml", GraphIO::writeGML);
GraphIO::write(GA, "output-unix-history-hierarchical.svg", GraphIO::drawSVG);
return 0;
}
Declares class GraphIO which provides access to all graph read and write functionality.
Declaration of class MedianHeuristic.
Declaration and implementation of the optimal third phase of the Sugiyama algorithm.
Declaration of optimal ranking algorithm for Sugiyama algorithm.
Declaration of Sugiyama algorithm.
Stores additional attributes of a graph (like layout information).
Data type for general directed graphs (adjacency list representation).
Definition Graph_d.h:521
The median heuristic for 2-layer crossing minimization.
The LP-based hierarchy layout algorithm.
double layerDistance() const
Returns the minimal allowed y-distance between layers.
The optimal ranking algorithm.
Sugiyama's layout algorithm.
void setRanking(RankingModule *pRanking)
Sets the module option for the node ranking (layer assignment).
int main()
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.

Step-by-step explanation

  1. What we see here for the first time is how to read a graph from a file. To achieve this we first have to enable all the attributes we want to be filled in using the information from the specified file. When calling ogdf::GraphIO::read() (again specifying the correct reader function for .gml files) any attribute enabled in GA will be parsed from the file – if present.
  2. We then set up the configuration for a hierarchical layout algorithm called ogdf::SugiyamaLayout. As can be seen the algorithm is highly modular. In this case we specify
    1. A ranking module that will determine the layering of the graph
    2. A module that handles the minimization of two-layer crossing
    3. The main module that computes the actual graph layout
  3. Although this is done by passing dynamically allocated configuration objects we don't have to worry about cleaning them up, as the layout class takes care of that. Also there is default values for all modules so you need not explicitly set all of them.
  4. Calling the layout algorithm on an ogdf::GraphAttribute object relies on node size information and will alter the xy-coordinates of the nodes but will leave the other attributes untouched, so the svg visualization that is output in the end will still use the information initially read from the .gml file.

Hierarchical layout with predefined layering

This example shows a slight modification of the previous one in that layering is not done by an optimization module but instead is specified in advance.

using namespace ogdf;
int r[] = {
0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 10, 11, 12, 12,
13, 14, 14, 15, 16, 17, 18, 18, 19, 19, 20, 21, 22, 22,
22, 23, 23, 23, 23, 24, 25, 26, 27, 27, 27, 28, 29, 29,
29, 30, 30, 31, 31, 31, 32, 33, 33, 34, 34, 35, 35, 35,
35, 0, 1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18,
19, 20, 21, 22, 23, 25, 27, 29, 30, 31, 32, 33, 34, 35, -1
};
int main()
{
Graph G;
GraphAttributes::nodeGraphics |
GraphAttributes::edgeGraphics |
GraphAttributes::nodeLabel |
GraphAttributes::edgeStyle |
GraphAttributes::nodeStyle |
GraphAttributes::nodeTemplate);
if (!GraphIO::read(GA, G, "unix-history-time.gml", GraphIO::readGML)) {
std::cerr << "Could not load unix-history-time.gml" << std::endl;
return 1;
}
NodeArray<int> rank(G);
int i = 0;
for(node v : G.nodes)
rank[v] = r[i++];
SL.arrangeCCs(false);
ohl->nodeDistance(25.0);
ohl->weightBalancing(0.7);
SL.setLayout(ohl);
SL.call(GA, rank);
GraphIO::write(GA, "output-unix-history-hierarchical-ranking.gml", GraphIO::writeGML);
GraphIO::write(GA, "output-unix-history-hierarchical-ranking.svg", GraphIO::drawSVG);
return 0;
}
Dynamic arrays indexed with nodes.
Definition NodeArray.h:125
Class for the representation of nodes.
Definition Graph_d.h:177
void setCrossMin(LayeredCrossMinModule *pCrossMin)
Sets the module option for the two-layer crossing minimization.
int r[]

There is just one new concept we encounter here which is ogdf::NodeArray<T>, a templated class used for direct mapping from ogdf::node handles to any type T. In this case it holds a rank value for each node which is later passed together with GA to the layout algorithm. In this case the ranking optimization module has no effect. Note that we also disable the separate layout and arranging of connected components by the default packing module using ogdf::SugiyamaLayout::arrangeCCs().

Energy-based layout

This example shows yet another layout algorithm, ogdf::FMMMLayout (fast multipole multilevel layout), suited for very large graphs and based on potential-field and force computations.

using namespace ogdf;
int main()
{
Graph G;
if (!GraphIO::read(G, "sierpinski_04.gml")) {
std::cerr << "Could not load sierpinski_04.gml" << std::endl;
return 1;
}
for (node v : G.nodes)
GA.width(v) = GA.height(v) = 5.0;
FMMMLayout fmmm;
fmmm.useHighLevelOptions(true);
fmmm.unitEdgeLength(15.0);
fmmm.newInitialPlacement(true);
fmmm.qualityVersusSpeed(FMMMOptions::QualityVsSpeed::GorgeousAndEfficient);
fmmm.call(GA);
GraphIO::write(GA, "output-energybased-sierpinski-layout.gml", GraphIO::writeGML);
GraphIO::write(GA, "output-energybased-sierpinski-layout.svg", GraphIO::drawSVG);
return 0;
}
Declaration of Fast Multipole Multilevel Method (FM^3).
The fast multipole multilevel layout algorithm.
Definition FMMMLayout.h:232
FMMMOptions::QualityVsSpeed qualityVersusSpeed() const
Returns the current setting of option qualityVersusSpeed.
Definition FMMMLayout.h:361
double unitEdgeLength() const
Returns the current setting of option unitEdgeLength.
Definition FMMMLayout.h:337
bool useHighLevelOptions() const
Returns the current setting of option useHighLevelOptions.
Definition FMMMLayout.h:319
virtual void call(GraphAttributes &GA) override
Calls the algorithm for graph GA and returns the layout information in GA.
bool newInitialPlacement() const
Returns the current setting of option newInitialPlacement.
Definition FMMMLayout.h:351

Step-by-step explanation

  1. An important thing to note here is that after loading the graph from a file we can access node width and height without explicitly enabling ogdf::GraphAttributes::nodeGraphics in GA. This is because ogdf::GraphAttributes::nodeGraphics and ogdf::GraphAttributes::edgeGraphics are enabled by default.
  2. ogdf::FMMMLayout can be configured in two ways: using high-level options (recommended) or low-level options (requires good knowledge of the algorithm). For this example we will use the few high-level options ogdf::FMMMLayout provides and thus set the respective flag to true before actually setting anything.
  3. We then set the unit edge length (a scaling factor if you will), enable initial replacing of nodes and choose one of the available options from ogdf::FMMMOptions::QualityVsSpeed to tune tradeoffs between speed and aesthetic of the resulting graph. The only remaining high-level option is ogdf::FMMMOptions::PageFormatType which defaults to a Square if not explicitly set. These high-level options will then be used to derive the low-level settings accordingly.
  4. After calling the algorithm on our read graph instance the same instance augmented by the node positions in the resulting graph layout is written back out to a .gml and a .svg file.

Orthogonal layout

This example shows how to layout a graph so that all edges propagate only parallel to the x- or y-axis meaning any edge bends have an angle of 90°. This is called an orthogonal drawing.

using namespace ogdf;
int main()
{
Graph G;
GraphAttributes::nodeGraphics | GraphAttributes::nodeType |
GraphAttributes::edgeGraphics | GraphAttributes::edgeType);
if (!GraphIO::read(GA, G, "ERDiagram.gml", GraphIO::readGML)) {
std::cerr << "Could not read ERDiagram.gml" << std::endl;
return 1;
}
for (node v : G.nodes)
{
GA.width(v) /= 2;
GA.height(v) /= 2;
}
ps->runs(100);
ves->removeReinsert(RemoveReinsertType::All);
crossMin->setSubgraph(ps);
crossMin->setInserter(ves);
pl.setCrossMin(crossMin);
pl.setEmbedder(emb);
ol->separation(20.0);
ol->cOverhang(0.4);
pl.setPlanarLayouter(ol);
pl.call(GA);
GraphIO::write(GA, "output-ERDiagram.gml", GraphIO::writeGML);
GraphIO::write(GA, "output-ERDiagram.svg", GraphIO::drawSVG);
return 0;
}
Declares ogdf::EmbedderMinDepthMaxFaceLayers.
Declaration of class OrthoLayout which represents an orthogonal planar drawing algorithm.
Declaration of the PlanarSubgraphFast.
Declaration of class PlanarizationLayout.
Declaration of class SubgraphPlanarizer.
Declaration of class VariablEmbeddingInserter.
Planar graph embedding that minimizes block-nesting depth and maximizes the external face and optimiz...
The Orthogonal layout algorithm for planar graphs.
Definition OrthoLayout.h:41
double separation() const override
Returns the minimum distance between edges and vertices.
Definition OrthoLayout.h:68
Computation of a planar subgraph using PQ-trees.
void runs(int nRuns)
Sets the number of randomized runs to nRuns.
The planarization approach for drawing graphs.
The planarization approach for crossing minimization.
void removeReinsert(RemoveReinsertType rrOption)
Sets the remove-reinsert postprocessing method.
Optimal edge insertion module.

Step-by-step explanation

  1. Here, we use ogdf::PlanarizationLayout as our base layout algorithm, again configuring it to our needs by passing dynamically allocated module instances.
  2. The first module we specify is the ogdf::CrossingMinimizationModule for which we choose ogdf::SubgraphPlanarizer. It works in two core phases, the former will compute a planar subgraph while the latter then reinserts the remaining edges while trying to minimize the resulting crossings. We alter its default configuration by setting the number of randomized reruns for planar subgraph computation and making it consider all edges in the postprocessing step during edge reinsertion.
  3. The next submodule we configure is ogdf::EmbedderModule for which we use a default instance of ogdf::EmbedderMinDepthMaxFaceLayers.
  4. The final module supplied to pl is ogdf::LayoutPlanRepModule. We use ogdf::OrthoLayout to achieve the main feature we wanted to achieve from the beginning and configure the minimum allowed distance between edges and vertices (and their corners).
  5. As always, after calling the composed algorithm on the graph instance the result is once again written to out to .gml and .svg files.

Hypergraph layout

This example shows the interface for IO and layout of hypergraphs. There are only few algorithms for hypergraphs in the OGDF.

using namespace ogdf;
int main()
{
H.readBenchHypergraph("c17.bench");
HypergraphAttributesES HA(H, EdgeStandardType::tree);
hlES.setProfile(HypergraphLayoutES::Profile::Normal);
hlES.call(HA);
GraphIO::write(HA.repGA(), "output-c17.gml", GraphIO::writeGML);
GraphIO::write(HA.repGA(), "output-c17.svg", GraphIO::drawSVG);
return 0;
}
Layout algorithms for hypergraph based on edge standard representations (clique / star / tree) - Hype...
Stores additional attributes of edge standard representation of a hypergraph.
void setProfile(Profile pProfile)
Sets the layout profile.

Step-by-step explanation

  1. While ogdf::Hypergraph is the direct analogon to ogdf::Graph, ogdf::HypergraphAttributesES is the analogon of ogdf::GraphAttributes for edge-standard representation.
  2. The input file is read via a dedicated hypergraph reader function ogdf::Hypergraph::readBenchHypergraph.
  3. The hypergraph attributes get initialized and the option ogdf::EdgeStandardType that governs the internal representation of hyperedges is set to a tree representation. Note that only ogdf::EdgeStandardType::star and ogdf::EdgeStandardType::tree will insert dummy nodes which might be useful (as in this example) to generate a representation of the hypergraph using the standard ogdf::Graph and ogdf::GraphAttributes interfaces.
  4. The base layout algorithm ogdf::HypergraphLayoutES that is then used has basically the same interface for modular configuring as the standard graph layout algorithms but on top of that it also has an option to choose between the general profiles ogdf::HypergraphLayoutES::Profile::Normal and ogdf::HypergraphLayoutES::Profile::ElectricCircuit.
  5. After calling the layout algorithm on our hypergraph instance we can access the ogdf::GraphAttributes component of hlES as the internal representation works on a wrapped instance of ogdf::GraphAttributes with some dummy nodes added anyways. This is especially useful for using the standard ogdf::GraphIO interface to output a reduced representation of the resulting hypergraph layout.

Multilevel layout mixer

This example shows the use of the modular multilevel mixer class that can be used to build energybased multilevel layouts. Since it is modular one can easily assemble different layouts by using different coarsening techniques (merger), placer and single level layouts. As this example is quite exhaustive explanation is provided in place as inline comments.

// Introduction for Multilevelmixer:
//
// Multilevel layout computation is an iterative process that can
// be roughly divided in three phases: coarsening, placement, and
// single level layout. Starting with the smallest graph, the final
// layout for the input graph is obtained by successively computing
// layouts for the graph sequence computed by the coarsening phase.
// At each level, the additional vertices need to be placed into the
// layout of the preceding level, optionally after a scaling to provide
// the necessary space.
// It helps to overcome some problems of single level energybased graph
// layouts (such as finding a local optimal solution) and it speeds up
// the computation.
//
// The Modular Multilevel Mixer is an abstract class that can be used
// to build energybased multilevel layouts. Since it is modular you can
// easily assemble different layouts by using different coarsening
// techniques (merger), placer and single level layouts.
using namespace ogdf;
template<class T>
{
T *merger = new T();
merger->setFactor(2.0);
merger->setEdgeLengthAdjustment(0);
return merger;
}
{
placer->weightedPositionPriority(true);
return placer;
}
{
// The SolarMerger is used for the coarsening phase.
merger = new SolarMerger(false, false);
// The SolarPlacer is used for the placement.
// Postprocessing is applied at each level after the single level layout.
// It is turned off in this example.
sl->setExtraScalingSteps(0);
// In this example it is used to scale with fixed factor 2 relative to the graph drawing.
sl->setScalingType(ScalingLayout::ScalingType::RelativeToDrawing);
sl->setScaling(2.0, 2.0);
}
{
// The EdgeCoverMerger is used for the coarsening phase.
// The BarycenterPlacer is used for the placement.
// Postprocessing is applied at each level after the single level layout.
// In this example a FastMultipoleEmbedder with zero iterations is used for postprocessing.
sl->setExtraScalingSteps(0);
// No scaling is done. It is fixed to factor 1.
sl->setScalingType(ScalingLayout::ScalingType::RelativeToDrawing);
sl->setScaling(1.0, 1.0);
}
{
// The LocalBiconnectedMerger is used for the coarsening phase.
// It tries to keep biconnectivity to avoid twisted graph layouts.
// The BarycenterPlacer is used for the placement.
// Postprocessing is applied at each level after the single level layout.
// It is turned off in this example.
sl->setExtraScalingSteps(1);
// The ScalingLayout is used to scale with a factor between 5 and 10
// relative to the edge length.
sl->setScalingType(ScalingLayout::ScalingType::RelativeToDesiredLength);
sl->setScaling(5.0, 10.0);
}
int main(int argc, const char *argv[])
{
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " (0|1|2)" << std::endl;
return 255;
}
// We first declare a Graph G with GraphAttributes GA and load it from
// the GML file sierpinski_04.gml.
Graph g;
if (!GraphIO::read(ga, g, "uk_Pack_Bary_EC_FRENC.gml", GraphIO::readGML)) {
std::cerr << "Could not load Graph" << std::endl;
return 1;
}
// We assign a width and height of 10.0 to each node.
for (node v : g.nodes) {
ga.width(v) = ga.height(v) = 10.0;
}
// Then we create a MultilevelGraph from the GraphAttributes.
// The FastMultipoleEmbedder is used for the single level layout.
// It will use 1000 iterations at each level.
fme->setNumIterations(1000);
fme->setRandomize(false);
// To minimize dispersion of the graph when more nodes are added, a
// ScalingLayout can be used to scale up the graph on each level.
sl->setLayoutRepeats(1);
// The FastMultipoleEmbedder is nested into this ScalingLayout.
sl->setSecondaryLayout(fme);
// Set the merger and placer according to the wanted configuration.
switch (argv[1][0]) {
case 2:
break;
case 1:
break;
default:
break;
}
// Then the ModularMultilevelMixer is created.
// The single level layout, the placer and the merger are set.
mmm->setLevelLayoutModule(sl);
mmm->setInitialPlacer(placer);
mmm->setMultilevelBuilder(merger);
// Since energybased algorithms are not doing well for disconnected
// graphs, the ComponentSplitterLayout is used to split the graph and
// computation is done separately for each connected component.
// The TileToRowsPacker merges these connected components after computation.
csl->setPacker(ttrccp);
csl->setLayoutModule(mmm);
// At last the PreprocessorLayout removes double edges and loops.
ppl.setRandomizePositions(true);
ppl.call(mlg);
// After the computation the MultilevelGraph is exported to the
// GraphAttributes and written to disk.
mlg.exportAttributes(ga);
GraphIO::write(ga, "output-multilevelmixer-" + std::string(argv[1]) + ".gml", GraphIO::writeGML);
GraphIO::write(ga, "output-multilevelmixer-" + std::string(argv[1]) + ".svg", GraphIO::drawSVG);
return 0;
}
Places nodes at the barycenter of his neighbors.
Splits and packs the components of a Graph.
Merges nodes with neighbour to get a Multilevel Graph.
Declaration of Fast-Multipole-Embedder layout algorithm.
Merges nodes with neighbour to get a Multilevel Graph.
MMM is a Multilevel Graph drawing Algorithm that can use different modules.
Preprocessor Layout simplifies Graphs for use in other Algorithms.
ScalingLayout scales and calls a secondary layout.
Merges nodes with solar system rules.
Places Nodes with solar system rules.
Declaration of class TileToRowsCCPacker.
The barycenter placer for multilevel layout.
The fast multipole embedder approach for force-directed layout.
Base class for placer modules.
Modular multilevel graph layout.
void setLayoutRepeats(int times=1)
Determines how many times the one-level layout will be called.
Base class for merger modules.
The PreprocessorLayout removes multi-edges and self-loops.
void setLayoutModule(LayoutModule *layout)
Sets the secondary layout.
Scales a graph layout and calls a secondary layout algorithm.
The solar merger for multilevel layout.
Definition SolarMerger.h:42
The solar placer for multilevel layout.
Definition SolarPlacer.h:42
The tile-to-rows algorithm for packing drawings of connected components.
static void configureFastLayout(ScalingLayout *sl, MultilevelBuilder *&merger, InitialPlacer *&placer)
static void configureNiceLayout(ScalingLayout *sl, MultilevelBuilder *&merger, InitialPlacer *&placer)
static void configureNoTwistLayout(ScalingLayout *sl, MultilevelBuilder *&merger, InitialPlacer *&placer)
static InitialPlacer * getBarycenterPlacer()