Mit Graphviz komplexe Strukturen veranschaulichen
Richtig ausgerichtet
Graphviz-Serie
Michael Niedermair: "Richtig arrangiert" | LU 01/2014, S. 46 | http://www.linux-community.de/28542 |
Michael Niedermair: "Dot2tex" | LU 06/2014, S. XXX | http://www.linux-community.de/28543 |
In der Open-Source-Landschaft ist das Programm Graphviz [1] seit Längerem fest verankert (siehe Kasten "Aus den Bell Labs"). Vielfach leistet es unbemerkt im Hintergrund seine Dienste, etwa beim automatischen Erstellen von Abbildungen auf einem Webserver über ein Skript aus einer Datenbank heraus.
Aus den Bell Labs
Die plattformübergreifende Visualisierungssoftware Graphviz stammt ursprünglich von AT&T und den Bell Labs. Die Software existiert seit 1988, steht unter der Eclipse Public License (EPL) [2] und läuft unter den Betriebssystemen Linux, Solaris, Windows und Mac OS X. Für alle Distributionen stehen stabile Pakete bereit.
Die Markdown-Sprache Asciidoc [3] bietet die Möglichkeit, Graphviz-Daten direkt einzubetten – der Compiler übersetzt diese Abschnitte automatisch in entsprechende Grafiken. Für Doxygen [4] und diverse Wiki-Plattformen stehen passende Plugins bereit. Ebenso kommt Graphviz in Puppet [5] zum Einsatz – hier zum Erzeugen von Ressourcen-Graphen.
Beim Verarbeiten gerichteter und ungerichteter Graphen (siehe Kasten "Graphen-Typen") helfen die Kommandozeilenwerkzeuge dot
, neato
, fdp
, circo
und twopi
. Sie alle gehören zum Graphviz-Paket und setzen jeweils spezifische Algorithmen aus der Graphentheorie zur Reduktion von Kantenlängen, Separierung von Teilgraphen und Erkennen von Zusammenhangskomponenten [6] um.
Graphen-Typen
Ein Graph besteht aus einer Menge von Knoten und Kanten, wobei eine Kante stets zwei Knoten miteinander verbindet. Es gibt zwei Typen von Graphen: ungerichtet und gerichtet. Bei einem ungerichteten Graphen weisen die Kanten keine Angabe zur Richtung auf. Bei gerichteten Graphen dagegen verfügen alle Kanten über eine solche. Diese gibt die Leserichtung vor, ähnlich einer Einbahnstraße.
Arbeitsablauf
Zunächst erzeugen Sie mit einem Texteditor eine Beschreibung der Elemente und deren Abhängigkeiten untereinander und speichern diese als Textdatei ab. Im nächsten Schritt steht das Übersetzen der Datei mit einem der genannten Tools in ein Ausgabeformat an (GIF, PNG, SVG, PDF, Postscript). Der folgende Befehl erzeugt aus graph.dot
eine Abbildung im PNG-Format:
$ dot -Tpng graph.dot -o graph.png
Der Aufbau der Dot-Datei gestaltet sich recht einfach: Zunächst definieren Sie einen Graphen (Listing 1, Zeile 1). Mit dem Schlüsselwort digraph
beginnt ein gerichteter Graph, auf Englisch abgekürzt für "directed graph". Vergessen Sie keinesfalls die öffnende, geschweifte Klammer nach dem Schlüsselwort.
In den darauffolgenden Zeilen spezifizieren Sie die drei Knoten A, B und C mit entsprechenden Attributen zum Gestalten der Knoten und Kanten. Jede Zeile schließen Sie am Ende mit einem Semikolon ab. Als Name eines Knotens verwenden Sie entweder einen Bezeichner, wie er in der Programmiersprache C zulässig ist, oder eine Zahl beziehungsweise eine in Anführungszeichen eingeschlossene Zeichenkette. Leer-, Steuer- und sonstige Satzzeichen respektiert Dot ebenfalls. Mehrzeilige Beschriftungen erzeugen Sie mittels \n
für einen Zeilenumbruch. Die Beschriftung erscheint dann mittig.
Der Operator ->
erzeugt eine Kante zwischen zwei Punkten in der entsprechenden Richtung. In Zeile 6 schließen Sie die Definition des Graphen mit einer geschweiften Klammer ab. Mit der Vergabe von Attributen steuern Sie das Aussehen des Graphen. Die Attribute geben Sie in eckigen Klammern an. Das ist entweder als allgemeine Anweisung für alle nachfolgenden Elemente möglich oder nur explizit für einzelne Knoten. Letzteres zeigen die Zeilen 2 und 3 in Listing 1.
Listing 1
digraph G { A -> B [style=dotted]; A -> C [color=red, label="Beschriftung"]; C [shape=box, style=filled, color="0.7 0.7 0.0"]; B -> C; }
Des Weiteren definiert Zeile 2 eine gepunktete Linie, Zeile 3 stattdessen eine rot gefärbte Linie mit einer Beschriftung der Kante. Dazu verwenden Sie das Attribut label
, gefolgt von einem Gleichheitszeichen und dem Inhalt in Anführungszeichen. In Zeile 4 legen Sie für den Knoten C einen eckigen Rahmen fest, dessen Inhalt eine blaue Farbe erhält. Den genauen Farbwert setzen Sie aus den Rot-, Grün- und Blau-Anteilen zusammen. Abbildung 1 zeigt den Quellcode und das Ergebnis im Bildbetrachter.
In der praktischen Arbeit mit dem Rechner eignet sich Graphviz unter anderem dazu, Verzeichnishierarchien zu visualisieren. Ein ungerichteter Graph zeigt in einer Baumstruktur, wo sich möglicherweise unerwünscht Ordner angesammelt haben. Das Programm bietet mit der Option folder
für die Ausgabe der Knoten kleine Symbole an, deren Aussehen sich an jenes von Ordnern im Dateimanager anlehnt (Listing 2).
Listing 2
graph { "/" [shape=folder]; "/boot" [shape=folder]; "/usr" [shape=folder]; "/home" [shape=folder]; "/var" [shape=folder]; "/frank" [shape=folder]; "/peter" [shape=folder]; "/" -- "/boot"; "/" -- "/usr"; "/" -- "/home"; "/" -- "/var"; "/home" -- "/frank"; "/home" -- "/peter"; }
Diese Datei übersetzen Sie analog zum vorher gezeigten Beispiel. Abbildung 2 präsentiert die erzeugte Grafik. Nutzen Sie eines der anderen Werkzeuge, übersetzen diese obige Beschreibung zwar anstandslos, ordnen die Objekte aber kreisförmig an, was der gewohnten Sicht auf ein Dateisystem entgegensteht.
Mit etwas Geschick ließe sich die Dot-Datei aus einem Skript heraus erzeugen. Auf diese Weise würden Sie sich automatisiert einen Überblick über einen Zweig des Dateisystems verschaffen.
Binärer Baum
Bäume bestehen als Datenstrukturen aus Knoten und Kanten, wobei die Wurzel den oberste Knoten bildet. Binäre Bäume verfügen über zwei Sorten von Knoten – äußere (ohne Nachfolger) und innere (mit genau zwei Nachfolgern). Das vorrangige Einsatzgebiet solcher Binärbäume stellt das Strukturieren und die möglichst effiziente Suche in sortierten Datenmengen dar.
Graphviz nimmt Ihnen beim Umgang mit solchen Graphen Arbeit ab, wenn Sie das Programm richtig nutzen. Listing 3 zeigt, wie Sie einen solchen binären Baum mit der Software erstellen. Nachdem Sie zunächst in Zeile 2 das Aussehen aller Knoten als Rechteck festgelegt haben, definieren Sie in den Zeilen 4 bis 8 die Struktur und die Inhalte der Knoten.
Listing 3
digraph G { node [shape=record, height=0.1]; knoten0 [label = "<l> | <m> H | <r>"]; knoten1 [label = "<l> | <m> D | <r>"]; knoten2 [label = "<l> | <m> A | <r>"]; knoten3 [label = "<l> | <m> P | <r>"]; knoten4 [label = "<l> | <m> W | <r>"]; knoten0:l -> knoten1:m; knoten1:l -> knoten2:m; knoten0:r -> knoten3:m; knoten1:r -> knoten4:m; }
Jeder Knoten verfügt über drei Elemente: Einen Verweis auf den nachfolgenden, linken Knoten (benannt mit l), ein mittleres Datenfeld mit Inhalt (benannt mit m) sowie einen Verweis auf den nachfolgenden, rechten Knoten (benannt mit r). Auf die einzelnen Elemente greifen Sie später über deren Namen zu.
In Zeile 10 verknüpfen Sie das linke Element von knoten0
mit dem mittleren Element von knoten1
. Die anderen Knoten binden Sie in ähnlicher Weise ein. Das gewünschte Element des jeweiligen Knotens adressieren Sie über den Namen des Elements, durch einen Doppelpunkt separiert vom Namen des Knotens. Damit bestimmen Sie die Position, auf die der Pfeil zeigt. Das nachfolgende Übersetzen erzeugt die gewünschten Kästchen und Linien (Abbildung 3).