Zum Inhalt

Tutorial

In diesem Beispiel werden wir die grundlegenden Funktionen von dssTools kennen lernen und einmal die grobe Suite durchlaufen.

Grundsätzlich unterteilt sich dssTools in drei Teile:

  1. Eingang oder inputs
  2. Verarbeitung oder processing
  3. Ausgang oder outputs

Zu 1. zählen Funktionen wieder beispielsweise der Import von Daten, zu 2. zählt die Festlegung der Positionen des Netzwerks auf der Bildfläche (das sog. Canvas) und zu 3. wird das Aufsetzen sowie das Speichern der Abbildung gezählt.

Die Übergabe zwischen den Teilen findet immer mit einem nx.Graph statt. Veränderungen werde über die Graph-, Node- und Edgeattribute geschrieben und ausgelesen.

Hinweis

Falls das etwas kompliziert klingen sollte: Das ist nicht weiter schlimm, in der Nutzung hat man mit diesen Prinzipien wenig zu tun.

Fangen wir also in einem sauberen Zustand an:

Vorarbeit

Zuerst musst du dssTools installieren. Grundsätzlich empfiehlt es sich, einen eigenen Ordner für das Projekt anzulegen, den wir in der Folge mit Dateien und weiteren Ordner füllen werden. Im weiteren wird dieser Ordner als Wurzelverzeichnis bezeichnet.

Hinweis

Es kann sich lohnen, den eigenen Fortschritt über ein Git-Repository zu tracken. Sollte das gewünscht sein, dann wäre das jetzt der richtige Zeitpunkt dafür.

Für die Verwaltung von sog. Abhängigkeiten empfiehlt sich Poetry. Für die Erläuterung der Installation mit Poetry hier klicken.

Hinweis

Es gibt auch andere Möglichkeiten wie die Kombination aus Pip und venv allerdings ist dies eher für Fortgeschrittene zu empfehlen.

Wenn alles geklappt hat, kannst du in dem Wurzelordner eine Python-Datei mit Namen main.py anlegen. Füge Folgendes in die Datei mit einem Texteditor oder IDE ein:

import networkx as nx
import dsstools as dts

Wir importieren sowohl NetworkX als auch dssTools und das Mapping, welches für Farben und Größen von Knoten und Kanten später relevant ist. Alle Module erhalten ein sog. Alias, um die Schreibarbeit zu reduzieren.

Führe diese Datei aus. Es sollten keine Fehler auftreten. Falls Fehler wie ImportError auftreten, bitte noch einmal die Installation der einzelnen Abhängigkeiten überprüfen und poetry install erneut ausführen.

Falls keine Probleme auftreten, kannst du zum nächsten Schritt übergehen.

Input

Für den Import bieten sich mehrere Optionen, 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 im Wurzelordner.

Der Wurzelordner (.) sollte jetzt so aussehen:

.
├── main.py
├── poetry.lock
└── pyproject.toml
  • [ ] Jetzt lässt sich diese Datei in Python importieren. Da wir vorerst keine Sonderfunktionen benötigen, nutzen wir die Standardfunktion für diesen Zweck in NetworkX:
G = nx.read_gexf("./example_graph.gexf")

Verarbeitung/Processing

Hier legen wir die Positionen fest. Dafür gibt es zwei Möglichkeiten:

  1. NetworkX: Einfach und bereits installiert.
  2. 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.update_positions("positions.json", G, seed=1234, k=1)

Zuerst wird ein Layout-Objekt erstellt. In der nächsten Zeile wird mittels der Objektmethode update_positions() ein Layout erzeugt. Dieses erhält vier Argumente: Den Pfad, in dem 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.

Warnung

update_positions() liest ein bestehendes Layout ein, wenn es unter dem Pfad eine bestehende Datei findet. Ansonsten schreibt es diese neu. Sollen immer neue Abbildungen erzeugt werden und die bestehenden Dateien überschrieben werden, so muss das Argument overwrite=True übergeben werden (siehe Beispiel unten).

Hinweis

Indem der Seed mittels eines Loops iteriert wird, lassen sich unterschiedliche Positionierungen miteinander vergleichen. Bspw. könnte das so aussehen, um 20 unterschiedliche Abbildungen zu erzeugen:

for i in range(0,20):
    layouter.update_positions(f"positions_{i}", G, seed=i, overwrite=True)

Die Positionsdaten des Layouters werden sowohl über positions in Form eines Dicts übergeben als auch in die Datei unter dem angegebene Pfad gespeichert. Im jetzt folgenden Zeichen-Prozess 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.

Zeichnen

Jetzt kommen wir auch schon zum Zeichnen. Dazu erzeugen wir zuerst einen sog. ImageGenerator. Das ist ein Objekt, in dem alle Einstellungen für die jeweilige Abbildung eingestellt werden. Zuerst wird es mittels des Graphen initialisiert.

ig = dts.ImageGenerator(G)

Darüber hinaus müssen wir als Erstes die Positionierungen festlegen:

ig.nodes.set_positions(positions)

Nun können wir einzelne Einstellungen auswählen. Bspw. wollen wir alle Kanten grau einfärben:

ig.edges.set_colors(dts.fixed("grey"))

ig.edges.set_colors() erhält dabei ein Argument in Form von dts.fixed("grey"). Das bedeutet, dass für alle Kanten der Wert "grey" angewendet wird.

Für die Einfärbung von Knoten entlang eines vorhandenen, codierten Attributes:

ig.nodes.set_colors(dts.nominal("stage_of_sf", cmap="Set2"))

Hinweis

Das Attribut stage_of_sf wurde bereits mit der GEXF-Datei übergeben. Natürlich können auch eigene Attribute an die Netzwerkelemente angehängt und dargestellt werden.

Die Größe der Knoten möchten wir entlang des Indegree skalieren:

ig.nodes.set_sizes(dts.ordinal("degree", out_range=(5, 500)))

Zuletzt wird die Abbildung gezeichnet und dann in eine Datei geschrieben:

ig.draw().write_file("./abbildung.png")

Hinweis

Das Gleiche lässt sich auch in einem Aufwasch schreiben: Um mehrzeiligen Code in Python zu verfassen, müssen die Zeilen immer mit einer Klammer eingefasst sein.

ig = dts.ImageGenerator(G)
(
    ig.nodes.set_positions(positions)
    .set_colors(dts.qualitative("geographic_focus", cmap="Set2"))
    .set_sizes(dts.sequential("degree", out_range=(5, 500)))
)
ig.edges.set_colors(dts.fixed("grey"))
ig.draw().write_file("./abbildung.svg")

Damit ist sollte sich im Wurzelordner eine neue Datei mit Namen abbildung.svg finden, die das gezeichnete Netzwerk enthält. Die gesamte Python-Datei lässt sich hier herunterladen.