Become a member!

Graphviz DOT-Sprache: der Praxisleitfaden, den dir die offizielle Doku nicht gibt

🌐
Dieser Artikel ist auch in anderen Sprachen verfügbar:
🇬🇧 English  •  🇮🇹 Italiano  •  🇪🇸 Español  •  🇧🇷 Português

Für Entwickler, Analysten und Softwarearchitekten, die professionelle Diagramme erstellen wollen: klar und schön anzusehen


Was ist die DOT-Sprache? Was ist Graphviz?

DOT ist eine textbasierte Sprache zur Beschreibung von Graphen. Damit beschreibst du Knoten, Kanten und visuelle Attribute mit einer einfachen, gut lesbaren Syntax. Es ist das Standardformat von Graphviz.

Graphviz (Graph Visualization Software) ist eine Open-Source-Werkzeugsammlung zur Visualisierung von Graphen. Ursprünglich bei AT&T Labs entwickelt, liest Graphviz DOT-Dateien und erzeugt daraus Bilder in verschiedenen Formaten (SVG, PNG, PDF). Es ist das weltweit meistgenutzte Werkzeug, um Diagramme aus Code zu erzeugen.

Warum DOT und Graphviz statt grafischer Werkzeuge?

  • Versionierbar: DOT-Dateien sind reiner Text, ideal für Git
  • Reproduzierbar: Dieselbe Datei erzeugt immer dasselbe Diagramm
  • Automatisierbar: Diagramme entstehen in deiner CI/CD-Pipeline
  • Schnell: Du schreibst Code, statt Kästchen mit der Maus herumzuschieben
  • Professionell: Hochwertige Ausgabe für technische Dokumentation

Vorwort

Warum habe ich dieses Handbuch geschrieben? Weil es Anleitungen zu DOT und Graphviz zwar gibt, sie aber alles abdecken: Biologie, Chemie, soziale Netzwerke, Stammbäume. Jedes Mal musste ich mir heraussuchen, was für Softwareentwickler wirklich zählt. Also habe ich beschlossen, diesen Leitfaden zu schreiben und alles zusammenzutragen, was ich über die Jahre benutzt und immer wieder nachgeschlagen habe. Es war einiges an Arbeit, aber ich hoffe, sie lohnt sich. Jetzt teile ich ihn.

Der Vorteil, Diagramme aus Code zu erzeugen? Die DOT-Datei liegt im Repository, direkt neben dem Quellcode. Wenn du die Architektur änderst, aktualisierst du das Diagramm im selben Commit, es durchläuft dasselbe Code-Review und folgt demselben Workflow. Es ist keine PowerPoint-Datei, die auf irgendeinem Laufwerk vergessen wird und die nie wieder jemand öffnet. Es ist Teil des Projekts.

Und das ist noch nicht alles. DOT-Dateien sind Text, also kannst du sie programmatisch erzeugen. Deine Software kann Diagramme produzieren, die den aktuellen Systemzustand zeigen, die Phasen eines Prozesses, den Weg einer Anfrage durch die Microservices, die Abhängigkeiten zwischen zur Laufzeit geladenen Modulen. Ich habe Teams gesehen, die automatisch Karten ihrer Datenbankmigrationen erzeugen, Graphen der aktiven Feature Flags, sogar Diagramme ihrer Message Queues in Echtzeit. Die Möglichkeiten sind endlos.

Wenn du auch genug hast von Screenshots, die am Tag nach der Aufnahme schon veraltet sind, findest du hier alles, was du für den Einstieg brauchst. Und wenn du DOT einmal beherrschst, wirst du merken, dass Diagramme keine statische Dokumentation mehr sind: Sie werden zu einem lebendigen Teil deines Systems.

Daniele Teti
November 2025


Einführung

In der täglichen Arbeit von Softwareentwicklern, ob Analyst, Backend-Entwickler, Frontend-Entwickler, Datenbankexperte oder Architekt, kommt immer der Moment, in dem ein Diagramm unverzichtbar wird.

Du brauchst eines, wenn du:

  • einen komplexen Ablauf erklären musst,
  • die CI/CD-Pipeline aufzeichnen willst,
  • einem neuen Kollegen die Architektur beschreiben sollst,
  • Abhängigkeiten zwischen Modulen analysierst,
  • eine Datenbank dokumentierst,
  • eine technische Präsentation vorbereitest,
  • über ein Refactoring nachdenkst,
  • Engpässe finden musst.

Graphviz und seine DOT-Sprache sind dafür ideale Werkzeuge: textbasiert (versionierbar), schnell geschrieben, schön gerendert, flexibel.

Graphviz installieren

Bevor du loslegst, stell sicher, dass Graphviz installiert ist:

  • Windows: Lade den Installer von graphviz.org/download herunter oder verwende winget install graphviz
  • macOS: brew install graphviz
  • Linux: sudo apt install graphviz (Debian/Ubuntu) oder sudo dnf install graphviz (Fedora/RHEL)

Prüfe die Installation mit dot -V: Du solltest die installierte Version sehen.

Dieses Handbuch will der umfassende Leitfaden für alle in der Softwareentwicklung sein, die die DOT-Sprache voll ausschöpfen wollen. Du findest:

  • eine gründliche Erklärung der Attribute mit allen relevanten Optionen,
  • vollständige, wiederverwendbare und kommentierte Beispiele,
  • Best Practices für professionelle Grafiken,
  • Hinweise zum Einsatz der Layout-Engines,
  • konkrete Szenarien aus der Entwicklungswelt (Design, Refactoring, Analyse, Architektur).

Die DOT-Sprache: solide Grundlagen

DOT beschreibt Graphen mit einer sehr einfachen Syntax:

digraph Name {
    nodeA -> nodeB;
}

Oder ungerichtet:

graph Name {
    nodeA -- nodeB;
}

Die Grundbegriffe:

  • Knoten (nodes): Entitäten (Funktionen, Objekte, Microservices, DB-Tabellen)
  • Kanten (edges): Beziehungen, Aufrufe, Abläufe
  • Attribute: visuelles Erscheinungsbild oder Metadaten

Quick Start: dein erstes Diagramm in 30 Sekunden

Sofort online testen (ohne etwas zu installieren)

Alle Beispiele in diesem Artikel kannst du direkt online mit Edotor.net ausprobieren:

  1. Geh auf edotor.net

  2. Kopiere den DOT-Code eines beliebigen Beispiels aus diesem Artikel

  3. Füge ihn im linken Bereich ein (und ersetze den vorhandenen Code)

  4. Sieh dir das Rendering sofort im rechten Bereich an

Das ist der schnellste Weg, um zu experimentieren, ohne Graphviz zu installieren. Wenn du für die Produktion bereit bist, installierst du Graphviz lokal.

Erstes Beispiel zum Ausprobieren

Kopiere diesen Code und teste ihn auf edotor.net:

digraph MyFirstGraph {
    node [shape=box, style=rounded, fillcolor=lightblue, style="rounded,filled"];
    edge [color=blue];

    Start -> Process -> End;
    Process -> Error [style=dashed, label="on failure"];
    Error -> Process [label="retry"];
}

Oder über die lokale Kommandozeile

Lege eine Datei hello.dot mit dem obigen Code an und erzeuge das SVG-Bild:

dot -Tsvg hello.dot -o hello.svg

Öffne hello.svg im Browser und du siehst dein erstes Flussdiagramm! Ab hier basiert alles auf Variationen und Kombinationen dieser Konzepte.


Grundlegende Attribute (mit allen Optionen)

Attribute lassen sich global anwenden auf:

  • graph
  • node
  • edge
  • einzelne Elemente

Beispiel:

digraph demo {
    graph [rankdir=LR];
    node [shape=box];
    edge [color=grey];

    A -> B;
}

Es folgt eine Liste der wichtigsten Attribute mit den Optionen, die in der Softwareentwicklung am nützlichsten sind.


Knotenattribute (node)

shape: Form des Knotens

Nützliche Optionen:

  • box
  • ellipse
  • circle
  • diamond (Entscheidungen in Abläufen)
  • record (Klassendiagramme, Datenstrukturen)
  • plaintext (vollständig individueller Inhalt mit HTML-Label)
  • note
  • folder (in manchen Builds verfügbar)

Beispiel:

node [shape=box];

Typische Verwendung:

  • box → Softwaremodule
  • ellipse → Zustände
  • diamond → Entscheidungen

style: grafischer Stil

Gängige Optionen:

  • filled
  • dashed
  • dotted
  • bold
  • rounded
  • Kombinationen: "filled,rounded"

Beispiel:

node [style="filled,rounded"];

fillcolor: Füllfarbe

Formate:

  • Namen (z. B. "lightgrey")
  • HEX (z. B. "#AABBCC")
  • RGB ("#rrggbb")
  • HSL (in manchen Builds)

fontname, fontcolor, fontsize

Z. B.:

node [fontname="Segoe UI", fontsize=12, fontcolor="#333333"];

margin

Innenabstand des Knotens.

node [margin="0.2,0.1"];

width und height: Abmessungen des Knotens

Steuern die Größe der Knoten. Standardmäßig bemisst Graphviz die Knoten automatisch passend zu ihrem Inhalt.

node [width=1.5, height=0.8];

fixedsize: exakte Abmessungen erzwingen:

  • fixedsize=false (Standard): Der Knoten wächst mit dem Inhalt, width/height gelten als Mindestwerte
  • fixedsize=true: Der Knoten hat exakt die mit width/height angegebenen Abmessungen, unabhängig vom Inhalt
  • fixedsize=shape: Gilt nur für die Form, nicht für das Label

Praktische Anwendungsfälle:

  • Einheitliches Erscheinungsbild: Verwende fixedsize=true mit width, damit alle Knoten gleich groß sind (unverzichtbar für Zustandsdiagramme und Flussdiagramme)
  • Flexible Größe: Lass den Standard fixedsize=false, damit sich die Knoten der Länge des Inhalts anpassen
  • Nur feste Breite: Kombiniere es mit height, um das Seitenverhältnis zu steuern
// Alle Zustände gleich groß (professionelle FSM)
node [shape=circle, fixedsize=true, width=0.9];

// Mindestgröße, kann aber wachsen
node [shape=box, width=1.0, fixedsize=false];

label und xlabel: Beschriftungen der Knoten

label: Standardbeschriftung, die im Knoten oder in seiner Nähe angezeigt wird:

A [label="State A"];

Mehrzeilige Labels: Verwende \n für Zeilenumbrüche:

A [label="Main Title\nSubtitle or description"];

xlabel: Externe Beschriftung außerhalb der Knotengrenze. Graphviz sucht automatisch die beste Position, um Überlappungen mit Kanten und anderen Knoten zu vermeiden. Sehr praktisch für Zustandsdiagramme, in denen die Zustände aufgeräumt bleiben sollen:

A [xlabel="State A"];

Praktisches Beispiel: label und xlabel im Vergleich

digraph LabelComparison {
    graph [rankdir=LR, fontname="Segoe UI"];
    node [shape=circle, fontsize=11, fontname="Segoe UI"];
    edge [fontname="Segoe UI"];

    subgraph cluster_standard {
        label="Using label (internal)";
        style=filled;
        fillcolor="#F5F5F5";

        S1 [label="Idle"];
        S2 [label="Running"];
        S3 [label="Done"];

        S1 -> S2 [label="start"];
        S2 -> S3 [label="finish"];
        S3 -> S1 [label="reset"];
    }

    subgraph cluster_external {
        label="Using xlabel (external)";
        style=filled;
        fillcolor="#F5F5F5";

        X1 [xlabel="Idle"];
        X2 [xlabel="Running"];
        X3 [xlabel="Done"];

        X1 -> X2 [label="start"];
        X2 -> X3 [label="finish"];
        X3 -> X1 [label="reset"];
    }
}

Graphviz-Zustandsgraph im Vergleich: label innerhalb der Knoten und xlabel außerhalb

Wann du xlabel verwendest:

  • Zustandsdiagramme: Die Zustandskreise bleiben optisch sauber
  • Komplexe Graphen: Weniger visuelles Durcheinander in den Knoten
  • Automatische Positionierung: Graphviz findet die optimale Position der Beschriftung
  • Kleine Knoten: Wenn interne Labels die Knoten zu groß machen würden

Notizen und Anmerkungen an Knoten

Es gibt mehrere Techniken, um den Knoten deiner Diagramme erklärende Notizen, Beschreibungen oder Anmerkungen hinzuzufügen. Besonders nützlich sind sie für Mindmaps, Dokumentation und komplexe Architekturen.

Technik 1: Mehrzeilige Labels mit \n

Der einfachste Ansatz: Zeilenumbrüche direkt im Label.

Concept [label="Main Concept\n(This is a note explaining the concept)"];

Technik 2: Tooltip mit dem Attribut tooltip

Ein Tooltip, der beim Überfahren mit der Maus erscheint (funktioniert im SVG, wenn es im Browser angezeigt wird):

Node [label="Cloud Storage", tooltip="Amazon S3, Azure Blob, Google Cloud Storage"];

Technik 3: Eigener Notizknoten, mit gestrichelter Kante verbunden

Ein eigener Notizknoten, der sich optisch von den Hauptknoten abhebt:

MainNode [label="User Service"];
Note1 [shape=note, label="Handles authentication\nand user profiles", fillcolor="#FFFACD"];
MainNode -> Note1 [style=dashed, arrowhead=none, color="#CCCCCC"];

Technik 4: HTML-ähnliche Labels mit der Form record

Strukturierte Records trennen den Titel von der Beschreibung:

node [shape=record];
Concept [label="{Concept Name|Description or note\labout this concept}"];

Vollständiges Beispiel: Mindmap mit Notizen

graph MindMapWithNotes {
    graph [layout=fdp, K=0.6, fontname="Segoe UI"];
    node [shape=box, style="rounded,filled", fillcolor="#E3F2FD", fontsize=11, fontname="Segoe UI"];
    edge [color="#888888", fontname="Segoe UI"];

    // Hauptkonzept (zentral)
    Central [label="Project\nArchitecture", fillcolor="#BBDEFB", fontsize=14, width=2.0, height=1.0, pin=true, pos="0,0!"];

    // Unterkonzepte (rund um das Zentrum)
    Frontend [label="Frontend\nReact + TypeScript", width=1.8];
    Backend [label="Backend\nNode.js + Express", width=1.8];
    Database [label="Database\nPostgreSQL", width=1.5];
    DevOps [label="DevOps\nDocker + CI/CD", width=1.5];

    // Notizknoten (an die Konzepte gehängt)
    FrontendNote [shape=note, label="Uses Redux\nfor state mgmt", fillcolor="#FFFACD", fontsize=10];
    BackendNote [shape=note, label="RESTful API\n+ WebSocket", fillcolor="#FFFACD", fontsize=10];
    DatabaseNote [shape=note, label="PostgreSQL\n+ migrations", fillcolor="#FFFACD", fontsize=10];
    DevOpsNote [shape=note, label="Automated\ndeployments", fillcolor="#FFFACD", fontsize=10];

    // Hauptverbindungen (Äste der Mindmap)
    Central -- Frontend;
    Central -- Backend;
    Central -- Database;
    Central -- DevOps;

    // Notizen mit gestrichelten Linien angehängt (ohne Pfeile)
    Frontend -- FrontendNote [style=dashed, color="#CCCCCC"];
    Backend -- BackendNote [style=dashed, color="#CCCCCC"];
    Database -- DatabaseNote [style=dashed, color="#CCCCCC"];
    DevOps -- DevOpsNote [style=dashed, color="#CCCCCC"];
}

Graph einer Projektarchitektur mit Notizknoten zu React, Node.js, PostgreSQL und Docker

Wann welche Technik passt:

TechnikAm besten fürVorteileNachteile
Mehrzeilig \nKurze Notizen (1-2 Zeilen)Einfach, immer sichtbarKann Knoten zu groß machen
tooltipLange ErklärungenÜberlädt das Diagramm nichtFunktioniert nur im interaktiven SVG
Eigener NotizknotenWichtige AnmerkungenSehr sichtbar, gestaltbarMehr visuelle Komplexität
HTML-RecordStrukturierte DatenSaubere TrennungKomplexere Syntax

Kantenattribute (edge)

arrowsize

Skalierung der Pfeilspitze. Standard ~1.0

edge [arrowsize=0.8];

arrowhead / arrowtail

Nützliche Optionen:

  • normal
  • empty (hohles Dreieck, sehr gut lesbar)
  • diamond
  • onormal
  • crow (ER-Diagramme)
  • tee
  • none

style und color

edge [style=dashed, color="#888888"];

label

Beschriftung der Kante.

A -> B [label="calls"];

Graph-Attribute (graph)

rankdir

Layoutrichtung (nur dot):

  • TB (oben → unten)
  • BT (unten → oben)
  • LR (links → rechts)
  • RL (rechts → links)

Z. B.:

graph [rankdir=LR];

splines

Steuert die Form der Kanten:

  • true (Standard)
  • false (gerade Linien)
  • polyline
  • ortho (orthogonal, ideal für “Architekten”-Diagramme)

ranksep, nodesep

Horizontale/vertikale Abstände.

graph [ranksep=0.8, nodesep=0.6];

Wie definiert man in DOT Stile für Knotengruppen?

Eine der häufigsten Fragen bei Graphviz lautet: Wie wende ich denselben Stil auf eine Gruppe von Knoten an, ohne ihn für jeden einzelnen zu wiederholen?

Die Antwort ist einfach: Liste die Knoten in derselben Zeile auf, gefolgt von der Attributdefinition. DOT wendet diese Attribute auf alle aufgeführten Knoten an.

Syntax für das Stylen von Knotengruppen

Methode 1: Knoten-Defaults neu definieren (empfohlen)

// Node-Defaults vor jeder Gruppe neu definieren
node [shape=box, style=filled, fillcolor="#E8F4F8"];
A; B; C;

node [shape=ellipse, style=filled, fillcolor="#FFF4E6", fontname="Segoe UI"];
D; E; F;

node [shape=diamond, style=filled, fillcolor="#FFE8E8"];
G; H; I;

Methode 2: Knoten mit Attributen auflisten

// Alternative: Knoten durch Semikolons getrennt auflisten, der letzte mit Attributen
A; B; C [shape=box, style=filled, fillcolor="#E8F4F8"];
D; E; F [shape=ellipse, style=filled, fillcolor="#FFF4E6"];
G; H; I [shape=diamond, style=filled, fillcolor="#FFE8E8"];

Hinweis: Methode 1 ist über verschiedene Graphviz-Versionen hinweg zuverlässiger und macht es leichter, später Knoten zu einer Kategorie hinzuzufügen.

Diese Technik ist unverzichtbar, wenn du komplexe Diagramme mit Dutzenden Knoten aus verschiedenen Kategorien hast.

Praxisbeispiel: Knoten nach Rolle kategorisieren

Stell dir vor, du musst eine Architektur mit drei Arten von Komponenten zeichnen: Services (blaue Kästen), Datenbanken (grüne Zylinder), Queues/Nachrichten (orange Ellipsen).

digraph Architecture {
    graph [rankdir=LR, nodesep=0.8, fontname="Segoe UI"];
    node [fontname="Segoe UI"];
    edge [fontname="Segoe UI"];

    // Services - blaue Kästen
    node [shape=box, style="filled,rounded", fillcolor="#E3F2FD"];
    AuthService; UserService; OrderService; NotificationService;

    // Datenbanken - grüne Zylinder
    node [shape=cylinder, style=filled, fillcolor="#E8F5E9"];
    UserDB; OrderDB; SessionCache;

    // Message Queues - orange Ellipsen
    node [shape=ellipse, style=filled, fillcolor="#FFF3E0"];
    EmailQueue; SMSQueue; PushQueue;

    // Beziehungen
    AuthService -> SessionCache;
    UserService -> UserDB;
    OrderService -> OrderDB;
    OrderService -> EmailQueue;
    NotificationService -> EmailQueue;
    NotificationService -> SMSQueue;
    NotificationService -> PushQueue;
}

Services, Datenbanken und Queues nach Rolle eingefärbt: AuthService, UserDB, OrderService, EmailQueue

Was dieses Beispiel macht: Es definiert drei Knotenkategorien mit unterschiedlichen Stilen in nur drei Zeilen. Services sind abgerundete blaue Kästen, Datenbanken grüne Zylinder, Queues orange Ellipsen. Jede Kategorie ist auf einen Blick erkennbar.

Warum diese Technik?

  1. DRY-Code (Don’t Repeat Yourself): Du wiederholst shape=box, style=filled nicht für jeden Knoten
  2. Wartbarkeit: Um die Farbe aller Services zu ändern, genügt eine einzige Änderung
  3. Lesbarkeit: Der DOT-Code dokumentiert sich selbst (du siehst sofort, welche Knoten Services und welche DBs sind)
  4. Skalierbarkeit: Ein neuer Service bedeutet nur, seinen Namen zur Liste hinzuzufügen

Kombination mit Standardattributen

Du kannst diese Technik für maximale Flexibilität mit Standardattributen kombinieren:

digraph Mixed {
    // Standard für alle Knoten
    node [fontname="Segoe UI", fontsize=11];

    // Dann nach Gruppe spezialisieren
    Input; Validation [shape=parallelogram, fillcolor="#B3E5FC", style=filled];
    Process; Transform [shape=box, fillcolor="#C8E6C9", style=filled];
    Output; Export [shape=parallelogram, fillcolor="#FFCCBC", style=filled];
    Error [shape=octagon, fillcolor="#FFCDD2", style=filled];

    Input -> Validation -> Process -> Transform -> Output -> Export;
    Validation -> Error;
    Process -> Error;
}

Knoten für Input, Validierung, Verarbeitung, Transformation und Output, gestylt über gemeinsame Standardattribute

Was dieses Beispiel macht: Es legt einen gemeinsamen Standard fest (Schrift Arial 11pt) und dann drei Gruppen: Input/Output als Parallelogramme (Flussdiagramm-Konvention), Verarbeitungsschritte als Kästen, Fehler als rote Achtecke.


Layout-Engines: die richtige wählen

Graphviz hat nicht nur eine Rendering-Engine, sondern mehrere, jede für bestimmte Arten von Graphen optimiert. Die richtige Engine zu wählen heißt, lesbarere und professionellere Diagramme zu bekommen.

Die Engine gibst du auf der Kommandozeile mit dem Flag -K an:

dot -Kdot -Tsvg file.dot -o output.svg
dot -Kneato -Tsvg file.dot -o output.svg

Oder direkt in der DOT-Datei:

graph G {
    layout=neato;
    // ...
}

Es folgen die wichtigsten Engines und wann du sie einsetzt.


Verfügbare Layout-Engines

dot: hierarchisches Layout (Standard)

Was sie macht: Ordnet die Knoten hierarchisch an und folgt dabei der Richtung der Kanten. Sie ist die meistgenutzte.

Perfekt für:

  • Flussdiagramme und Ablaufdiagramme
  • CI/CD-Pipelines
  • Call Graphs (Graph der Aufrufe zwischen Funktionen)
  • Schichtenarchitekturen (Presentation → Business → Data)
  • Sequenzielle Prozesse
  • Abhängigkeitsdiagramme mit klarer Richtung

Beispielbefehl:

dot -Tsvg flowchart.dot -o flowchart.svg

Visuelles Beispiel:

digraph DotExample {
    graph [rankdir=TB, fontname="Segoe UI"];
    node [shape=box, style="rounded,filled", fillcolor="#E3F2FD", fontname="Segoe UI"];

    A -> B -> C;
    A -> D -> C;
    B -> E;
    D -> E;
}

Fünf Knoten A bis E, von der hierarchischen Engine dot von oben nach unten angeordnet

Was du siehst: Knoten in klaren hierarchischen Ebenen von oben nach unten. Perfekt, um Abläufe und Abhängigkeiten zu zeigen.

Wann du sie meiden solltest: Wenn der Graph keine klare hierarchische Struktur hat oder viele Zyklen enthält.

neato: Force-directed-Layout

Was sie macht: Positioniert die Knoten, indem sie physikalische Kräfte simuliert (Abstoßung/Anziehung), und erzeugt so organische, symmetrische Layouts.

Nützlich für:

  • Ungerichtete Graphen (ohne Pfeile)
  • Begriffsnetze und Mindmaps
  • Nicht hierarchische Beziehungen zwischen Entitäten
  • Kleine bis mittlere Graphen, in denen natürliche Cluster sichtbar werden sollen

Beispielbefehl:

dot -Kneato -Tsvg concepts.dot -o concepts.svg

Visuelles Beispiel (derselbe Graph wie oben, andere Engine):

graph NeatoExample {
    graph [layout=neato, fontname="Segoe UI"];
    node [shape=ellipse, style=filled, fillcolor="#FFF4E6", fontname="Segoe UI"];

    A -- B -- C;
    A -- D -- C;
    B -- E;
    D -- E;
}

Dieselben fünf Knoten A bis E, platziert von der Force-directed-Engine neato

Was du siehst: Knoten organisch im 2D-Raum verteilt, mit natürlicher Gruppierung. Perfekt für Mindmaps und Begriffsnetze mit nicht hierarchischen Beziehungen.

Wann du sie meiden solltest: Bei sehr großen Graphen (>100 Knoten) oder stark gerichteten.

fdp: Force-directed Placement

Was sie macht: Ähnlich wie neato, aber mit einem anderen Algorithmus (Fruchterman-Reingold). Auf mittleren Graphen meist schneller.

Nützlich für:

  • Mittelgroße ungerichtete Graphen
  • Visualisierung sozialer Netzwerke (Freundschaften, Verbindungen)
  • Abhängigkeitsanalyse ohne ausgeprägte Richtung

Beispielbefehl:

dot -Kfdp -Tsvg network.dot -o network.svg

sfdp: skalierbares Force-directed Placement

Was sie macht: Für sehr große Graphen (Tausende Knoten) optimierte Version von fdp.

Hervorragend für:

  • Abhängigkeitsanalyse komplexer Codebasen
  • Klassengraph eines Enterprise-Projekts
  • Komplexe Netze (Infrastruktur, Microservices)
  • Wenn neato oder fdp zu langsam sind

Beispielbefehl:

dot -Ksfdp -Tsvg dependencies.dot -o dependencies.svg

Tipp: Verwende sfdp ab etwa 100-200 Knoten.

circo: kreisförmiges Layout

Was sie macht: Ordnet die Knoten in konzentrischen Kreisen um einen zentralen Knoten an.

Ideal für:

  • Satellitenmodule rund um einen zentralen Kern darstellen
  • Hub-and-Spoke-Architekturen
  • Komponenten, die von einem zentralen Service abhängen

Beispielbefehl:

dot -Kcirco -Tsvg modules.dot -o modules.svg

Visuelles Beispiel:

graph CircoExample {
    graph [layout=circo, fontname="Segoe UI"];
    node [shape=circle, style=filled, fillcolor="#E8F5E9", fontname="Segoe UI"];

    Core -- Module1;
    Core -- Module2;
    Core -- Module3;
    Core -- Module4;
    Core -- Module5;
    Module1 -- Module2;
    Module3 -- Module4;
}

Core-Knoten und fünf Module, von der Engine circo im Ring angeordnet

Was du siehst: Der zentrale Knoten (Core) in der Mitte, die Satelliten im Kreis darum. Perfekt für Hub-and-Spoke-Architekturen.

twopi: radiales Layout

Was sie macht: Erzeugt ein radiales Baumlayout mit dem Wurzelknoten in der Mitte und Ebenen, die sich nach außen ausbreiten.

Perfekt für:

  • Hierarchische Bäume (Organigramm, Dateisystem)
  • Taxonomien
  • Strukturierte Mindmaps
  • Ausbreitung von einem zentralen Punkt aus

Beispielbefehl:

dot -Ktwopi -Tsvg tree.dot -o tree.svg

Visuelles Beispiel:

digraph TwopiExample {
    graph [layout=twopi, ranksep=2.0, fontname="Segoe UI"];
    node [shape=box, style="rounded,filled", fillcolor="#FFEBEE", fontsize=11, width=1.0, height=0.5, fontname="Segoe UI"];
    edge [color="#666666", fontname="Segoe UI"];

    CEO [label="CEO", fillcolor="#FFCDD2"];

    CEO -> Engineering [label=""];
    CEO -> Sales [label=""];
    CEO -> Marketing [label=""];

    Engineering -> Dev1 [label=""];
    Engineering -> Dev2 [label=""];

    Sales -> Rep1 [label=""];
    Sales -> Rep2 [label=""];

    Marketing -> Designer [label=""];
    Marketing -> Writer [label=""];
}

Firmenorganigramm, das vom CEO ausgeht, gezeichnet von der radialen Engine twopi

Was du siehst: Der CEO in der Mitte, die Abteilungen (Engineering, Sales, Marketing) im ersten Ring und die Teammitglieder im äußeren Ring. Eine klare radiale Hierarchie, perfekt für Organigramme.

Wie du in der Praxis wählst

Art des GraphenEmpfohlene Engine
Flussdiagramm, Pipeline, Prozessedot
Schichtenarchitekturendot
Call Graph, Abhängigkeitsbaumdot
Begriffsnetz, Brainstormingneato
Soziales Netzwerk, mittlere ungerichtete Graphenfdp
Große Graphen (>200 Knoten)sfdp
Zentraler Hub mit Satellitencirco
Hierarchische Bäume, Organigrammtwopi

Faustregel: Hast du Pfeile und eine klare Richtung → nimm dot. Sonst probiere neato oder fdp.


Diagrammtypen und wann du sie im echten Entwickleralltag brauchst

Das ist der umfangreichste Abschnitt. Zu jedem Diagrammtyp findest du:

  • Wann du es im echten Leben einsetzt
  • Empfohlene Attribute
  • Vollständiges Beispiel

Flussdiagramm: Verhalten verstehen

Im Arbeitsalltag musst du oft einen komplexen Entscheidungsablauf erklären: eine Validierung mit mehreren Verzweigungen, einen Onboarding-Prozess für Benutzer oder einfach das Verhalten einer Funktion mit vielen verschachtelten if/else. Das Flussdiagramm ist dafür das ideale Werkzeug.

Wann du ein Flussdiagramm brauchst:

Du bist in der Anforderungsanalyse und musst alle möglichen Fälle verstehen. Du debuggst eine Logik, die verrückt zu spielen scheint, und willst sehen, wo sich der Ablauf verzweigt. Du musst die Dokumentation eines komplexen Geschäftsprozesses schreiben. Du arbeitest einen neuen Kollegen ein und willst ihm zeigen, wie das Authentifizierungssystem funktioniert.

Das Flussdiagramm zeigt visuell Entscheidungen (Rauten), Verarbeitungsschritte (abgerundete Rechtecke) und den logischen Ablauf (Pfeile). Es ist unmittelbar, klar, universell.

Empfohlene Attribute für professionelle Flussdiagramme:

Verwende rankdir=TB (von oben nach unten), um der üblichen Flussdiagramm-Konvention zu folgen. Verwende shape=diamond für Entscheidungsknoten (if/else-Bedingungen). Verwende style=rounded für die Verarbeitungsschritte, damit sie sich von den Rauten abheben. Verwende sanfte Farben (fillcolor), um Start (hellgrün), Fehler (hellrot) und Ende (grau) hervorzuheben.

Vollständiges Beispiel:

digraph Flow {
    graph [rankdir=TB, nodesep=0.6];
    node [fontname="Segoe UI"];

    Start   [shape=oval, style=filled, fillcolor="#C1F2C7"];
    Check   [shape=diamond, label="Valid input?"];
    Process [shape=box, style="filled,rounded", fillcolor="#F0F4FF"];
    Error   [shape=box, fillcolor="#FFEAEA", style=filled];
    End     [shape=oval, fillcolor="#DDDDDD", style=filled];

    Start -> Check;
    Check -> Process [label="yes"];
    Check -> Error   [label="no"];
    Process -> End;
}

Einfaches Flussdiagramm: Start, Raute zur Eingabevalidierung, Zweig Verarbeitung oder Fehler, Ende

Was dieses Beispiel macht: Es beginnt bei einem Anfangszustand (Start), durchläuft die Validierung (Check) und verzweigt sich in zwei Pfade: Erfolg (Process) oder Fehler (Error). Die Farben machen sofort klar, was positiv und was negativ ist.


Abhängigkeitsgraphen: Software als System verstehen

Wenn du an einem bestehenden Projekt arbeitest, lautet eine der ersten Fragen: “Was hängt wovon ab?” Musst du ein Modul refaktorieren, willst du wissen, wer es verwendet. Musst du eine Bibliothek aktualisieren, willst du die Folgewirkungen verstehen. Entwirfst du ein neues Feature, willst du sehen, wo es in die bestehende Architektur passt.

Der Abhängigkeitsgraph ist die Landkarte deines Systems. Er zeigt Module, Services, Klassen oder Microservices als Knoten und Abhängigkeiten als Pfeile. Unverzichtbar ist er für:

Sicheres Refactoring: Bevor du ein Modul anfasst, siehst du, wer es aufruft. Impact-Analyse: Änderst du eine API, siehst du sofort alle Konsumenten. Automatische Dokumentation: Erzeuge den Graphen aus dem Code (mit Werkzeugen wie Doxygen, Madge oder eigenen Skripten) und halte ihn aktuell. Dependency-Injection-Mapping: Visualisiere, wie Spring, Angular oder .NET die Abhängigkeiten injizieren.

Nützliche Attribute:

Verwende rankdir=LR (von links nach rechts) für einen horizontalen Ablauf, typisch für Abhängigkeitsketten. Verwende shape=box für Module/Services. Verwende color und penwidth, um kritische oder problematische Abhängigkeiten hervorzuheben (z. B. zirkuläre Abhängigkeiten in Rot). Verwende style=dashed für optionale oder schwache Abhängigkeiten.

Beispiel:

digraph Deps {
    graph [rankdir=LR];
    node [shape=box, style=filled, fillcolor="#F7FAFF", fontname="Segoe UI"];
    edge [color="#555555"];

    UI -> API;
    API -> Auth;
    API -> UserService;
    UserService -> Database [color="#FF5555", penwidth=2, label="critical"];
}

Abhängigkeitsgraph von der UI über API und Auth bis zu UserService und Datenbank

Was dieses Beispiel macht: Es zeigt eine klassische Webarchitektur: Die UI ruft die API auf, die API hängt von Auth und UserService ab, UserService spricht mit der Datenbank. Die kritische Abhängigkeit (UserService → Database) ist rot und mit dicker Linie hervorgehoben: Fällt die DB aus, bricht alles zusammen.


Softwarearchitektur: Cluster und Schichten

Wenn du eine Architektur entwirfst oder die bestehende dokumentierst, musst du logische Gruppierungen und die Trennung der Schichten zeigen. Ein typisches Websystem hat Presentation, Business und Data. Ein Microservices-Projekt hat logische Grenzen (Edge, Services, Datastores). Ein Legacy-System hat vielleicht nach Domäne getrennte Module.

Das Architekturdiagramm mit Clustern ermöglicht dir:

Getrennte Schichten darstellen: Presentation Layer, Business Layer, Data Layer. Jede Schicht ist ein farbiger Kasten mit ihren Komponenten. Grenzen der Microservices zeigen: Edge Gateway, Services, Datastores. Jede Grenze ist ein Cluster. Legacy-Module dokumentieren: Isoliere die Module nach Verantwortung (Auth, Orders, Reporting), damit klar ist, wer was macht. Stakeholdern die Architektur präsentieren: Ein Schichtendiagramm ist universell und auch für Nicht-Techniker verständlich.

Nützliche Attribute:

Verwende subgraph cluster_*, um visuelle Gruppierungen zu erzeugen. Verwende compound=true, um Kanten zu erlauben, die Cluster überqueren. Verwende splines=ortho für orthogonale Linien, typisch für “Architekten”-Diagramme. Verwende shape=cylinder für Datenbanken, damit sie sofort erkennbar sind.

Beispiel einer Schichtenarchitektur:

digraph Architecture {
    graph [
        rankdir=TB,
        ranksep=0.8,
        nodesep=0.6,
        overlap=false,
        splines=true,
        sep="+0.2"
    ];
    node [shape=box, style="rounded,filled", fillcolor="#F0F4FF", fontname="Segoe UI"];

    subgraph cluster_presentation {
        label="Presentation Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#E8F4F8";
        UI;
    }

    subgraph cluster_business {
        label="Business Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#FFF4E6";
        ServiceA; ServiceB;
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#F0F0F0";
        DB [shape=cylinder, fillcolor="#D0E8FF"];
    }

    UI -> ServiceA;
    UI -> ServiceB;
    ServiceA -> DB;
    ServiceB -> DB;
}

Schichtenarchitektur mit Clustern für Presentation, Business und Data Layer

Was dieses Beispiel macht: Es definiert drei Schichten mit subgraph cluster_*. Presentation enthält die UI, Business zwei Services, Data die DB (mit shape=cylinder). Die Pfeile zeigen den Ablauf: UI → Services → DB. Die Architektur ist auf einen Blick verständlich.


Microservices-Karte: ein verteiltes Ökosystem verstehen

Wenn du mit Microservices arbeitest, hast du Dutzende Services, die miteinander kommunizieren: API Gateway, Domänen-Services (Orders, Users, Notifications), Datenbanken, Queues, Caches. Wenn in der Produktion ein Incident auftritt, lautet die erste Frage: “Wer spricht mit wem? Wo ist der Engpass?”

Die Microservices-Karte ist dein Navi im verteilten Chaos. Du brauchst sie für:

Architekturentwurf: Bevor du Code schreibst, zeichne die Karte. Identifiziere die logischen Grenzen (Edge, Core Services, Datastores). API-Dokumentation: Zeige, wer welchen Service über welches Protokoll aufruft (REST, gRPC, Events). Performance-Analyse: Während eines Incidents schaust du auf die Karte und verstehst sofort, ob das Problem im API Gateway, in einem bestimmten Service oder in der gemeinsamen DB liegt. Post-Mortem: Nach einem Ausfall hilft die Karte, die Fehlerkette zu rekonstruieren.

Nützliche Attribute:

Verwende cluster, um logische Grenzen zu trennen (Edge, Services, Data). Verwende shape=cylinder für Datenbanken, shape=box für Services. Verwende Labels an den Kanten, um das Protokoll anzugeben (HTTP, gRPC, Kafka). Verwende shape=plaintext mit HTML-Tabelle für komplexe Services mit mehreren Ports.

Beispiel:

digraph Micro {
    // Globale Einstellungen (gelten für alles)
    graph [rankdir=LR, splines=true, nodesep=1.2, ranksep=1.8, overlap=false, sep="+0.4", fontname="Segoe UI"];
    node [shape=box, style="rounded,filled", fillcolor="#E3F2FD", fontname="Segoe UI", fontsize=11];
    edge [color="#555555", arrowsize=0.8, fontsize=10, fontcolor="#333333", fontname="Segoe UI"];

    subgraph cluster_gateway {
        label="Edge Layer";
        fillcolor="#FFF3E0";
        color="#FF9800";
        Gateway [label="API Gateway", fillcolor="#FFE0B2"];
    }

    subgraph cluster_services {
        label="Microservices Layer";
        fillcolor="#E8F5E9";
        color="#4CAF50";
        OrderService [label="Order Service", fillcolor="#C8E6C9"];
        UserService [label="User Service", fillcolor="#C8E6C9"];
        NotificationService [label="Notification Service", fillcolor="#C8E6C9"];
    }

    subgraph cluster_data {
        label="Data Layer";
        fillcolor="#F5F5F5";
        color="#9E9E9E";
        DB [shape=cylinder, label="Postgres\nDB", fillcolor="#BBDEFB"];
        Cache [shape=cylinder, label="Redis\nCache", fillcolor="#FFCCBC"];
    }

    // Edge zu den Services
    Gateway -> UserService [label="HTTP"];
    Gateway -> OrderService [label="HTTP"];

    // Service zu den Daten
    OrderService -> DB [label="SQL"];
    UserService -> Cache [label="GET/SET"];

    // Service zu Service
    NotificationService -> UserService [label="gRPC"];
    OrderService -> NotificationService [label="Event", style=dashed];
}

Microservices-Karte: API Gateway, Order-, User- und Notification-Service, Postgres und Redis

Was dieses Beispiel macht: Es gliedert ein Microservices-Ökosystem in drei farbige Schichten:

  • Edge Layer (orange): API Gateway als Einstiegspunkt
  • Microservices Layer (grün): drei Services mit klaren Verantwortlichkeiten
  • Data Layer (grau): Postgres-Datenbank und Redis-Cache (Zylinder zur optischen Unterscheidung)

Gezeigte Kommunikationsmuster:

  • Gateway → Services: HTTP-Aufrufe (durchgezogene Pfeile)
  • Services → Data: SQL-Abfragen und Cache-Operationen
  • Service-to-Service: synchroner gRPC-Aufruf und asynchrones Event (gestrichelter Pfeil)

Die farbcodierten Cluster zeigen sofort die Architekturgrenzen, und die beschrifteten Pfeile machen die Protokolle explizit. Perfekt für Onboarding, Architektur-Reviews oder die Analyse von Incidents.


Zustandsdiagramme: Verhalten modellieren

Viele Systeme haben ein zustandsbasiertes Verhalten: Eine HTTP-Anfrage kann Idle, Loading, Success oder Error sein. Eine E-Commerce-Bestellung geht von Draft → Pending → Confirmed → Shipped. Ein Embedded-System hat die Zustände Einschalten, Standby, Betrieb, Fehler. Eine Benutzeroberfläche hat die Zustände Laden, Bereit, Fehler.

Das Zustandsdiagramm modelliert dieses Verhalten als Graph: Jeder Knoten ist ein Zustand, jede Kante ein Übergang, beschriftet mit dem Ereignis, das ihn auslöst. Unverzichtbar ist es für:

Zustandsautomaten entwerfen: Bevor du das State Pattern im Code umsetzt, zeichne das Diagramm. Protokolle dokumentieren: Netzwerkprotokolle (TCP, WebSocket, eigene) haben präzise Zustandsautomaten. Das Diagramm macht sie explizit. UI/UX-Abläufe modellieren: Wenn du eine App entwirfst, zeichne die Zustände der Oberfläche: Laden, Bereit, Fehler, Leer. Embedded-Systeme debuggen: Bleibt ein Gerät in einem Zustand hängen, hilft dir das Diagramm zu verstehen, welche Übergänge fehlen.

Verbindung zur Informatik-Theorie und zu Design Patterns:

Zustandsdiagramme in DOT bilden grundlegende Konzepte der Informatik und des Softwaredesigns direkt ab:

  • FSM (Finite State Machine, endlicher Automat): Ein Berechnungsmodell mit einer endlichen Anzahl von Zuständen. Das Diagramm zeigt alle möglichen Zustände und die Übergänge zwischen ihnen. Eingesetzt in Compilern, Parsern und Protokollimplementierungen.

  • DFA (Deterministic Finite Automaton, deterministischer endlicher Automat): Eine besondere Art von FSM, bei der jeder Zustand pro Eingabesymbol genau einen Übergang hat. Zustandsdiagramme sind die visuelle Darstellung der DFAs, die in der Theorie formaler Sprachen und in Engines für reguläre Ausdrücke verwendet werden.

  • State Pattern (GoF-Design-Pattern): Ein objektorientiertes Entwurfsmuster, mit dem ein Objekt sein Verhalten ändern kann, wenn sich sein interner Zustand ändert. Das Zustandsdiagramm wird zum Bauplan für die Umsetzung des Patterns: Jeder Kreis ist eine Klasse, die das Interface State implementiert, jeder Pfeil eine Methode für den Zustandsübergang.

Wenn du ein Zustandsdiagramm zeichnest, erstellst du nicht nur Dokumentation: Du erstellst eine formale Spezifikation, die sich direkt in Code übersetzen (State Pattern), zur Validierung verwenden (DFA) oder auf Korrektheit analysieren lässt (FSM-Theorie).

Nützliche Attribute:

Verwende shape=circle für Zustände (übliche FSM-Konvention). Verwende rankdir=LR für ein horizontales Layout, typisch für Zustandsdiagramme. Verwende label an den Kanten, um das Ereignis zu zeigen, das den Übergang auslöst. Verwende shape=doublecircle für End- bzw. Terminalzustände. Verwende fixedsize=true mit width, damit alle Kreise für ein einheitliches Bild gleich groß sind.

Anfangs- und Endzustände darstellen (FSM/DFA-Standard):

Nach den Konventionen für endliche Automaten und DFAs gilt:

  • Anfangszustand: Verwende shape=point mit kleiner width (z. B. 0.2), um einen schwarzen Punkt als Einstiegspunkt zu erzeugen
  • End-/Akzeptanzzustand: Verwende shape=doublecircle für einen doppelten Kreisrand, der Terminal- bzw. Akzeptanzzustände kennzeichnet
  • Normale Zustände: Verwende shape=circle mit fixedsize=true für alle Zwischenzustände (sorgt für ein einheitliches Bild)

Vollständiges Beispiel mit korrekter FSM-Notation:

digraph States {
    graph [rankdir=LR, fontname="Segoe UI"];
    node [shape=circle, fontsize=12, fixedsize=true, width=0.9, fontname="Segoe UI"];
    edge [fontname="Segoe UI"];

    // Anfangszustand (schwarzer Punkt)
    START [shape=point, width=0.2, fixedsize=true];

    // Endzustand (doppelter Kreis)
    END [shape=doublecircle, fixedsize=true, width=0.9];

    // Normale Zustände
    Idle; Loading; Ready; Error;

    // Übergänge
    START -> Idle;
    Idle -> Loading   [label="start"];
    Loading -> Ready  [label="success"];
    Loading -> Error  [label="fail"];
    Error -> Idle     [label="reset"];
    Ready -> END      [label="finish"];
}

Zustandsdiagramm mit den Zuständen Idle, Loading, Ready und Error und beschrifteten Übergängen

Was dieses Beispiel macht: Es modelliert den Lebenszyklus einer asynchronen Anfrage nach den FSM/DFA-Konventionen:

  • START (shape=point): schwarzer Punkt als Einstiegspunkt des Zustandsautomaten
  • END (shape=doublecircle): doppelter Kreis als Akzeptanz- bzw. Terminalzustand
  • Normale Zustände (Idle, Loading, Ready, Error): einheitliche Kreise (fixedsize=true, width=0.9) für die Zwischenzustände
  • Beschriftete Übergänge: Pfeile mit den Ereignissen, die die Zustandswechsel auslösen

Der Automat beginnt bei START, geht in Idle über und wechselt dann zu Loading. Von Loading aus kann er erfolgreich sein (→ Ready) oder scheitern (→ Error). Fehler lassen sich auf Idle zurücksetzen. Der Erfolg führt zum Endzustand END.

Vom Diagramm zum Code (Umsetzung des State Pattern):

Dieses Diagramm lässt sich direkt in das State Pattern übersetzen:

// Jeder Kreis wird zu einer State-Klasse
interface State {
    void start();
    void success();
    void fail();
    void reset();
    void finish();
}

class IdleState implements State { ... }
class LoadingState implements State { ... }
class ReadyState implements State { ... }
class ErrorState implements State { ... }

// Übergänge werden zu Methodenimplementierungen
class LoadingState implements State {
    void success() {
        context.setState(new ReadyState());
    }
    void fail() {
        context.setState(new ErrorState());
    }
}

Das Diagramm dient zugleich als Dokumentation und als Spezifikation der Implementierung.


Klassendiagramme mit record

Wenn du ein objektorientiertes System entwirfst oder die Domäne einer Anwendung dokumentieren willst, ist das Klassendiagramm der Standard. Es zeigt Klassen mit Attributen und Methoden sowie die Beziehungen zwischen ihnen (Vererbung, Komposition, Abhängigkeit).

DOT ist kein UML, aber mit shape=record bekommst du etwas sehr Ähnliches, das sich bestens lesen lässt. Nützlich ist das für:

Erster Entwurf: Bevor du Code schreibst, zeichne die wichtigsten Domänenklassen. Identifiziere Attribute, Methoden, Beziehungen. Refactoring: Wenn du ein Modul umbauen musst, zeichne den aktuellen und den gewünschten Zustand. Vergleiche die beiden Diagramme. Domain-Driven Design (DDD): Modelliere Entities, Value Objects, Aggregates. Das Diagramm hilft, die Grenzen der Domäne sichtbar zu machen. Dokumentation: Erzeuge das Diagramm automatisch aus dem Code (mit Werkzeugen wie Doxygen) und halte es aktuell.

Nützliche Attribute:

Verwende shape=record, um Kästen mit getrennten Abschnitten zu erzeugen (Klassenname | Attribute | Methoden). Verwende fontname="Segoe UI" oder eine Monospace-Schrift, damit es wie Code aussieht. Verwende arrowhead=onormal für Vererbung (hohler Pfeil, UML-Standard). Verwende \l (Backslash-l), um den Text im Record linksbündig auszurichten.

Beispiel:

digraph Classes {
    node [shape=record, fontname="Segoe UI"];

    Person [label="{Person|name: string\l age: int\l|greet()}"];
    Employee [label="{Employee|id: int\l role: string\l|work()}"];

    Person -> Employee [arrowhead="onormal"];
}

Klassendiagramm mit record-Formen: Die Klasse Employee erbt von Person

Was dieses Beispiel macht: Es definiert zwei Klassen: Person (mit den Attributen name, age und der Methode greet) und Employee (mit id, role und der Methode work). Person ist die Oberklasse von Employee (Pfeil mit arrowhead=onormal, UML-Standard für Vererbung). Das \l richtet den Text im Record linksbündig aus.


Professionelle ER-Diagramme mit HTML-Label

Wenn du mit Datenbanken arbeitest, musst du früher oder später das Tabellenschema zeichnen: Primärschlüssel, Fremdschlüssel, 1:N- oder N:N-Beziehungen. Das Entity-Relationship-Diagramm (ER) ist dafür der Standard.

DOT unterstützt HTML-Tabellen in Knoten mit shape=plaintext, sodass du saubere, professionelle ER-Diagramme erstellen kannst. Unverzichtbar ist das für:

Datenbankentwurf: Bevor du Migrationen schreibst, zeichne das Schema. Identifiziere Entitäten, Attribute, Beziehungen. Validiere den Entwurf mit dem Team. Datenmodellierung: Wenn du ein neues Modul entwirfst, beginne mit dem Datenmodell. Das ER-Diagramm hilft dir, über Normalisierung und Performance nachzudenken. Reverse Engineering: Erbst du eine Legacy-DB ohne Dokumentation, erzeuge das ER-Diagramm aus der DB selbst (mit Werkzeugen wie SchemaSpy oder pg_dump + Skript), um die Struktur zu verstehen. Dokumentation: Das ER-Diagramm ist auch für Nicht-Entwickler verständlich (Produktmanager, Business-Analysten).

Nützliche Attribute:

Verwende shape=plaintext, um HTML-Labels zu aktivieren. Verwende das HTML-Element <TABLE>, um strukturierte Kästen mit Kopfzeile (Tabellenname) und Zeilen (Felder) zu erzeugen. Verwende arrowhead=crow für 1:N-Beziehungen (Standard in ER-Diagrammen). Verwende label="1:N" an den Kanten, um die Kardinalität explizit zu machen.

Beispiel:

digraph ER {
    node [shape=plaintext];

    User [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
            <TR><TD><B>User</B></TD></TR>
            <TR><TD>id PK</TD></TR>
            <TR><TD>email</TD></TR>
        </TABLE>
    >];

    Order [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
            <TR><TD><B>Order</B></TD></TR>
            <TR><TD>id PK</TD></TR>
            <TR><TD>user_id FK</TD></TR>
        </TABLE>
    >];

    User -> Order [label="1:N", arrowhead="crow"];
}

ER-Diagramm mit HTML-Label-Tabellen: User und Order in einer 1:N-Beziehung

Was dieses Beispiel macht: Es definiert zwei Tabellen (User und Order) mit HTML. Jede Tabelle hat eine fette Kopfzeile und Zeilen für die Felder. Der Pfeil mit arrowhead=crow und label="1:N" zeigt die Beziehung: Ein User hat viele Orders (Fremdschlüssel user_id in Order).


Diagramme von CI/CD-Pipelines

Wenn du in einem Team mit Continuous Integration und Deployment arbeitest, hast du eine Pipeline, die automatische Schritte ausführt: Build, Test, statische Analyse, Packaging, Deploy, Monitoring. Wenn etwas kaputtgeht oder ein neuer Entwickler dazukommt, brauchst du ein Diagramm der gesamten Pipeline.

Das CI/CD-Diagramm zeigt den automatischen Ablauf vom Commit bis zum Deploy. Nützlich ist es für:

DevOps und SRE: Dokumentiere die bestehende Pipeline. Finde die Engpässe (welcher Schritt dauert am längsten?). Onboarding im Team: Ein neuer Entwickler sieht sich das Diagramm an und versteht sofort, was nach einem git push passiert. Optimierung: Willst du einige Schritte parallelisieren? Das Diagramm zeigt dir, welche wovon abhängen. Debugging: Schlägt die Pipeline fehl? Das Diagramm hilft dir zu verstehen, bei welchem Schritt und warum (gestrichelter Pfeil für Wiederholungen).

Nützliche Attribute:

Verwende rankdir=LR für einen horizontalen Ablauf (typisch für Pipelines). Verwende shape=box mit style=filled für die Schritte und färbe sie nach Typ (Build=blau, Test=grün, Deploy=rot). Verwende style=dotted mit label="retry", um automatische Wiederholungsmechanismen zu zeigen. Verwende label an den Kanten, um Bedingungen anzugeben (z. B. “nur auf dem master-Branch”).

Beispiel:

digraph CICD {
    graph [rankdir=LR];
    node [shape=box, style=filled, fillcolor="#F8FBFF"];

    Code -> Build -> Test -> Package -> Deploy -> Monitor;

    Test -> Build [style=dotted, label="retry"];
}

CI/CD-Pipeline von Code über Build, Test mit Retry, Package und Deploy bis Monitor

Was dieses Beispiel macht: Es zeigt eine klassische Pipeline: Code → Build → Test → Package → Deploy → Monitor. Der gestrichelte Pfeil von Test zu Build zeigt eine automatische Wiederholung, wenn ein Test fehlschlägt. Ein linearer Ablauf, sofort verständlich.


Komplexität reduzieren: Concept Maps und Analyse

Nicht jedes Diagramm muss hierarchisch oder gerichtet sein. Manchmal musst du begriffliche Beziehungen ohne feste Struktur darstellen: beim Brainstorming, beim gemeinsamen Entwurf im Team oder wenn du begriffliche Abhängigkeiten zwischen Technologiebereichen abbilden willst.

Die Concept Map hat keinen “Anfang” und kein “Ende”: Sie ist ein Netz organisch verbundener Knoten. Nützlich ist sie für:

Brainstorming: Beginne bei einer zentralen Idee und füge verbundene Knoten hinzu, während du mit dem Team diskutierst. Die Karte wächst von selbst. Gemeinsamer Entwurf: Bilde in einer Design-Session die Komponenten und ihre Beziehungen ab. Die Hierarchie kennst du noch nicht, aber du weißt, dass “das Backend mit Datenbank und API spricht”. Analyse begrifflicher Abhängigkeiten: Du willst verstehen, welche Technologiebereiche verbunden sind (z. B. Security → Logging → Observability). Übersichtsdokumentation: Für nicht technische Stakeholder ist eine Concept Map zugänglicher als ein hierarchischer Graph.

Nützliche Attribute:

Verwende die Engine neato oder fdp statt dot, um ein organisches Layout auf Basis physikalischer Kräfte zu bekommen. Verwende shape=ellipse für Begriffsknoten (keine Prozesse). Verwende style=filled mit sanften Farben für visuelle Gruppierungen. Verwende ungerichtete Graphen (graph statt digraph), wenn die Beziehungen in beide Richtungen gelten.

Beispiel mit der Engine neato:

graph Concepts {
    layout=neato;
    node [shape=ellipse, style=filled, fillcolor="#EFEFFF"];

    Backend -- Database;
    Backend -- API;
    API -- Security;
    Security -- Logging;
    Logging -- Observability;
}

Concept Map, die Backend, Datenbank, API, Security, Logging und Observability verbindet


Überlappungen vermeiden: overlap und splines

Eines der häufigsten Probleme beim Zeichnen komplexer Graphen sind Überlappungen von Pfeilen, Text und Knoten. Graphviz bietet gezielte Attribute, um dieses Verhalten zu steuern und die Diagramme lesbarer zu machen.

Das Problem: unerwünschte Überlappungen

Bei vielen Knoten und Pfeilen, besonders mit hierarchischen Layouts oder mit splines=ortho, können Pfeile über die Labels der Cluster oder über Knoten laufen. Hier ein typisches Beispiel des Problems:

digraph OverlapProblem {
    graph [rankdir=TB, splines=ortho];
    node [shape=box, style=rounded];

    subgraph cluster_a {
        label="Component A";
        A1; A2;
    }

    subgraph cluster_b {
        label="Component B";
        B1; B2;
    }

    subgraph cluster_c {
        label="Component C";
        C1; C2;
    }

    A1 -> B1;
    A2 -> B2;
    B1 -> C1;
    B2 -> C2;
    A1 -> C1;
}

Drei Komponenten-Cluster, deren Kanten Knoten überqueren, bevor die Overlap-Einstellungen korrigiert werden

Problem: Mit splines=ortho können Pfeile die Labels der Cluster kreuzen und das Diagramm unübersichtlich machen.

Die Lösung: overlap und splines

Graphviz bietet mehrere Attribute, um dieses Problem zu lösen:

overlap: Überlappungen zwischen Knoten vermeiden

graph [overlap=false];

Die wichtigsten Optionen:

  • false oder voronoi: vermeidet Überlappungen (bessere Qualität, langsamer)
  • scale: skaliert den Graphen, um Überlappungen zu vermeiden
  • scalexy: skaliert mit unterschiedlichen Proportionen auf X und Y
  • true (Standard): erlaubt Überlappungen

splines: Form der Kanten steuern

graph [splines=true];

Optionen:

  • true oder spline: weiche Kurven, die Knoten ausweichen (empfohlen)
  • curved: leicht gekrümmte Kanten
  • polyline: gebrochene Linien
  • ortho: orthogonale Linien (können Überlappungen verursachen!)
  • line oder false: gerade Linien

sep: zusätzlicher Abstand zwischen Elementen

graph [sep="+0.2"];

Fügt Abstand zwischen Knoten und Kanten hinzu (in Zoll). Das + bedeutet “zum Standardwert hinzufügen”.

ranksep und nodesep: Abstand zwischen Ebenen und Knoten

graph [ranksep=0.8, nodesep=0.6];

Vergrößert den vertikalen (ranksep) und horizontalen (nodesep) Abstand zwischen den Elementen.

Verbessertes Beispiel

Hier derselbe Graph mit optimierten Attributen gegen Überlappungen:

digraph OverlapSolved {
    graph [
        rankdir=TB,
        ranksep=0.8,
        nodesep=0.6,
        overlap=false,
        splines=true,
        sep="+0.2"
    ];
    node [shape=box, style=rounded];

    subgraph cluster_a {
        label="Component A";
        style=filled;
        fillcolor="#E8F4F8";
        A1; A2;
    }

    subgraph cluster_b {
        label="Component B";
        style=filled;
        fillcolor="#FFF4E6";
        B1; B2;
    }

    subgraph cluster_c {
        label="Component C";
        style=filled;
        fillcolor="#F0F0F0";
        C1; C2;
    }

    A1 -> B1;
    A2 -> B2;
    B1 -> C1;
    B2 -> C2;
    A1 -> C1;
}

Dieselben drei Komponenten-Cluster, sauber neu gezeichnet nach dem Setzen von overlap und splines

Ergebnis: Die Pfeile weichen jetzt Knoten und Labels aus, der Graph ist luftiger und lesbarer. Die Hintergrundfarben helfen, die Cluster zu unterscheiden.

Wann du was verwendest

SzenarioEmpfohlene Attribute
Komplexe Diagramme mit vielen Knotenoverlap=false, splines=true
Hierarchische Graphen (Flussdiagramme, Architekturen)ranksep=0.8, nodesep=0.6, splines=true
Graphen mit Clusternoverlap=false, sep="+0.2"
“Architekten”-Diagramme mit geraden Liniensplines=polyline (ortho vermeiden)
Kleine, einfache GraphenStandard (nichts zu ändern)

Faustregel: Beginne immer mit overlap=false und splines=true, wenn du mehr als 10 Knoten hast oder Cluster verwendest.

Vollständiges Beispiel mit allen Best Practices

Hier ein reales Beispiel, das alle empfohlenen Attribute kombiniert: eine Microservices-Architektur mit 4 Schichten, vielen Knoten und Kanten, farbigen Clustern und optimierten Abständen:

digraph CompleteExample {
    graph [
        rankdir=TB,
        ranksep=1.0,
        nodesep=0.7,
        overlap=false,
        splines=true,
        sep="+0.25"
    ];
    node [shape=box, style="rounded,filled", fillcolor="#F0F4FF", fontname="Segoe UI", fontsize=11];
    edge [color="#555555", arrowsize=0.8];

    subgraph cluster_frontend {
        label="Frontend Layer";
        style=filled;
        fillcolor="#E8F4F8";
        color="#5A9FD4";

        WebUI [label="Web UI"];
        MobileApp [label="Mobile App"];
    }

    subgraph cluster_api {
        label="API Gateway Layer";
        style=filled;
        fillcolor="#FFF4E6";
        color="#E8A87C";

        Gateway [label="API Gateway"];
        LoadBalancer [label="Load Balancer"];
    }

    subgraph cluster_services {
        label="Microservices Layer";
        style=filled;
        fillcolor="#F0F8E8";
        color="#90C290";

        AuthService [label="Auth Service"];
        UserService [label="User Service"];
        OrderService [label="Order Service"];
        PaymentService [label="Payment Service"];
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        fillcolor="#F5F5F5";
        color="#999999";

        UsersDB [shape=cylinder, fillcolor="#D0E8FF", label="Users DB"];
        OrdersDB [shape=cylinder, fillcolor="#D0E8FF", label="Orders DB"];
        Cache [shape=box, fillcolor="#FFE8D0", label="Redis Cache"];
    }

    // Frontend zum Gateway
    WebUI -> LoadBalancer [label="HTTPS"];
    MobileApp -> LoadBalancer [label="HTTPS"];

    // Gateway zu den Services
    LoadBalancer -> Gateway;
    Gateway -> AuthService [label="gRPC"];
    Gateway -> UserService [label="REST"];
    Gateway -> OrderService [label="REST"];

    // Abhängigkeiten zwischen Services
    OrderService -> PaymentService [label="API call"];
    UserService -> AuthService [label="validate"];
    PaymentService -> AuthService [label="validate"];

    // Datenzugriff
    AuthService -> UsersDB;
    UserService -> UsersDB;
    UserService -> Cache [style=dashed, label="cache"];
    OrderService -> OrdersDB;
    OrderService -> Cache [style=dashed, label="cache"];
}

Kommandozeile:

dot -Tsvg overlap_complete.dot -o overlap_complete.svg

Komplettes Schichtensystem von Web-UI und Load Balancer über Gateway und Services bis zu den Datenbanken

Was dieses Beispiel zeigt:

  • overlap=false: keine Überlappungen zwischen Knoten, selbst mit 13 Knoten und 4 Clustern
  • splines=true: geschwungene Pfeile, die Knoten und Labels elegant ausweichen
  • sep="+0.25": zusätzlicher Abstand, der alles lesbar hält
  • ranksep=1.0, nodesep=0.7: großzügige Abstände zwischen Schichten und Knoten
  • Farbige Cluster: Jede Schicht hat eine eigene Farbe und ist sofort erkennbar
  • Labels an den Kanten: Protokolle (HTTPS, gRPC, REST) und Verbindungsart explizit
  • Gestrichelter Stil für den Cache: optionale Abhängigkeiten anders dargestellt
  • Zylinderform für DBs: Datenbanken sofort erkennbar

Das ist die ideale Vorlage, um komplexe Architekturen professionell und lesbar zu dokumentieren.


Color Schemes: professionelle Paletten, sofort einsatzbereit

Graphviz enthält vordefinierte Color Schemes auf Basis der professionellen Paletten von ColorBrewer. Statt die Farben von Hand auszuwählen, kannst du Paletten verwenden, die auf Lesbarkeit, Barrierefreiheit und professionelle Wirkung getestet sind.

Wie Color Schemes funktionieren

Mit dem Attribut colorscheme wählst du eine Palette und verwendest dann statt Hex-Codes die Zahlen 1-9 (oder mehr, je nach Schema):

node [colorscheme=set39, fillcolor=1, color=2];

Die Color Schemes sind in Kategorien gegliedert:

  • Qualitativ (set1, set2, set3, pastel1, pastel2, dark2, paired, accent): für unterschiedliche Kategorien
  • Sequenziell (blues3-9, greens3-9, reds3-9, purples3-9, oranges3-9): für aufsteigende Werte
  • Divergierend (rdylgn3-11, spectral3-11, rdbu3-11): für Daten mit einem Mittelpunkt

Vollständige Referenz: graphviz.org/docs/attrs/colorscheme/

Praxisbeispiele mit professionellen Color Schemes

Jedes Beispiel verwendet dasselbe Diagramm (einen Prozess in 5 Schritten), aber mit unterschiedlichen Paletten. Vergleiche sie und wähle die, die am besten zu deinem Anwendungsfall passt.

Beispiel 1: Set39 (qualitativ, lebhaft)

Hervorragend, um verschiedene Kategorien auseinanderzuhalten, für farbige Präsentationen und Dashboards.

digraph ProcessSet39 {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=set39, fontname=Arial];
    edge [colorscheme=set39, penwidth=2];

    Start [fillcolor=1, label="Start"];
    Validate [fillcolor=2, label="Validate"];
    Process [fillcolor=3, label="Process"];
    Store [fillcolor=4, label="Store"];
    Notify [fillcolor=5, label="Notify"];

    Start -> Validate [color=1];
    Validate -> Process [color=2];
    Process -> Store [color=3];
    Store -> Notify [color=4];
}

Kommandozeile:

dot -Tsvg colorscheme_set39.dot -o colorscheme_set39.svg

Prozess in fünf Schritten, eingefärbt mit dem Brewer-Farbschema set39

Beispiel 2: Pastel19 (qualitativ, sanft)

Pastellfarben für technische Dokumentation, Wikis, Blogartikel. Weniger auffällig, aber auf Dauer angenehmer zu lesen.

digraph ProcessPastel {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=pastel19, fontname=Arial, fontcolor="#333333"];
    edge [colorscheme=dark28, penwidth=2];

    Start [fillcolor=1, label="Start"];
    Validate [fillcolor=3, label="Validate"];
    Process [fillcolor=5, label="Process"];
    Store [fillcolor=7, label="Store"];
    Notify [fillcolor=9, label="Notify"];

    Start -> Validate [color=1];
    Validate -> Process [color=3];
    Process -> Store [color=5];
    Store -> Notify [color=7];
}

Kommandozeile:

dot -Tsvg colorscheme_pastel.dot -o colorscheme_pastel.svg

Prozess in fünf Schritten, eingefärbt mit einem sanften Pastell-Brewer-Farbschema

Beispiel 3: Blues9 (sequenziell, Abstufung)

Ideal, um zunehmende Intensität, Prioritäten oder Reifegrade zu zeigen.

digraph ProcessBlues {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=blues9, fontname=Arial];
    edge [color="#2171B5", penwidth=2];

    Start [fillcolor=2, fontcolor=black, label="Start"];
    Validate [fillcolor=4, fontcolor=white, label="Validate"];
    Process [fillcolor=6, fontcolor=white, label="Process"];
    Store [fillcolor=8, fontcolor=white, label="Store"];
    Notify [fillcolor=9, fontcolor=white, label="Notify"];

    Start -> Validate -> Process -> Store -> Notify;
}

Kommandozeile:

dot -Tsvg colorscheme_blues.dot -o colorscheme_blues.svg

Prozess in fünf Schritten, abgestuft mit dem sequenziellen Farbschema blues

Beispiel 4: RdYlGn9 (divergierend, Ampel)

Perfekt für Zustände wie Erfolg/Warnung/Fehler, Health Checks, Monitoring.

digraph ProcessStatus {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=rdylgn9, fontname=Arial, fontcolor=black];
    edge [penwidth=2, color="#666666"];

    Idle [fillcolor=5, label="Idle\n(neutral)"];
    Starting [fillcolor=7, label="Starting\n(ok)"];
    Running [fillcolor=9, label="Running\n(good)"];
    Warning [fillcolor=4, label="Warning"];
    Error [fillcolor=1, label="Error"];

    Idle -> Starting -> Running;
    Running -> Warning [style=dashed];
    Warning -> Error [style=dashed];
    Running -> Idle [label="stop"];
}

Kommandozeile:

dot -Tsvg colorscheme_rdylgn.dot -o colorscheme_rdylgn.svg

Service-Zustände von Idle bis Error, eingefärbt mit dem Rot-Gelb-Grün-Schema rdylgn

Beispiel 5: Paired12 (qualitativ, Paare)

Verwendet aufeinander abgestimmte Farbpaare. Hervorragend für Vergleiche, A/B-Versionen, Beziehungen.

digraph ProcessPaired {
    graph [rankdir=TB, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=paired12, fontname=Arial];
    edge [colorscheme=paired12, penwidth=2];

    subgraph cluster_v1 {
        label="Version 1.x";
        style=filled;
        fillcolor="#F0F0F0";
        V1_Start [fillcolor=1, label="Start v1"];
        V1_Process [fillcolor=1, label="Process v1"];
        V1_End [fillcolor=1, label="End v1"];
        V1_Start -> V1_Process -> V1_End;
    }

    subgraph cluster_v2 {
        label="Version 2.x";
        style=filled;
        fillcolor="#F8F8F8";
        V2_Start [fillcolor=2, label="Start v2"];
        V2_Process [fillcolor=2, label="Process v2"];
        V2_End [fillcolor=2, label="End v2"];
        V2_Start -> V2_Process -> V2_End;
    }

    V1_Start -> V2_Start [label="upgrade", color=4, style=dashed];
}

Kommandozeile:

dot -Tsvg colorscheme_paired.dot -o colorscheme_paired.svg

Abläufe der Versionen 1.x und 2.x nebeneinander mit dem Farbschema paired

Beispiel 6: Accent8 (qualitativ, starke Kontraste)

Maximaler Kontrast zwischen den Elementen. Um wichtige Unterschiede hervorzuheben.

digraph ProcessAccent {
    graph [rankdir=LR, bgcolor="#F5F5F5"];
    node [shape=box, style="rounded,filled", colorscheme=accent8, fontname=Arial, fontcolor=black];
    edge [colorscheme=accent8, penwidth=2];

    Input [fillcolor=1, label="Input"];
    Parse [fillcolor=2, label="Parse"];
    Transform [fillcolor=3, label="Transform"];
    Validate [fillcolor=4, label="Validate"];
    Output [fillcolor=5, label="Output"];

    Input -> Parse [color=1];
    Parse -> Transform [color=2];
    Transform -> Validate [color=3];
    Validate -> Output [color=4];
    Validate -> Parse [color=6, label="retry", style=dashed];
}

Kommandozeile:

dot -Tsvg colorscheme_accent.dot -o colorscheme_accent.svg

Datenpipeline Input, Parse, Transform, Validate, Output, hervorgehoben mit dem Schema accent

Wann du welches Color Scheme verwendest

SzenarioEmpfohlenes Color Scheme
Unterschiedliche Kategorien, Präsentationenset39, set28, dark28
Technische Dokumentation, Wikispastel19, pastel28
Abstufungen, Prioritäten, Stufenblues9, greens9, purples9, oranges9
Zustände (ok/warning/error)rdylgn9, rdylbu9, spectral9
Vergleiche, A/B-Versionenpaired12, paired11
Maximaler Kontrastaccent8, set39
Barrierefreiheit (Farbenblindheit)set2, dark2 (ColorBrewer safe)

Color Schemes kombinieren

Du kannst für Knoten und Kanten unterschiedliche Schemata verwenden:

node [colorscheme=pastel19, fillcolor=3];
edge [colorscheme=dark28, color=2];

Tipp: Prüfe die Farben immer mit ColorBrewer, um Barrierefreiheit und Druckbarkeit sicherzustellen.


Fortgeschrittene Techniken: Ports, Ranks, Compound Edges

Ports in Records: Verbinde Kanten mit bestimmten Feldern eines Records über die Syntax node:port:

ClassA:field1 -> ClassB:field2;

Knoten auf dieselbe Ebene zwingen: Mit rank=same positionierst du mehrere Knoten auf derselben horizontalen Linie:

{ rank=same; A; B; C; }

Compound Edges zwischen Clustern: Verbinde ganze Cluster statt einzelner Knoten mit lhead und ltail:

edge [lhead=cluster_B, ltail=cluster_A];

Orthogonale Kanten: Kanten mit rechten Winkeln für einen “Architekten”-Stil:

graph [splines=ortho];

Professioneller Stil: praktische Tipps

  • Verwende stimmige Paletten.
  • Vermeide zu grelle Farbverläufe.
  • Verwende Inter, Arial oder Roboto für gute Lesbarkeit.
  • Verwende ortho für “Architekten”-Kanten.
  • Halte angemessene Abstände ein (nodesep, ranksep).
  • Bevorzuge SVG für die Qualität in Blogs.
  • Halte die DOT-Dateien unter Versionskontrolle.

Grafikstile, sofort einsatzbereit

Hier sind 5 Stilvarianten für dasselbe Zustandsdiagramm, bereit zum Kopieren und Anpassen an deine Diagramme. Jeder Stil legt Farben, Schriften, Größen und Formen fest und sorgt für einen einheitlichen Look.

Stil 1: Corporate Blue (professionell, formell)

Blau-graue Palette, Schrift Arial, aufgeräumter Stil für Unternehmenspräsentationen.

digraph CorporateBlue {
    graph [
        rankdir=LR,
        bgcolor="#F8F9FA",
        fontname="Segoe UI",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#E3F2FD",
        color="#1976D2",
        fontname="Segoe UI",
        fontsize=11,
        fontcolor="#1565C0",
        penwidth=2
    ];
    edge [
        color="#1976D2",
        fontname="Segoe UI",
        fontsize=10,
        fontcolor="#424242"
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Kommandozeile:

dot -Tsvg style_corporate.dot -o style_corporate.svg

Zustandsautomat Idle, Processing und Complete im Stil Corporate Blue

Stil 2: Dark Mode (modern, technisch)

Dunkler Hintergrund, heller Text, grün-cyanfarbene Palette für moderne UIs und Entwicklerwerkzeuge.

digraph DarkMode {
    graph [
        rankdir=LR,
        bgcolor="#1E1E1E",
        fontname="Consolas",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#2D2D30",
        color="#00D9FF",
        fontname="Consolas",
        fontsize=11,
        fontcolor="#E0E0E0",
        penwidth=2
    ];
    edge [
        color="#00D9FF",
        fontname="Consolas",
        fontsize=10,
        fontcolor="#B0B0B0"
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Kommandozeile:

dot -Tsvg style_dark.dot -o style_dark.svg

Derselbe Zustandsautomat im dunklen Theme auf dunkelgrauem Hintergrund

Stil 3: Warm Minimal (sanft, gut lesbar)

Warme Orange-Beige-Palette, serifenlose Schrift, hervorragend für technische Dokumentation.

digraph WarmMinimal {
    graph [
        rankdir=LR,
        bgcolor="#FFFBF5",
        fontname="Segoe UI",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#FFE8CC",
        color="#FF8C42",
        fontname="Segoe UI",
        fontsize=11,
        fontcolor="#6B4423",
        penwidth=1.5
    ];
    edge [
        color="#FF8C42",
        fontname="Segoe UI",
        fontsize=10,
        fontcolor="#8B5A3C",
        penwidth=1.5
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Kommandozeile:

dot -Tsvg style_warm.dot -o style_warm.svg

Derselbe Zustandsautomat im warmen Stil mit Orangetönen

Stil 4: Monochrome (elegant, druckfreundlich)

Schwarz-weiß mit Graustufen, perfekt für den Druck und formelle Dokumentation.

digraph Monochrome {
    graph [
        rankdir=LR,
        bgcolor="white",
        fontname="Segoe UI",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#F5F5F5",
        color="#333333",
        fontname="Segoe UI",
        fontsize=11,
        fontcolor="#000000",
        penwidth=2
    ];
    edge [
        color="#333333",
        fontname="Segoe UI",
        fontsize=10,
        fontcolor="#666666",
        penwidth=1.5
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Kommandozeile:

dot -Tsvg style_mono.dot -o style_mono.svg

Derselbe Zustandsautomat im monochromen Stil, nur in Grau und Schwarz

Stil 5: Vibrant Gradient (kreativ, auffällig)

Lebhafte Farben mit Farbverläufen, hervorragend für Präsentationen und optisch ansprechende Folien.

digraph VibrantGradient {
    graph [
        rankdir=LR,
        bgcolor="#FAFAFA",
        fontname="Segoe UI",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#A8E6CF:#56CCF2",
        gradientangle=90,
        color="#2D6A9F",
        fontname="Segoe UI",
        fontsize=11,
        fontcolor="#1A3A52",
        penwidth=2.5
    ];
    edge [
        color="#9B59B6",
        fontname="Segoe UI",
        fontsize=10,
        fontcolor="#5B3A72",
        penwidth=2
    ];

    Idle [label="Idle"];
    Processing [label="Processing", fillcolor="#FFD93D:#FF6B9D", gradientangle=90];
    Complete [label="Complete", fillcolor="#6BCF7F:#4ECDC4", gradientangle=90];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Kommandozeile:

dot -Tsvg style_vibrant.dot -o style_vibrant.svg

Derselbe Zustandsautomat im lebhaften Stil mit satten Farben

So verwendest du diese Stile

Kopiere den Block graph, node, edge des Stils, der dir gefällt, und wende ihn auf deine Diagramme an. Anpassen kannst du dann:

  • Farben: Ersetze die Hex-Codes durch deine Palette
  • Schriften: Verwende fontname="FontName" (Arial, Helvetica, Courier, Times, Verdana, Consolas)
  • Größen: fontsize für den Text, penwidth für die Stärke von Rändern und Pfeilen
  • Form: box, ellipse, circle, diamond, cylinder, record
  • Farbverläufe: Verwende fillcolor="color1:color2" mit gradientangle (nur bei manchen Ausgabeformaten)

Hinweise zur Schriftkompatibilität

Die Schriften müssen auf dem System installiert sein, auf dem du die Bilder erzeugst:

  • Universelle Schriften (funktionieren überall): Arial, Helvetica, Times, Times-Roman, Courier
  • Moderne Schriften (Verfügbarkeit prüfen): Verdana, Consolas, Roboto, Inter
  • Windows: Die meisten Schriften sind bereits installiert
  • macOS: Hervorragende Unterstützung für die Standardschriften
  • Linux: Installiere fonts-liberation oder fonts-dejavu, um Entsprechungen zu Arial/Helvetica zu haben
  • CI/CD: Verwende Basisschriften oder nimm die Schriften in den Docker-Container auf

Ist eine Schrift nicht verfügbar, greift Graphviz auf einen Fallback zurück (meist Times). Um sicherzugehen, verwende immer Basisschriften oder teste die Erzeugung in der Produktionsumgebung.


Workflow: Graphviz in die echte Arbeit integrieren

  1. Lege die .gv-Dateien ins Repository.

  2. Erzeuge die SVGs automatisch in der CI:

    dot -Tsvg diagram.gv -o diagram.svg
    
  3. Binde die SVGs in die Dokumentation ein (README, Wiki, Blog).

  4. Aktualisiere die Diagramme bei jedem Refactoring.

  5. Nutze Diff und Versionierung der DOT-Dateien wie beim Code.


Troubleshooting: häufige Fehler und Lösungen

Fehler: “syntax error in line X near…”

  • Ursache: Ungültige DOT-Syntax
  • Lösung: Prüfe auf fehlende Semikolons, nicht geschlossene Klammern, nicht passende Anführungszeichen
  • Beispiel: A -> B muss mit ; enden → A -> B;

Fehler: “Warning: Unable to find font…”

  • Ursache: Die angegebene Schrift ist auf dem System nicht installiert
  • Lösung: Verwende universelle Schriften (Arial, Helvetica, Times) oder installiere die benötigte Schrift
  • Verfügbare Schriften prüfen: dot -v zeigt die verfügbaren Schriften

Das Diagramm ist zu groß/klein

  • Lösung 1: Füge graph [size="8,6"] hinzu, um die Abmessungen zu begrenzen (in Zoll)
  • Lösung 2: Verwende graph [ratio=compress], um automatisch zu komprimieren
  • Lösung 3: Erzeuge ein PNG mit eigener DPI: dot -Tpng -Gdpi=150 file.dot -o file.png

Pfeile überlappen Knoten

  • Lösung: Füge graph [overlap=false, splines=true] hinzu (siehe Abschnitt “Überlappungen vermeiden”)

Die Knoten sind alle horizontal statt vertikal ausgerichtet

  • Lösung: Verwende graph [rankdir=TB] für oben nach unten (Standard ist LR = links nach rechts)

Der Cluster erscheint nicht

  • Ursache: Der Name des Clusters beginnt nicht mit cluster_
  • Lösung: Benenne subgraph mygroup in subgraph cluster_mygroup um

SVG-Ausgabe zu groß (Dateigröße)

  • Ursache: SVG mit vielen Elementen
  • Lösung 1: Verwende PNG statt SVG für sehr komplexe Graphen
  • Lösung 2: Optimiere mit svgo: svgo input.svg -o output.svg

Der Graph wird nicht erzeugt (keine Ausgabe, kein Fehler)

  • Ursache: Falscher Befehl oder falsche Umleitung
  • Prüfen: Verwende -v für die ausführliche Ausgabe: dot -v -Tsvg input.dot -o output.svg
  • Schnelltest: echo "digraph{A->B}" | dot -Tsvg > test.svg

Die Labels der Kanten sind nicht sichtbar

  • Ursache: Labels zu lang oder Schrift zu klein
  • Lösung: Erhöhe fontsize an den Kanten oder verwende \n, um die Labels auf mehrere Zeilen umzubrechen

Best Practices für sauberen DOT-Code

Don’t Repeat Yourself (DRY)

Definiere Attribute einmal auf oberster Ebene, statt sie bei jedem Element zu wiederholen.

❌ Schlecht (repetitiv):

digraph {
    node [fontname="Segoe UI"];
    A [fontname="Segoe UI", shape=box];
    B [fontname="Segoe UI", shape=box];
    C [fontname="Segoe UI", shape=box];
}

✅ Gut (DRY):

digraph {
    // Einmal definieren, gilt für alle
    graph [fontname="Segoe UI"];
    node [fontname="Segoe UI", shape=box];
    edge [fontname="Segoe UI"];

    A; B; C;  // Erben alle Attribute
}

Grundprinzip: Verwende die Deklarationen graph, node und edge, um Standardwerte zu setzen. Überschreibe sie nur, wenn ein bestimmtes Element andere Attribute braucht.

Kommentare verwenden

Füge Kommentare hinzu, um komplexe Abschnitte zu erklären:

digraph {
    // Globales Styling
    graph [rankdir=LR, fontname="Segoe UI"];

    // Kernkomponenten
    A -> B;

    // Pfad der Fehlerbehandlung
    B -> Error [style=dashed, color=red];
}

Große Graphen organisieren

Gruppiere zusammengehörige Deklarationen:

digraph {
    // === Konfiguration ===
    graph [rankdir=TB];
    node [shape=box];

    // === Services ===
    ServiceA; ServiceB; ServiceC;

    // === Datenbanken ===
    DB1 [shape=cylinder];
    DB2 [shape=cylinder];

    // === Verbindungen ===
    ServiceA -> DB1;
    ServiceB -> DB2;
}

DOT-Vorlagen + Graphviz-Befehle (CLI)

Jede Vorlage enthält:

  1. das DOT-Snippet

  2. den CLI-Befehl zum Erzeugen des Bildes

Der Einheitlichkeit halber verwende ich das Format SVG, aber du kannst -Tsvg ersetzen durch:

  • -Tpng
  • -Tpdf
  • -Tjpg
  • -Tgif

Den DOT-Input kannst du in template.dot speichern oder per Pipe übergeben.


Flussdiagramm

Vorlage 1: Einfacher Prozess

digraph FlowBasic {
    graph [rankdir=TB];
    node [shape=rectangle, style=rounded, fontsize=12];

    Start [label="Start", shape=circle];
    Step1 [label="Input validation"];
    Step2 [label="Process request"];
    Step3 [label="Persist data"];
    End [label="End", shape=doublecircle];

    Start -> Step1 -> Step2 -> Step3 -> End;
}

Kommandozeile:

dot -Tsvg FlowBasic.dot -o FlowBasic.svg

Ausgabe der Vorlage: linearer Prozess vom Start über Validierung und Persistenz bis zum Ende

Vorlage 2: Verzweigung (if/else)

digraph FlowIfElse {
    graph [rankdir=TB];
    node [fontsize=12, style=rounded];

    Start [shape=circle];
    Check [shape=diamond, label="Is valid?"];
    A [label="Handle valid case"];
    B [label="Handle error"];
    End [shape=doublecircle];

    Start -> Check;
    Check -> A [label="Yes"];
    Check -> B [label="No"];
    A -> End;
    B -> End;
}

Kommandozeile:

dot -Tsvg FlowIfElse.dot -o FlowIfElse.svg

Ausgabe der Vorlage: if/else-Flussdiagramm mit einer Gültigkeitsraute und zwei Zweigen

Vorlage 3: Prozess mit Abschnitten

digraph FlowSections {
    graph [rankdir=TB];
    node [fontsize=11, style=rounded];

    subgraph cluster_input {
        label="Input Stage";
        color=lightgrey;
        style=filled;

        A1 [label="Receive request"];
        A2 [label="Validate payload"];
        A1 -> A2;
    }

    subgraph cluster_processing {
        label="Processing Stage";
        color=lightblue;
        style=filled;

        P1 [label="Transform data"];
        P2 [label="Apply business rules"];
        P1 -> P2;
    }

    subgraph cluster_output {
        label="Output Stage";
        color=lightyellow;
        style=filled;

        O1 [label="Persist"];
        O2 [label="Return response"];
        O1 -> O2;
    }

    A2 -> P1 -> O1;
}

Kommandozeile:

dot -Tsvg FlowSections.dot -o FlowSections.svg

Ausgabe der Vorlage: Verarbeitung einer Anfrage, aufgeteilt in die Cluster Input, Processing und Output

Zustandsautomat

Vorlage 4: Einfacher Zustandsautomat

digraph StateMachine {
    graph [rankdir=LR];
    node [shape=circle, fontsize=12];

    Idle;
    Loading;
    Error;
    Success;

    Idle -> Loading [label="start"];
    Loading -> Success [label="ok"];
    Loading -> Error [label="fail"];
    Error -> Idle [label="retry"];
}

Kommandozeile:

dot -Tsvg StateMachine.dot -o StateMachine.svg

Ausgabe der Vorlage: Zustandsautomat mit Idle, Loading, Success, Error und Retry

Vorlage 5: Verschachtelte Zustände

digraph NestedStates {
    graph [rankdir=LR];
    node [fontsize=11];

    subgraph cluster_ready {
        label="Ready state";
        style=dashed;
        R1 [shape=circle, label="Idle"];
        R2 [shape=circle, label="Primed"];
        R1 -> R2 [label="prepare"];
    }

    subgraph cluster_active {
        label="Active state";
        style=dashed;
        A1 [shape=circle, label="Running"];
        A2 [shape=circle, label="Paused"];
        A1 -> A2 [label="pause"];
        A2 -> A1 [label="resume"];
    }

    R2 -> A1 [label="activate"];
}

Kommandozeile:

dot -Tsvg NestedStates.dot -o NestedStates.svg

Ausgabe der Vorlage: verschachtelte Zustände, Cluster Ready und Active mit pause und resume

Sequenzdiagramm (DOT)

Vorlage 6: Horizontale Sequenz

digraph Sequence {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    Client -> API [label="POST /login"];
    API -> AuthService [label="Check credentials"];
    AuthService -> DB [label="Query user"];
    DB -> AuthService [label="Result"];
    AuthService -> API [label="Token"];
    API -> Client [label="200 OK"];
}

Kommandozeile:

dot -Tsvg Sequence.dot -o Sequence.svg

Ausgabe der Vorlage: horizontale Login-Sequenz zwischen Client, API, AuthService und DB

Vorlage 7: Sequenz mit Aktivierungen

digraph SequenceActivation {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    User -> Frontend [label="Login"];
    Frontend -> Backend [label="POST /login"];
    Backend -> Backend [label="validate()"];
    Backend -> DB [label="SELECT user"];
    DB -> Backend [label="row found"];
    Backend -> Frontend [label="JWT"];
    Frontend -> User [label="Welcome"];
}

Kommandozeile:

dot -Tsvg SequenceActivation.dot -o SequenceActivation.svg

Ausgabe der Vorlage: Login-Sequenz mit Aktivierungen über User, Frontend, Backend und DB

Abhängigkeitsgraph

Vorlage 8: Module

digraph DependencyTree {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=12];

    App -> ModuleA;
    App -> ModuleB;
    ModuleA -> LibA;
    ModuleA -> LibB;
    ModuleB -> LibB;
}

Kommandozeile:

dot -Tsvg DependencyTree.dot -o DependencyTree.svg

Ausgabe der Vorlage: Abhängigkeitsbaum der Module von App zu Modulen und Bibliotheken

Vorlage 9: Microservices

digraph MicroservicesDep {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Gateway -> Auth;
    Gateway -> Orders;
    Auth -> UsersDB;
    Orders -> ProductsService;
    Orders -> Payments;
    Payments -> BankAPI;
}

Kommandozeile:

dot -Tsvg MicroservicesDep.dot -o MicroservicesDep.svg

Ausgabe der Vorlage: Abhängigkeiten der Microservices vom Gateway zu Auth, Orders, Payments und Bank-API

Architekturdiagramm

Vorlage 10: Schichten

digraph Layered {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=12];

    subgraph cluster_presentation {
        label="Presentation Layer";
        style=filled;
        color=lightyellow;
        UI;
        API;
    }

    subgraph cluster_business {
        label="Business Layer";
        style=filled;
        color=lightblue;
        Services;
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        color=lightgrey;
        DB;
        Cache;
    }

    UI -> API -> Services -> DB;
    Services -> Cache;
}

Kommandozeile:

dot -Tsvg Layered.dot -o Layered.svg

Ausgabe der Vorlage: Schichtenarchitektur mit UI, API, Services, Datenbank und Cache

Vorlage 11: Hexagonal

digraph Hexagonal {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    AppCore [label="Core Domain"];
    PortIn [label="Inbound Ports"];
    PortOut [label="Outbound Ports"];
    AdapterIn [label="Inbound Adapters"];
    AdapterOut [label="Outbound Adapters"];
    DB [label="Database"];
    UI [label="Frontend/UI"];

    UI -> AdapterIn -> PortIn -> AppCore;
    AppCore -> PortOut -> AdapterOut -> DB;
}

Kommandozeile:

dot -Tsvg Hexagonal.dot -o Hexagonal.svg

Ausgabe der Vorlage: hexagonale Architektur mit Core Domain, Ports und Adaptern

ER-Diagramme

Vorlage 12: 1:N

digraph ER_OneToMany {
    graph [rankdir=LR];
    node [shape=record, fontsize=11];

    User [label="{User|id PK|name|email}"];
    Order [label="{Order|id PK|user_id FK|total}"];

    User -> Order [label="1:N"];
}

Kommandozeile:

dot -Tsvg ER_OneToMany.dot -o ER_OneToMany.svg

Ausgabe der Vorlage: ER-Diagramm von User und Order in einer 1:N-Beziehung

Vorlage 13: N:N

digraph ER_ManyToMany {
    graph [rankdir=LR];
    node [shape=record, fontsize=11];

    Student [label="{Student|id PK|name}"];
    Course [label="{Course|id PK|title}"];
    Enroll [label="{Enroll|student_id FK|course_id FK}"];

    Student -> Enroll;
    Course -> Enroll;
}

Kommandozeile:

dot -Tsvg ER_ManyToMany.dot -o ER_ManyToMany.svg

Ausgabe der Vorlage: N:N-Beziehung zwischen Student und Course über eine Tabelle Enroll

Call Graph

Vorlage 14: Einfach

digraph CallGraph {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=11];

    main -> init;
    main -> loadConfig;
    loadConfig -> readFile;
    readFile -> parseJson;
}

Kommandozeile:

dot -Tsvg CallGraph.dot -o CallGraph.svg

Ausgabe der Vorlage: Call Graph von main zu init, loadConfig, readFile und parseJson

Vorlage 15: Mit Kategorien

digraph CategorizedCalls {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=11];

    subgraph cluster_io {
        label="I/O Functions";
        color=lightgrey;
        readFile;
        writeFile;
    }

    subgraph cluster_logic {
        label="Business Logic";
        color=lightblue;
        compute;
        validate;
    }

    main -> compute -> validate;
    compute -> readFile;
    validate -> writeFile;
}

Kommandozeile:

dot -Tsvg CategorizedCalls.dot -o CategorizedCalls.svg

Ausgabe der Vorlage: Call Graph mit I/O-Funktionen und Geschäftslogik in getrennten Clustern

Netzwerkdiagramm

Vorlage 16: Einfach

digraph Network {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Client -> LoadBalancer;
    LoadBalancer -> AppServer1;
    LoadBalancer -> AppServer2;
    AppServer1 -> DB;
    AppServer2 -> DB;
}

Kommandozeile:

dot -Tsvg Network.dot -o Network.svg

Ausgabe der Vorlage: Netzwerk vom Client über den Load Balancer zu zwei App-Servern und der DB

Vorlage 17: Mit Protokollen

digraph NetworkProto {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    Client -> API [label="HTTPS"];
    API -> Auth [label="gRPC"];
    API -> Orders [label="REST"];
    Orders -> DB [label="TCP"];
}

Kommandozeile:

dot -Tsvg NetworkProto.dot -o NetworkProto.svg

Ausgabe der Vorlage: Netzwerkkanten, beschriftet mit den Protokollen HTTPS, gRPC, REST und TCP

Timeline / Roadmap

Vorlage 18: Timeline

digraph Timeline {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Start -> Milestone1 -> Milestone2 -> Milestone3 -> Release;
}

Kommandozeile:

dot -Tsvg Timeline.dot -o Timeline.svg

Ausgabe der Vorlage: Projekt-Timeline vom Start über drei Meilensteine bis zum Release

Vorlage 19: Roadmap

digraph Roadmap {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    subgraph cluster_backend {
        label="Backend";
        B1 [label="Auth module"];
        B2 [label="Payments"];
    }

    subgraph cluster_frontend {
        label="Frontend";
        F1 [label="Login UI"];
        F2 [label="Dashboard"];
    }

    B1 -> B2;
    F1 -> F2;
}

Kommandozeile:

dot -Tsvg Roadmap.dot -o Roadmap.svg

Ausgabe der Vorlage: Roadmap mit Backend- und Frontend-Strang, Auth, Payments, Login-UI, Dashboard

Mindmap

Vorlage 20: Mindmap

graph MindMap {
    layout=twopi;
    rankdir=LR;
    node [shape=box, style=rounded, fontsize=11];

    Central -- Idea1;
    Central -- Idea2;
    Central -- Idea3;
    Idea2 -- Sub1;
    Idea2 -- Sub2;
}

Kommandozeile:

dot -Ktwopi -Tsvg MindMap.dot -o MindMap.svg

Ausgabe der Vorlage: radiale Mindmap mit einem zentralen Knoten, drei Ideen und Unterideen

Komponentendiagramm

Vorlage 21: Komponenten

digraph Components {
    graph [rankdir=LR];
    node [shape=component, fontsize=11];

    UI -> API;
    API -> Service;
    Service -> DB;
}

Kommandozeile:

dot -Tsvg Components.dot -o Components.svg

Ausgabe der Vorlage: Komponentendiagramm, das UI, API, Service und Datenbank verkettet

Klassendiagramm

Vorlage 22: UML-ähnliche Klassen

digraph Classes {
    graph [rankdir=TB];
    node [shape=record, fontsize=11];

    Person [label="{Person|name:string|age:int}"];
    Student [label="{Student|grade:int}"];
    Person -> Student;
}

Kommandozeile:

dot -Tsvg Classes.dot -o Classes.svg

Ausgabe der Vorlage: UML-ähnliches Klassendiagramm, in dem Student von Person erbt

Layouts

Vorlage 23: Horizontal

digraph Horizontal {
    graph [rankdir=LR];
    node [shape=box, style=rounded];
}

Kommandozeile:

dot -Tsvg Horizontal.dot -o Horizontal.svg

Ausgabe der Vorlage: leeres Grundgerüst von links nach rechts, bereit für die Knoten

Vorlage 24: Vertikal

digraph Vertical {
    graph [rankdir=TB];
    node [shape=box, style=rounded];
}

Kommandozeile:

dot -Tsvg Vertical.dot -o Vertical.svg

Ausgabe der Vorlage: leeres Grundgerüst von oben nach unten, bereit für die Knoten

Vorlage 25: Kreisförmig

graph Circular {
    layout=circo;
    node [shape=box, style=rounded];
}

Kommandozeile:

dot -Kcirco -Tsvg Circular.dot -o Circular.svg

Ausgabe der Vorlage: leeres Grundgerüst mit circo-Layout, bereit für die Knoten

Professionelle Stile

Vorlage 26: Modernes Theme

digraph Modern {
    graph [rankdir=LR];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#eef3f8",
        color="#6a8bbf",
        fontsize=11
    ];
    edge [color="#6a8bbf"];

    A -> B -> C;
}

Kommandozeile:

dot -Tsvg Modern.dot -o Modern.svg

Ausgabe der Vorlage: drei Knoten A, B, C im modernen Theme, abgerundet und gefüllt

Vorlage 27: Dark Theme

digraph Dark {
    bgcolor="#1e1e1e";
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#333333",
        fontcolor="white",
        color="#777777",
        fontsize=11
    ];
    edge [color="#999999"];

    A -> B -> C;
}

Kommandozeile:

dot -Tsvg Dark.dot -o Dark.svg

Ausgabe der Vorlage: drei Knoten A, B, C im dunklen Theme auf dunklem Hintergrund


Nützliche Ressourcen

Offizielle Dokumentation

Online-Werkzeuge

Integrationen und Bibliotheken

  • Graphviz Visual Editor (VSCode): Erweiterung für die Live-Vorschau in Visual Studio Code
  • PlantUML: plantuml.com: verwendet Graphviz für das UML-Rendering
  • Mermaid: mermaid.js.org: JavaScript-basierte Alternative zu Graphviz für Graphen in Markdown
  • Python graphviz: graphviz.readthedocs.io: Python-Bibliothek, um Graphen programmatisch zu erzeugen
  • Go graphviz: github.com/goccy/go-graphviz: Go-Binding für Graphviz

Galerie und Beispiele

Community und Support

Ergänzende Werkzeuge


FAQ: häufige Fragen zu DOT und Graphviz

Wie erstelle ich ein Diagramm mit Graphviz?

Lege eine Datei mit der Endung .dot an, die die Beschreibung des Graphen enthält, und führe dann dot -Tsvg file.dot -o output.svg aus. Der Befehl erzeugt aus dem DOT-Code ein SVG-Bild.

Was ist der Unterschied zwischen digraph und graph in DOT?

digraph erzeugt einen gerichteten Graphen (mit Pfeilen), graph einen ungerichteten Graphen (mit Linien ohne Pfeilspitzen). Verwende -> für gerichtete Kanten, -- für ungerichtete.

Wie ändere ich die Layoutrichtung in Graphviz?

Verwende das Attribut rankdir: TB (oben nach unten, Standard), BT (unten nach oben), LR (links nach rechts), RL (rechts nach links). Beispiel: graph [rankdir=LR];

Wie erstelle ich in DOT ein Flussdiagramm mit Entscheidungsrauten?

Verwende shape=diamond für die Entscheidungsknoten: Decision [shape=diamond, label="Valid?"];

Wie gruppiere ich Knoten in Graphviz in einem Kasten (Cluster)?

Verwende subgraph cluster_name { ... }. Das Präfix cluster_ ist Pflicht, damit die Gruppierung angezeigt wird.

Wie erstelle ich ER-Diagramme (Entity-Relationship) mit DOT?

Verwende shape=plaintext mit HTML-Labels für strukturierte Tabellen und arrowhead=crow für 1:N-Beziehungen.

Wie vermeide ich in Graphviz Überlappungen zwischen Pfeilen und Knoten?

Füge graph [overlap=false, splines=true, sep="+0.2"]; hinzu, um Kollisionen zu vermeiden.

Welche Layout-Engine ist die beste für mein Diagramm?

  • dot: Flussdiagramme, Pipelines, Hierarchien (Standard)
  • neato/fdp: ungerichtete Graphen, Concept Maps
  • circo: Hub-and-Spoke-Strukturen
  • twopi: radiale Bäume, Organigramme

Wie erzeuge ich mit Graphviz PNG statt SVG?

Ändere das Flag -T: dot -Tpng file.dot -o output.png. Du kannst auch die DPI angeben: dot -Tpng -Gdpi=150.

Kann ich Graphviz online verwenden, ohne es zu installieren?

Ja! Verwende edotor.net oder GraphvizOnline, um DOT-Code im Browser zu testen.

Wie integriere ich Graphviz in meine CI/CD-Pipeline?

Installiere Graphviz in deiner CI-Umgebung (z. B. apt install graphviz in Docker) und füge dann einen Schritt hinzu, der dot -Tsvg *.dot ausführt. Versioniere die .dot-Dateien und erzeuge die Bilder automatisch.

Wie erstelle ich Zustandsdiagramme (Zustandsautomaten) mit DOT?

Verwende shape=circle für die Zustände, shape=point für den Anfangszustand und shape=doublecircle für den Endzustand. Beschrifte die Kanten mit den Ereignissen: Idle -> Loading [label="start"];

Wie wende ich denselben Stil auf mehrere Knoten an, ohne ihn zu wiederholen?

Liste die Knoten in derselben Zeile auf, gefolgt von den Attributen: A; B; C [shape=box, fillcolor=lightblue, style=filled];

Unterstützt DOT HEX-Farben?

Ja! Verwende HEX-Codes wie fillcolor="#E3F2FD" oder vordefinierte Namen wie fillcolor=lightblue.

Wie erstelle ich UML-Diagramme mit Graphviz?

Verwende shape=record für Klassendiagramme: Class [label="{ClassName|attribute:type|method()}"];. Für vollständiges UML lohnt sich ein Blick auf PlantUML, das intern Graphviz verwendet.


Artikel von Daniele Teti, danieleteti.it

Comments