Zum Inhalt

Mapping

Als Mapping bezeichnen wir das Umwandeln von Attributwerten aus einem Graphen in Farb- und Größenattribute für die grafische Darstellung.

Mappings können auf zwei sog. Graph-Elemente, welche in sich wieder auf spezifische Attribute angewandt werden können. Konkret sind das:

  • Knoten (nodes)
    • Knotenfarbe (color)
    • Knotengröße (size)
    • Knotenlabel (labels)
    • Knotentransparenz (alpha)
  • Kanten (edges)
    • Kantenfarbe (color)
    • Kantendicke (size)
    • Kantentransparenz (alpha)

Es gibt vier Möglichkeiten für das Basis-Mapping:

  • fixed: Übernimmt einen festgelegten Wert für Farbe oder Größe, also einen float, int oder str. Dieser wird für alle Elementattribute übernommen.
  • qualitative: Damit werden qualitative Attributsausprägungen auf Graphenelemente gemappt. Beispielsweise hat das Attribut "pet" die Ausprägungen "cat", "dog", "mouse". Die Ausprägungen sind unterschiedlich, verfügen allerdings über keine natürliche Rangfolge.
  • sequential: Damit werden sequentielle Attributsausprägungen auf Graphenelemente gemappt. Beispielsweise kann dafür das Degree eines Knoten verwendet werden. Die Ausprägungen sind unterschiedlich, kontinuierlich und besitzen eine natürliche Rangfolge.
  • ego_mapping: Wendet ein Mapping an, das dem Ego-Netzwerk um ein Ego, d.h. einen ausgewählten Knoten, andere visuelle Attribute zuweist als dem Rest des Netzwerks. Das Ego-Netzwerk beinhaltet alle Knoten, die direkt mit dem Ego verbunden sind und alle Kanten zwischen ihnen.

Darüber hinaus gibt es vier weitere Mappings für komplexe Abbildungen, um Attributen andere grafische Darstellung zu geben, in Abhängigkeit einer gegebenen Bedingung:

  • filtering: Damit wird ein neues Mapping auf das ursprüngliche Mapping gemappt, wenn ein Attribut eine Wahr/Falsch-Bedingung erfüllt.
  • percentile: Damit wird ein neues Mapping auf das ursprüngliche Mapping gemappt, wenn die Perzentile eines Attributs ausserhalb der gegebenen Perzentile liegt.
  • from_node: Übernimmt die Werte des Mappings von Knoten (oder Labels) für das Mapping von Kanten. Entweder kann das Mapping des Start- oder Endknotens zugrunde gelegt werden oder die Bedingung, dass Start- und Endknoten gleich müssen.
  • filter_ego_network: Erlaubt es, das Ego-Netzwerk um ein Ego zu filtern und ein Mapping auf das Ego-Netzwerk und ein anderes auf den Rest anzuwenden. Diese Mappings können beliebig sein, z.B. sequential, ego_mapping, etc.

Anwendung

Das Mapping steht in engem Zusammenhang mit dem ImageGenerator. Für einen Einstieg in das Zeichnen siehe hier.

Fixe Werte

graph = nx.DiGraph() # (1)
graph.add_node("a")
graph.add_node("b")
ig = dts.ImageGenerator(graph) # (2)

fix = fixed(12) # (3)
ig.nodes.set_sizes(fix) # (4)
  1. Erstellung eines einfachen Graphens.
  2. Erstellung eines ImageGenerators.
  3. Hier wird ein Objekt mit einem fixen Wert von 12 initialisiert und der Variable fix zugewiesen.
  4. Hier wird das Objekt fix den Knoten zugewiesen. Alle Knoten im Netzwerk werden nun mit dem Durchmesser 12 gezeichnet.

Die letzten zwei Zeilen können auch kürzer zusammengefasst werden:

ig.nodes.set_sizes(fixed(12))
fixed ist dabei der Standardwert. Zur Erleichterung kann ein fixer Wert überall (insofern er den Typ str, int oder float trägt) auch kurz so geschrieben werden:

ig.nodes.set_sizes(12)

Qualitative Werte

graph = nx.DiGraph() # (1)
graph.add_node("a", pet="dog") # (2)
graph.add_node("b", pet="cat")
ig = dts.ImageGenerator(graph) # (3)

qual = dts.qualitative("pet", {"cat": "red", "dog": "green"}) # (4)
ig.nodes.set_colors(qual) # (5)
  1. Erstellung eines einfachen Graphens.
  2. Hier werden Knoten mit Daten erstellt: Der Knoten a hat für das Attribut pet den Wert dog.
  3. Erstellung eines ImageGenerators.
  4. Hier wird ein Objekt mit einem Attributschlüssel ("pet") und einem dict initialisiert, welches die Zuweisung von Wert zu Farbe erhält. Dies wird der Variable qual zugewiesen.
  5. Hier wird das Objekt qual den Knoten des Graphen als Farbe zugewiesen. Alle Knoten im Netzwerk werden nun mit den Farben der Zuweisung aus dem dict gezeichnet.

Auch hier lassen sich die letzten zwei Zeilen kürzer schreiben:

ig.nodes.set_colors(
    dts.qualitative("pet", {"cat": "red", "dog": "green"}
                )

Hinweis

Farben werden als String übergeben und können sowohl ein Farbwort als auch ein RGB bzw. RGBA sein. Für einen Überblick über alle Farbworte siehe hier. Alle Formen sind hier erläutert.

Falls ein qualitatives Mapping für Größen verwendet werden soll, so müssen in das dict entsprechend statt der Farben Zahlenwerte eingetragen, die die Größe repräsentieren. Katzenmenschen würden das entsprechend so darstellen:

ig.nodes.set_sizes(dts.qualitative("pet", {"cat": 50, "dog": 5})

Sequentielle Werte

graph = nx.DiGraph() # (1)
graph.add_node("a") # (2)
graph.add_node("b")
ig = dsstools.ImageGenerator(graph) # (3)

sequ = sequential("degree", out_range=(10, 50) ) # (4)
ig.nodes.set_sizes(sequ) # (5)
  1. Erstellung eines einfachen Graphens.
  2. Hier werden Knoten ohne zusätzliche Daten erstellt, da wir bereits vorhandene Attribute des Graphen und seiner Knoten nutzen.
  3. Erstellung eines ImageGenerators.
  4. Hier wird ein Objekt mit einem Attributschlüssel ("degree") und einer out_range initialisiert, welches die im Netzwerk vorhandenen Werte zu einer Größe zuweist. Dies wird der Variable sequ zugewiesen.
  5. Hier wird das Objekt sequ den Knoten zugewiesen. Alle Knoten im Netzwerk werden nun mit den Größen der Zuweisung aus der out_range gezeichnet.

Hinweis

Hier ist die Angabe des "degree" natürlich nicht sonderlich sinnvoll, da keine Kanten im Netzwerk bestehen.

Hinweis

Für das Mapping sequentieller Werte sind als interne Attribute folgende Werte zulässig:

  • degree
  • indegree
  • outdegree
  • betweenness
  • closeness
  • Darüber hinaus funktionieren entsprechend im Graph hinterlegte Werte, bspw. die über TextSearch eingelesen wurden. Hierbei ist wichtig, dass dafür der Texttag verwendet werden muss.

Die Kurzschreibweise sollte jetzt aus den bisherigen Beispielen bekannt sein. Genauso lassen sich sequentielle Werte auf das Farben übertragen. Dann muss allerdings anstatt des Parameters out_range der Parameter cmap (Colormap) verwendet werden. In diesem Fall wählen wir die Colormap viridis:

ig.nodes.set_colors("degree", cmap="viridis")

Farben und Größen können kombiniert werden, sodass sowohl Größe als auch Farbe von Knoten korreliert:

(
    ig.nodes
    .set_colors(dts.sequential("degree", cmap="viridis"))
    .set_sizes(dts.sequential("degree", out_range=(5,50)))
)
Für durch das Netz definierte Parameter sind in sequentiellen Mappings folgende Werte erlaubt:

  • "indegree"
  • "outdegree"
  • "degree"
  • "centrality"
  • "betweenness"
  • "closeness"

Darüber hinaus können auch manuell gesetzte Werte verwendet werden:

graph = nx.DiGraph() # (1)
graph.add_node("a", rating=3) # (2)
graph.add_node("b", rating=7)
graph.add_node("c")
ig = dts.ImageGenerator(graph) # (3)

ig.nodes.set_sizes(
    dts.sequential("rating", out_range=(12, 36), fallback=5) # (4)
)

ig.nodes.set_colors(
    dts.sequential("rating", fallback="orange", colormap="viridis") # (5)
)

  1. Erstellung eines einfachen Graphens.
  2. Hier werden Knoten mit Daten erstellt: Der Knoten a hat für das Attribut rating den Wert 3. Auch wird ein Knoten ohne das Attribut rating erstellt (c).
  3. Erstellung eines ImageGenerators.
  4. Hier wird ein Mapping-Objekt mit einem Attributschlüssel rating und einer out_range initialisiert, welches die im Netzwerk vorhandenen Werte zu einer Größe zuweist. Darüber hinaus wird mit fallback ein Standardwert für alle Knoten festgelegt, die nicht über das Attribut verfügen (gilt bspw. für den Knoten c). Alles zusammen wird den Knotengrößen mit ig.nodes.set_sizes() zugewiesen.
  5. Hier wird ein Mapping-Objekt für die Farbe erstellt. Die Vorgehensweise zur darüberliegenden Zeile.

Erweiterte Mappings

Erweiterte Mappings bauen auf bestehenden Mappings auf, um komplexere Mappings zu erstellen. Zwei Möglichkeiten für erweitertete Mappings gibt es:

  • filter: Erstellt ein Mapping entsprechend einer Filterbedingung. Die Filterbedingung wird für jedes Grafenelement evaluiert. Die Werte aus dem zugrundeliegenden base-Mapping werden übernommen, wenn der Ausdruck der Bedingung False zurückgibt. Die Werte von new_mapping werden hingegen genutzt, wenn die Bedingung True ist.
  • from_node: Übernimmt die Werte des Mappings von Knoten (oder Labels) für das Mapping von Kanten. Entweder kann das Mapping des Start- oder Endknotens zugrunde gelegt werden oder die Bedingung, dass Start- und Endknoten gleich müssen.

Filter-Werte

Bedingung
graph = nx.DiGraph() # (1)
graph.add_node("a")
graph.add_node("b")
ig = dts.ImageGenerator(graph) # (2)

base = dts.fixed("blue") # (3)
new_mapping = dts.fixed("orange") # (4)
attribute = "degree" # (5)
condition = lambda x:x > 0.5 # (6)
filtered = dts.filtering(base, new_mapping, attribute, condition) # (7)

ig.nodes.set_colors(filtering) # (8)
  1. Erstellung eines einfachen Graphens.
  2. Erstellung eines ImageGenerators.
  3. Hier wird ein Objekt mit einem fixen Wert von "blue" initialisiert und der Variable base zugewiesen.
  4. Hier wird ein Objekt mit fixen Wert von "orange" initialisiert und der Variable new_mapping zugewiesen.
  5. Hier wird das Attribut, das kontrolliert wird, definiert und der Variable attribute zugewiesen.
  6. Hier wird die Bedingung definiert und der Variable condition zugewiesen.
  7. Hier wird ein Mapping-Objekt, welches die Zuweisung von Wert zu Farbe auf Basis von der Bedingung erhält.
  8. Hier wird das Objekt filtering den Knoten des Graphen als Farbe zugewiesen. Alle Knoten mit einem Degree hoher als 0.5 orange gezeichnet und alle mit einem Degree niedriger als 0.5 den originalen Wert von blau gezeichnet.

base und new_mapping kann jeder Art von Mapping sein.

Perzentile
graph = nx.DiGraph() # (1)
graph.add_node("a")
graph.add_node("b")
ig = dsstools.ImageGenerator(graph) # (2)

base = dts.fixed("blue") # (3)
new_mapping = dts.fixed("orange") # (4)
attribute = "degree" # (5)

percentile = dts.percentile(base, new_mapping, attribute, perc_range=(0,50)) # (6)


ig.nodes.set_colors(percentile) # (7)
  1. Erstellung eines einfachen Graphens.
  2. Erstellung eines ImageGenerators.
  3. Hier wird ein Objekt mit einem fixen Wert von "blue" initialisiert und der Variable base zugewiesen.
  4. Hier wird ein Objekt mit fixen Wert von "orange" initialisiert und der Variable new_mapping zugewiesen.
  5. Hier wird das Attribut, das kontrolliert wird, definiert und der Variable attribute zugewiesen.
  6. Hier wird ein Mapping-Objekt, welches die Zuweisung von Wert zu Farbe auf Basis von der Bedingung erhält. Darüber hinaus wird mit perc_range das percentile range definiert
  7. Hier wird das Objekt percentile den Knoten des Graphen als Farbe zugewiesen. Alle Knoten mit einem Degree mit der Percentile außerhalb der Percentile range orange gezeichnet und alle Attribute mit einem Wert innerhalb der Percentile Range den originalen Wert von blau gezeichnet.

base und new_mapping kann jeder Art von Mapping sein.

From Node

Es gibt drei Möglichkeiten für das source Paramater von from_node Mapping, welche als String übergeben werden:

  • "incoming": Übernimmt den Wert des Startknotens zum Kanten.
  • "outgoing": Übernimmt den Wert des Endknotens zum Kanten.
  • "matching": Übernimmt den Wert von den Start- und Endknoten zum Kanten, falls sie gleich sind. Ansonsten wird der fallback Wert übernommen. Der Parameter fallback ist nur für das Keyword matching nötig.

Angehängt ist ein Beispiel für "matching":

graph = nx.DiGraph() # (1)
graph.add_node("a")
graph.add_node("b")
graph.add_edge(a,b)
ig = dts.ImageGenerator(graph) # (2)

ig.nodes.set_colors("degree", cmap="viridis") # (3)

from_node = dts.from_node(ig.nodes.colors, "matching", fallback= "red") # (4)

ig.edges.set_colors(from_node) # (5)

  1. Erstellung eines einfachen Graphens.
  2. Erstellung eines ImageGenerators.
  3. Hier wird ein Mapping-Objekt für die Farben der Knoten auf Basis von der "degree" erstellt.
  4. Hier wird ein Mapping-Objekt für die Farben von Kanten initialisiert und der Variable from_node zugewiesen.
  5. Hier wird das Objekt from_node den Knoten des Graphen als Farbe zugewiesen. Alle Kanten, deren Start- und Endknoten den gleichen Wert haben, erhalten diesen, ansonsten erhalten sie den fallback Wert.

Ego Mapping

Ein Ego Mapping kann für Knoten und für Kanten erstellt werden.

Als Ego muss ein Knoten des Graphen festgelegt werden.

Mit einem Mapping können entweder Größen oder Farben festgelegt werden.

Die "incoming", "outgoing", und "mutual" Kanten oder Knoten und das "ego"-Knote können mit ihren eigenen Mapping festgelegt werden durch den zugehörigen Parametern. Das ego_network Parameter setzt das Mapping für alle die Werte der Ego-Netzwerk auf einmal.

Beispiel für die Verwendung von Ego Mappings:

graph = nx.DiGraph()  # (1)
graph.add_nodes_from(["A", "B", "C", "D", "E", "F", "G", "H"])  # (2)
graph.add_edges_from(
    [("B", "C"), ("C", "D"), ("D", "A"), ("A", "F"), ("A", "B"), ("B", "E"), ("G", "H"), ("G", "E"), ("B", "D")])  # (3)
ig = dts.ImageGenerator(graph)  # (4)

ego_mapping_nodes = dts.filter_ego_network(base ="green", ego_network = "blue", attr = 2, ego = "purple" ,incoming="grey")
ego_mapping_edges = dts.filter_ego_network(base= 200, attr = 2, incoming = 500)

ig.nodes.set_colors(ego_mapping_nodes)  # (7)
ig.edges.set_sizes(ego_mapping_edges)  # (8)
  1. Erstelle einen DiGraph (gerichteten Graph)
  2. Füge Knoten zum Graph hinzu
  3. Füge Kanten zum Graph hinzu
  4. Erstelle einen ImageGenerator für den Graphen
  5. Erstelle das Ego Mapping für die Farben der Nodes.
  6. Erstelle das Ego Mapping für die Größen der Edges.
  7. Wende das Mapping auf die Farbe der Knoten an.
  8. Wende das Mapping auf die Dicke der Kanten an.

Filter Ego Network

filter_ego_network kombiniert die Funktionalität von filtering mit der Logik des Ego-Netzwerks.

Es erlaubt, ein Ego-Netzwerk aus dem Netzwerk herauszugreifen und ein Basis-Mapping auf den Teil anzuwenden, der nicht im Ego-Netzwerk liegt und ein neues Mapping auf den Teil, der im Ego-Netzwerk liegt. Dabei muss nicht ego_mapping benutzt werden, sondern jedes Mapping kann auf beide Teile angewandt werden.

Als Parameter werden ein Basis-Mapping, ein neues Mapping, ein Ego (ein Knoten des Netzwerks) und ein boolean ("undirected") übergeben. Der boolean hat denselben Zweck wie bei Ego Mapping.

Beispiel:

graph = nx.DiGraph()  # (1)
graph.add_nodes_from(["A", "B", "C", "D", "E", "F", "G", "H"])  # (2)
graph.add_edges_from(
    [("B", "C"), ("C", "D"), ("D", "A"), ("A", "F"), ("A", "B"), ("B", "E"), ("G", "H"), ("G", "E"), ("B", "D")])  # (3)
image_generator = dts.ImageGenerator(graph)  # (4)

filter_mapping_edges = dts.filter_ego_network(dts.fixed("green"), ego_mapping(ego="B", mapping={"ego_edge": "blue"}),
                                              ego="B")  # (5)
filter_mapping_nodes = dts.filter_ego_network(dts.fixed("green"), dts.fixed("blue"), ego="B")  # (6)

ig.edges.set_colors(filter_mapping_edges)  # (7)
ig.nodes.set_colors(filter_mapping_nodes)  # (8)
  1. Erstelle einen DiGraph (gerichteten Graph)
  2. Füge Knoten zum Graph hinzu
  3. Füge Kanten zum Graph hinzu
  4. Erstelle einen ImageGenerator für den Graphen
  5. Hier wird als Basis ein fixed Mapping mit Wert "green" genutzt, auf das herausgegriffene Ego-Netzwerk wird ein ego_mapping angewendet. Dabei wird sowohl für filter_ego_network als auch für ego_mapping das ego, hier "B", festgelegt.
  6. Hier wird als Basis ein fixed Mapping mit Wert "green" genutzt. Das herausgegriffene Ego-Netzwerk bekommt das Mapping fixed mit dem Wert "blue".
  7. Anwendung des Mappings auf die Kanten.
  8. Anwendung des Mappings auf die Knoten.