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.
{
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;
}
ohl->weightBalancing(0.8);
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 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).
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).
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.
Step-by-step explanation
- 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.
- 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
- A ranking module that will determine the layering of the graph
- A module that handles the minimization of two-layer crossing
- The main module that computes the actual graph layout
- 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.
- 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.
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
};
{
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;
}
int i = 0;
ohl->weightBalancing(0.7);
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.
Class for the representation of nodes.
void setCrossMin(LayeredCrossMinModule *pCrossMin)
Sets the module option for the two-layer crossing minimization.
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.
{
if (!GraphIO::read(G, "sierpinski_04.gml")) {
std::cerr << "Could not load sierpinski_04.gml" << std::endl;
return 1;
}
GA.width(v) =
GA.height(v) = 5.0;
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.
FMMMOptions::QualityVsSpeed qualityVersusSpeed() const
Returns the current setting of option qualityVersusSpeed.
double unitEdgeLength() const
Returns the current setting of option unitEdgeLength.
bool useHighLevelOptions() const
Returns the current setting of option useHighLevelOptions.
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.
Step-by-step explanation
- 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.
- 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.
- 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.
- 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.
{
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;
}
{
}
pl.setPlanarLayouter(
ol);
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.
double separation() const override
Returns the minimum distance between edges and vertices.
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
- Here, we use ogdf::PlanarizationLayout as our base layout algorithm, again configuring it to our needs by passing dynamically allocated module instances.
- 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.
- The next submodule we configure is ogdf::EmbedderModule for which we use a default instance of ogdf::EmbedderMinDepthMaxFaceLayers.
- 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).
- 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.
{
H.readBenchHypergraph("c17.bench");
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
- While ogdf::Hypergraph is the direct analogon to ogdf::Graph, ogdf::HypergraphAttributesES is the analogon of ogdf::GraphAttributes for edge-standard representation.
- The input file is read via a dedicated hypergraph reader function ogdf::Hypergraph::readBenchHypergraph.
- 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.
- 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.
- 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.
template<class T>
{
merger->setEdgeLengthAdjustment(0);
}
{
placer->weightedPositionPriority(
true);
}
{
sl->setExtraScalingSteps(0);
sl->setScalingType(ScalingLayout::ScalingType::RelativeToDrawing);
sl->setScaling(2.0, 2.0);
}
{
sl->setExtraScalingSteps(0);
sl->setScalingType(ScalingLayout::ScalingType::RelativeToDrawing);
sl->setScaling(1.0, 1.0);
}
{
sl->setExtraScalingSteps(1);
sl->setScalingType(ScalingLayout::ScalingType::RelativeToDesiredLength);
sl->setScaling(5.0, 10.0);
}
{
std::cout <<
"Usage: " <<
argv[0] <<
" (0|1|2)" << std::endl;
return 255;
}
if (!GraphIO::read(ga, g, "uk_Pack_Bary_EC_FRENC.gml", GraphIO::readGML)) {
std::cerr << "Could not load Graph" << std::endl;
return 1;
}
ga.width(v) = ga.height(v) = 10.0;
}
fme->setNumIterations(1000);
fme->setRandomize(
false);
sl->setSecondaryLayout(
fme);
case 2:
break;
case 1:
break;
default:
break;
}
mmm->setLevelLayoutModule(
sl);
ppl.setRandomizePositions(
true);
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.
The solar placer for multilevel layout.
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()