Fortgeschrittenes Tutorial (knapp)
Dieses Tutorial ist für dich geeignet, wenn du dich bereits mit Python auskennst und nur schnell wissen möchtest, was die grundsätzliche Idee ist bzw. wie der Workflow aussieht. Wir werfen außerdem einen kurzen Blick in networkx.
1. Setup
- Installier networkx und dsstools (empfohlen über pip)
- Wir nutzen folgende Aliase
2. Networkx (knapp)
Falls du networkx noch nicht kennst, sieh dazu Abschnitt 1 im Einstiegstutorial und networkx Dokumentation.
Im Schnelldurchlauf/zur Erinnerung:
- Es gibt immer einen Graph
graph = nx.Graph()
- Dieser hat Nodes
graph.add_nodes_from(["A", "B", "C", "D"])
- Die mit Edges verbunden sind
graph.add_edges_from([("A", "B"), ("B", "C"), ("C", "D"), ("D", "A")])
Die Nodes und Edges können dann verschiedene Eigenschaften haben, die man dann visualisieren möchte. Hier kommt
dsstools
ins Spiel.
3. Verarbeitung: Positionen festlegen
Hier legen wir die Positionen der Nodes in der visuellen Darstellung des Graphen fest. Dafür gibt es zwei Möglichkeiten:
NetworkX
: Einfach und bereits installiert.Graphviz
: Fortgeschritten und benötigt unter Windows eine komplizierte Installation. Sie liefert allerdings bessere Positionierungen.
In diesem Beispiel werden wird dementsprechend die Positionierung mit
NetworkX
verwenden. Das funktioniert wie folgt:
layouter = dts.Layouter()
positions = layouter.read_or_create_layout("positions.json", graph, seed=1234, k=1)
positions
) nimmt vier Parameter entgegen:
- Den Pfad, in den die Positionsdatei geschrieben wird,
- den Graphen selbst und
- einen sog. Seed. Der Seed bestimmt dabei die "Zufälligkeit" der Erzeugung.
k
ist für das genutzte Layout relevant und bestimmt die optimale Distanz zwischen Knoten. Falls Knoten zu eng beieinander liegen, kann eine Erhöhung dieses Wertes zu besseren Abbildungen führen.
Zudem gibt die Methode ein Dictionary der gespeicherten Positionen zurück. Existiert am angegeben Pfad bereits eine Datei mit diesem Namen, wird sie entsprechend eingelesen und es wird keine neue erzeugt.
4. Erzeugung von Abbildungen
Das nun erstellte Layout nutzen wir für die Visualisierung.
Dazu nutzen wir den dts.ImageGenerator
:
Hinweis
Im Setzen der Positionen mittels image_generator.nodes.set_positions()
kann entweder das Dict
oder der Pfad zur Positionsdatei übergeben werden. Die Datei wird
deshalb erstellt, damit innerhalb von Teams die Position festgelegt und
über Git getrackt werden kann.
Nun können wir einzelne Einstellungen auswählen. Bspw. könnten wir alle Kanten grau einfärben:
Für die Einfärbung von Knoten entlang eines vorhandenen, codierten Attributes durch qualitative mapping. Andere mappings wie filter, was eigene Expressions zulässt, wären z. B. auch möglich:
Woher kommen die Attribute?
Die Attribute entlang derer wir codieren, sind die, die man in networkx
festlegen kann: graph.nodes["A"]["Attribute1"] = "Wert 1"
. Im Workflow mit dsstools
kommen diese dann normalerweise aus den verschiedenen textsearch Funktionen.
Die Größe der Knoten möchten wir entlang des Degree skalieren (Degree ist dabei ein Stichwort, welches die Berechnung des Degrees intern anstößt). Die outrange
definiert wie groß der kleinste und größte Knoten maximal sein können:
# Auch hier wären andere mappings möglich
image_generator.nodes.set_sizes(dts.sequential("degree", out_range=(100, 500)))
An dieser Stelle möchten wir dich gerne dazu ermutigen, einen tieferen Blick in die verschiedenen Mapping-Strategien zu werfen.
dsstools
bietet noch viele weitere komplexere Möglichkeiten zur Visualisierung von Graphen, die du hier erkunden kannst.
Hinweis
Es funktionieren ebenfalls indegree
, outdegree
, betweenness
, closeness
als automatisch zu berechnende Stichwörter.
Zuletzt wird die Abbildung gezeichnet und dann in eine Datei geschrieben:
Hinweis
Das Gleiche lässt sich auch in einem Aufwasch schreiben:
image_generator = dts.ImageGenerator(graph)
(
image_generator.nodes.set_positions(positions)
.set_colors(dts.qualitative("Unser Attribute", cmap="Set2"))
.set_sizes(dts.sequential("degree", out_range=(100, 500)))
)
image_generator.edges.set_colors("grey")
image_generator.draw().write_file("./abbildung.svg")
5. Anwendungsbeispiel: Ein Workflow
Hier einmal ein Beispiel, was dsstools bringen kann bei einem großen Graphen, wie du ihn bestimmt selber haben wirst.
Schritt 1: Einlesen eines bestehenden Graphen
Für das Einlesen bieten sich mehrere Optionen an, sowohl in dssTools
als auch in
NetworkX
. Da es sich hier um ein einfaches Beispiel handelt, wollen wir ein
vorgefertigtes Netzwerk nutzen. Lade dafür diese
Datei herunter und
speichere sie entsprechend.
Schritt 2: Erstellung des Layouts und setzen der Positionen
import networkx as nx
import dsstools as dts
layouter = dts.Layouter()
positions = layouter.read_or_create_layout("positions.json", graph, seed=1234, k=1)
# Erzeuge ein ImageGenerator-Objekt. Ein ImageGenerator erzeugt mit einem Graph und
# verschieden Einstellungen eine (!) Abbildung.
image_generator = dts.ImageGenerator(graph)
# Setze die Positionen im ImageGenerator.
image_generator.nodes.set_positions(positions)
Schritt 3: Farben und Größen setzen
# Lege die Farben für die Kanten fest.
image_generator.edges.set_colors("grey")
# Lege die Farben für die Knoten fest. Wir nutzen ein qualitatives Mapping. Das
# bedeutet, dass mehrere Kategorien unterschiedliche eingefärbt werden.
image_generator.nodes.set_colors(dts.qualitative("stage_of_sf", cmap="Set2"))
# Lege die Knotengröße fest. Wir nutzen ein sequentielles Mapping. Das bedeutet, dass
# kontinuierliche Werte auf eine von uns gewählte Skala übertragen werden (`out_range`).
# In diesem Fall würde also das geringste Degree den Knotenradius 5, das höchste Degree
# im Netzwerk den Knotenradius 500 bedeuten.
image_generator.nodes.set_sizes(dts.sequential("degree", out_range=(5, 500)))
Schritt 4: Abbildung erstellen und speichern
# Wir zeichnen und schreiben die Datei. Zeichnen und Schreiben finden getrennt statt, da
# es möglich ist, eine Abbildung in mehreren Ebenen zu komponieren.
image_generator.draw().write_file("./abbildung.svg")
Die ganze mögliche Lösung kannst du hier herunterladen. Probier dich gerne noch weiter aus.