# Importiere die benötigten Abhängigkeiten. Neben dsstools benötigen wir auch NetworkX,
# ein Package für die Verwendung von Graphen, auf dem dsstools aufbaut.
# Beide werden mit einem Alias importiert
import networkx as nx
import dsstools as dts


# ==================================================================================== #
# Graph erstellen
# Die hier gezeigten Schritte sind sehr ausführlich, um den Prozess zu veranschaulichen
# und nicht wirklich best practice. Siehe hierzu die offizielle Dokumentation von
# networkx:
# https://networkx.org/documentation/stable/reference/introduction.html#graph-creation
# ==================================================================================== #

# Erstellung eines Graph-Objekts aus networkx
graph = nx.Graph()

# Hier fügen wir die Nodes dem Graphen zu. Um das nicht jedes Mal einzeln machen zu
# müssen, kann man auch sagen: graph.add_nodes_from(["A", "B", "C", "D"]). Also einfach
# eine Liste an Nodes. Das ist besonders hilfreich, wenn man die Knoten schon vorher
# kennt
graph.add_node("A")
graph.add_node("B")
graph.add_node("C")
graph.add_node("D")

# Nun da wir die Nodes haben, stellen wir einige Edges her:
graph.add_edge("A", "B")
graph.add_edge("B", "C")
graph.add_edge("C", "D")
graph.add_edge("D", "A")

# Nodes können außerdem bestimmte Attribute haben, die wir ihnen selber geben können:
# Node A erhält z. B. das Attribute "Unser Attribut", was den Wert "Wert 1" bekommt
graph.nodes["A"]["Unser Attribute"] = "Wert 1"
graph.nodes["B"]["Unser Attribute"] = "Wert 2"
graph.nodes["C"]["Unser Attribute"] = "Wert 3"
graph.nodes["D"]["Unser Attribute"] = "Wert 1"  # Bewusst gleich zu Node A (siehe unten)

# Attribute können auch andere Werte wie zum Beispiel Zahlen sein:
graph.nodes["D"]["Zahlen Attribute"] = 100

# Informationen über den Graphen ausgeben (optional):
print(graph)  # --> "Graph with 4 nodes and 3 edges"
print(graph.nodes)  # --> ['A', 'B', 'C', 'D']
print(graph.edges)  # --> [('A', 'B'), ('A', 'D'), ('B', 'C'), ('C', 'D')]

# ==================================================================================== #
# Arbeit mit dem Graph
# ==================================================================================== #

# Positionen festlegen über den Layouter()
layouter = dts.Layouter()
positions = layouter.read_or_create_layout("positions.json", graph, seed=1234, k=1)

# Erstellung des Imagegenerators, der letztlich die Abbildung für uns erzeugt. Dabei
# übergeben wir "graph", da das ja die Variable für unseren Graphen ist
image_generator = dts.ImageGenerator(graph)

# Der jetzt erzeugte Imagegenerator erzeugt zun die Positionen für den Graphen auf Basis
# der zuvor erzeugten Positionen
image_generator.nodes.set_positions(positions)

# Jetzt können wir noch die Farbe unserer Edges setzen (hier werden alle grau)
image_generator.edges.set_colors("grey")

# Zur Färbung der Knoten stehen verschiedene Methoden zur Verfügung. Wir wollen jetzt
# Knoten, deren Wert für unser oben definiertes Attribute - "Unser Attribute" - gleich
# ist, auch gleich einfärben. Um das zu demonstrieren, haben Node A und D denselben Wert
# für das Attribut erhalten.
image_generator.nodes.set_colors(dts.qualitative("Unser Attribute", cmap="Set2"))

# Die Größe der Nodes setzen wir anhand ihres degree. Dieses Attribut wird automatisch
# bei der Erstellung der Edges von networkx erzeugt.
image_generator.nodes.set_sizes(dts.sequential("degree", out_range=(100, 500)))

# Jetzt geben wir unseren Graphen mit die Anpassungen als Bild aus. Dazu nutzen wir hier
# das Format ".svg"
image_generator.draw().write_file("./abbildung.svg")



