Damit eine Graphviz-Hierarchie auf Ihrem Mac wie eine eingerückte Gliederung lesbar ist, weisen Sie jedem Knoten eine Zeile und eine Einrückungskoordinate zu und rendern Sie anschließend mit neato -n2. So bleiben die Eltern-Kind-Kanten erhalten, während Sie die Lesereihenfolge steuern können.

Diese Anleitung erstellt ein Beispiel mit sechs Knoten und exportiert es als PDF. Das Ziel ist genau festgelegt: ein Knoten pro Zeile, Nachfahren unmittelbar unter ihrem Elternknoten und dieselbe Einrückung für Knoten derselben Tiefe. Graphviz dokumentiert das Rendern mit festen Positionen über seine Befehlszeilenoption -n.

Warum sieht ein normaler Graphviz-Baum nicht wie eine Gliederung aus?

Eine Hierarchie beschreibt Beziehungen; eine eingerückte Gliederung legt zusätzlich eine Lesereihenfolge fest. In diesem Beispiel enthält die Wurzel zwei Zweige, und die Nachfahren des ersten Zweigs müssen vor dem zweiten Zweig erscheinen. Die gewünschte Reihenfolge lautet:

Knoten R
    Knoten A
        Knoten C
        Knoten D
    Knoten B
        Knoten E

Die Beziehungen im Graphen sind Wurzel zu A, Wurzel zu B, A zu C, A zu D und B zu E. Es besteht keine Beziehung von D zu B, nur weil B in der nächsten Zeile steht. DOT drückt gerichtete Kanten mit dem Operator -> aus; Knotendeklarationen und ihre Darstellungsattribute sind separate Bestandteile der Sprache. Siehe die offizielle DOT-Sprachreferenz.

Die Graphviz-Engine dot erzeugt hierarchische oder geschichtete Zeichnungen. Sie richtet Kanten in eine gemeinsame Richtung aus und versucht dabei, Kreuzungen und Kantenlängen zu reduzieren. Dieses Ziel eignet sich für ein verzweigtes Diagramm, legt aber nicht die oben gezeigte Gliederung mit einer Zeile pro Knoten fest. Siehe die Dokumentation zum Layout mit dot.

Mehrere bekannte Attribute lösen jeweils nur einen Teil des Problems:

Einstellung Dokumentierter Zweck Was weiterhin offenbleibt
rankdir=LR Ändert die Layoutrichtung von oben nach unten zu links nach rechts Legt keine vertikale Reihenfolge der Gliederung fest
rank=same Ordnet die Knoten eines Teilgraphen auf derselben Rangstufe an Weist nicht jedem Knoten eine eigene Gliederungszeile zu
ordering=out Beschränkt ausgehende Kanten darauf, in der Eingabereihenfolge von links nach rechts zu erscheinen Legt keine Einrückung nach Tiefe und keine Zeilenkoordinaten fest

Diese Abgrenzungen ergeben sich aus den offiziellen Referenzen zu rankdir, rank und ordering. Für die genaue Zeilenanordnung in diesem Artikel bieten explizite Koordinaten eine direktere Konstruktion, als diese Attribute zu kombinieren.

Wie richten Sie Graphviz auf einem Mac ein?

Öffnen Sie Terminal. Wenn Sie Homebrew bereits verwenden, installieren Sie Graphviz mit dem folgenden Befehl. Auf der offiziellen Graphviz-Downloadseite ist diese Installationsmethode für den Mac aufgeführt:

brew install graphviz

Wenn Sie stattdessen MacPorts verwenden, ist auf derselben Downloadseite sudo port install graphviz aufgeführt. Verwenden Sie den Paketmanager, den Sie bereits einsetzen. Falls keiner der beiden installiert ist, folgen Sie zunächst dem passenden Installationslink auf dieser Seite und kehren Sie dann zu dieser Anleitung zurück.

Prüfen Sie, ob der Renderer verfügbar ist:

neato -V

Die Option -V gibt Versionsinformationen zu Graphviz aus. Notieren Sie die angezeigte Version, wenn Sie Ergebnisse auf verschiedenen Computern vergleichen; Sie benötigen keine bestimmte Versionsnummer, die in diesem Artikel genannt wird. Graphviz dokumentiert diese Option in seiner Befehlszeilenreferenz.

Wie erstellen Sie die eingerückte Hierarchie?

Der folgende vollständige Shell-Block erstellt einen neuen Arbeitsordner und schreibt die DOT-Datei dort hinein. Führen Sie ihn in Terminal aus; nach Abschluss wird der Ordnerpfad ausgegeben. Der zitierte Here-Doc-Begrenzer sorgt dafür, dass der DOT-Text unverändert übernommen wird.

outline_dir=$(mktemp -d "$HOME/graphviz-outline.XXXXXX")
if [ -n "$outline_dir" ] && cd "$outline_dir"; then
  cat > hierarchy.dot <<'DOT'
digraph Hierarchy {
  graph [splines=ortho, bgcolor=white];
  node [
    shape=box,
    width=1.2,
    height=0.35,
    fixedsize=true,
    fontname="Courier",
    fontsize=12
  ];

  r [label="Node R", pos="100,300"];
  a [label="Node A", pos="136,252"];
  c [label="Node C", pos="172,204"];
  d [label="Node D", pos="172,156"];
  b [label="Node B", pos="136,108"];
  e [label="Node E", pos="172,60"];

  r -> a;
  r -> b;
  a -> c;
  a -> d;
  b -> e;
}
DOT
  pwd
fi

Die Knotenpositionen bilden die Gliederung ab. Jede folgende Zeile rückt um 48 Punkte nach unten, und jede zusätzliche Tiefenstufe um 36 Punkte nach rechts. Diese Werte dienen als Beispiel für Abstände und sind keine Graphviz-Standardwerte. In der Dokumentation zu pos ist festgelegt, dass sich Knotenpositionen auf die Knotenmittelpunkte beziehen und neato Positionen in Verbindung mit -n als Punkte interpretiert.

Knoten Tiefe Zeile, beginnend bei null Mittelpunktposition
Knoten R 0 0 100,300
Knoten A 1 1 136,252
Knoten C 2 2 172,204
Knoten D 2 3 172,156
Knoten B 1 4 136,108
Knoten E 2 5 172,60

Für diese Konstruktion lauten die Koordinatenregeln x = 100 + 36 × depth und y = 300 − 48 × row. Beachten Sie den Wechsel von Knoten D zu Knoten B: Die Zeile rückt weiter, aber die Tiefe nimmt ab. Genau dieser Übergang lässt die Zeichnung wie eine Gliederung statt wie eine Kette wirken.

Alle Kästen haben dieselben Abmessungen, sodass identische Mittelpunktkoordinaten auch ihre linken Kanten ausrichten. Die synthetischen Beschriftungen gleicher Länge erleichtern den Vergleich der Textpositionen. Mit fixedsize=true verwendet Graphviz die angegebenen Knotengrößen, statt die Kästen an ihren Inhalt anzupassen; zu große Beschriftungen lösen eine Warnung aus. Siehe die Referenz zu fixedsize.

Wie rendern und prüfen Sie das Ergebnis?

Führen Sie in derselben Terminal-Sitzung und im selben Arbeitsordner Folgendes aus:

neato -n2 -Tpdf hierarchy.dot -o hierarchy.pdf

Hier übernimmt -n2 die vorgegebene Knotenanordnung ohne Überlappungskorrektur und berechnet Routen für Kanten, deren Positionen nicht separat festgelegt wurden. Daher benötigt jeder Knoten einen Wert für pos. Die Optionen -Tpdf und -o legen das PDF-Format und den Zielpfad fest. Diese Funktionen sind in der Befehlszeilenreferenz dokumentiert.

Öffnen Sie den Arbeitsordner im Finder und öffnen Sie hierarchy.pdf. Für die PDF-Ausgabe ist eine Graphviz-Version erforderlich, die den Cairo-Renderer enthält, wie auf der PDF-Ausgabeseite von Graphviz angegeben. Das Beispiel wurde anhand der Dokumentation geprüft, aber hier nicht durch Rendern getestet, da Graphviz in der Rechercheumgebung nicht verfügbar war.

Prüfen Sie drei Dinge getrennt:

  1. Lesen Sie von oben nach unten: R, A, C, D, B und E sollten auf aufeinanderfolgenden Zeilen stehen.
  2. Vergleichen Sie die Einrückung: A und B sollten bündig stehen; C, D und E sollten einen Schritt weiter rechts ausgerichtet sein.
  3. Verfolgen Sie die Beziehungen: R ist mit A und B verbunden; A ist mit C und D verbunden; B ist mit E verbunden.

Mit den ersten beiden Prüfungen kontrollieren Sie die Koordinatenkonstruktion. Die dritte prüft den Graphen selbst. Wenn Sie diese Prüfungen getrennt durchführen, erkennen Sie leichter ein Diagramm, das zwar ordentlich aussieht, aber eine falsche Eltern-Kind-Kante enthält.

Sehen die Verbindungslinien genau wie die Baumstruktur eines Dateibrowsers aus?

Die Knotenreihen und Einrückungen sind explizit festgelegt; die Pfade der Verbindungslinien werden weiterhin berechnet. Im Beispiel wird splines=ortho angefordert, wodurch Kanten über rechtwinklige Segmente verlaufen. Laut Graphviz-Dokumentation unterstützt diese Routenführung auch keine Ports; Kompass-Ports sind also keine dokumentierte Methode, um ein bestimmtes Knickmuster zu erzwingen. Siehe die Referenz zu splines.

Diese Konstruktion bietet daher eine eingerückte Hierarchie mit automatisch gerouteten rechtwinkligen Verbindungslinien. Sie legt keine einzelne gemeinsame vertikale Führungslinie mit exakt platzierten Verzweigungspunkten fest. Wenn diese Geometrie der Verbindungslinien erforderlich ist, braucht es eine zusätzliche Konstruktion mit explizit angegebenen Kantenpfaden; splines=ortho allein drückt diese Anforderung nicht aus.

Für eine übersichtliche Gliederung ohne sichtbare Verbindungslinien ändern Sie die Grapheinstellung in splines=none und rendern Sie erneut. Die DOT-Datei enthält weiterhin ihre Eltern-Kind-Kanten, während der Renderer sie nicht zeichnet. Dies ist eine dokumentierte Rendering-Option in derselben Referenz zu splines.

Wie passen Sie das Beispiel an, ohne seine Bedeutung zu ändern?

Schreiben Sie zunächst die gewünschte Lesereihenfolge unabhängig von der Kantenliste auf. Gehen Sie zuerst den Elternknoten durch, dann dessen erstes Kind und die Nachfahren dieses Kindes, bevor Sie zum nächsten Kind wechseln. Weisen Sie jedem Knoten dieser Reihenfolge eine Zeile zu. Legen Sie anschließend die Einrückung anhand der Tiefe fest.

Um beispielsweise nach Knoten D ein weiteres Kind unter Knoten A hinzuzufügen, setzen Sie es in der Lesereihenfolge vor Knoten B. Geben Sie ihm Tiefe zwei, verschieben Sie die folgenden Zeilen nach unten und fügen Sie eine Kante von A zum neuen Knoten hinzu. Die bestehenden Elternbeziehungen ändern sich nicht allein dadurch, dass sich ihre Zeilennummern ändern.

Verwenden Sie die folgende Diagnoseabfolge, wenn eine bearbeitete Version falsch aussieht:

  • Die Zeichnung breitet sich in einer anderen Anordnung aus: Prüfen Sie, ob der Befehl weiterhin neato -n2 verwendet. Das Beispiel beruht auf vorgegebenen Positionen und nicht auf einem gewöhnlichen automatischen Layout.
  • Beim Rendern wird eine fehlende Position gemeldet: Prüfen Sie alle Knoten-IDs, einschließlich der IDs, die nur in Kantenaussagen vorkommen. Für diesen Arbeitsablauf benötigt jeder Knoten eine Positionsdeklaration.
  • Eine Beschriftung ragt über ihren Kasten hinaus: Vergrößern Sie die einheitlichen Kastenabmessungen oder kürzen Sie die Beschriftung. Kästen mit fester Größe werden nicht automatisch vergrößert.
  • Nach einer Vergrößerung der Kästen überlappen sich die Zeilen: Vergrößern Sie den Zeilenabstand. Der gewählte Rendermodus behält die Positionen bei, statt Überlappungen zu korrigieren.
  • Ein Zweig ist mit dem falschen Knoten verbunden: Korrigieren Sie die Kantenaussage. Eine Verschiebung des Kastens kann eine falsche Beziehung nicht beheben.

Die Bedingungen für fehlende Positionen und Überlappungen ergeben sich aus Graphvizs dokumentiertem -n2-Verhalten; die Bedingung für Beschriftungen aus dem dokumentierten Verhalten von fixedsize. Für dieses manuell positionierte Beispiel ist eine Vergrößerung der Abstände die entsprechende gestalterische Anpassung.

Verwenden Sie die Kantenliste der Hierarchie als Quelle der Beziehungen und die Koordinatentabelle als Quelle der Darstellung. Bei einem kleinen Diagramm auf dem Mac lässt sich das Ergebnis so einfach pflegen: Ändern Sie die Kanten, wenn sich die Hierarchie ändert, die Zeilen, wenn sich die Lesereihenfolge ändert, und die Abstände, wenn die Beschriftungen mehr Platz brauchen.

Quellen