Diagram sieci nazywany jest także mapą sieci (ang. Network map) lub diagramem łączenia węzłów (ang. Node-link diagram). Diagram sieci jest wizualizacją, która pokazuje jak dane zbiory jednostek (np. osoby, przedmioty, transakcje, akcje itp.) są ze sobą połączone tworząc graficzny obraz sieci.
Elementy na wykresie sieci są wyświetlane jako węzły (ang. nodes), a relacje między nimi są reprezentowane jako linie zwane krawędziami (ang. edges). Węzły mogą mieć różne kolory i rozmiary. Zazwyczaj węzły są rysowane jako małe kropki lub kółka, ale można również używać ikon. Z kolei krawędzie mogą mieć różne kolory i grubości.
Diagram sieci można wykorzystać do interpretacji struktury sieci poprzez wyszukiwanie klastrów węzłów, gęstości połączeń węzłów lub sposobu rozmieszczenia układu diagramu. Mogą być również optymalne dla różnych przypadków użycia, takich jak wizualizacja relacji między ludźmi, firmami, miastami i tak dalej. Piszę w tym momencie o nich, bo sam je niedawno wykorzystałem to zaprezentowania, w jaki sposób klient porusza się po stronie internetowej. Dzięki diagramowi łatwo było zauważyć anomalie, czy zapętlenia (ciekawe info dla UXowców!).
Można wyszczególnić dwa rodzaje diagramu sieciowego: nieskierowane i skierowane. Nieskierowany diagram sieci wyświetla tylko połączenia między podmiotami, podczas gdy skierowany diagram sieci pokazuje, czy połączenia są jednokierunkowe, czy dwukierunkowe za pomocą strzałek.
Diagram sieci staje się trudny do odczytania, gdy jest zbyt wiele węzłów i połączeń i nie ma przy tym wyraźnego wzorca! Wówczas wizualizacja staje się bardzo nieczytelna. To zagrożenie określa się mianem „Hairball„.
Jak narysować diagram sieci w Python?
Na ratunek przychodzi nam biblioteka networkx, która bardzo ułatwia rysowanie grafów w python. Wczytajmy najpierw potrzebne pakiety:
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
import networkx as nx
nx.__version__
Teraz zainicjujmy stworzenie naszego pierwszego grafu. Twórzmy najpierw 5 różnych wierzchołków. Następnie po prostu narysujmy je korzystając z funkcji nx.draw:
G = nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_node('A')
G.add_node('B')
print(G.nodes())
nx.draw(G)
Możemy jeszcze podpisać wierzchołki, aby łatwiej zobaczyć, gdzie który jest:
nx.draw(G, with_labels=1)
Teraz możemy zdefiniować ręcznie kilka przykładowych krawędzi między wierzchołkami.
G.add_edge(1, 2)
G.add_edge(2, 3)
G.add_edge(3, 1)
G.add_edge(3, 'A')
G.add_edge('A', 'B')
print(G.edges())
nx.draw(G, with_labels=1)
Jak możecie zauważyć ten przykład został dokładnie z wszystkimi zależnościami przeniesiony na wykres. Pobawmy się jeszcze kolorami, aby dodać troszkę polotu do naszej wizualizacji.
# Specify colors
cmap = matplotlib.colors.ListedColormap(['pink','darkorange','lightgreen'])
node_colors = [1,1,2,3,3]
nx.draw(G, with_labels=1,
node_color=node_colors, cmap=cmap)
Warto pamiętać, że możecie dowolnie sterować wielkością węzłów i grubościami krawędzi, aby dodać dodatkowe informacje do wykresu.
f = plt.figure(figsize=(15,6))
node_sizes = [2000 if col in ['A','B'] else col*500 for col in list(G.nodes)]
nx.draw(G, with_labels=1,
node_color=node_colors, cmap=cmap,
node_size=node_sizes)
Pamiętajcie, że biblioteka networkX daje naprawdę dużą swobodę. Można dodać jeszcze strzałki na wykresie, aby wskazać kierunek połączenia. Można również dodać informację opisową dla krawędzi lub je pokolorować. W razie wątpliwości zachęcam do przejrzenia galerii w celu inspiracji!
f = plt.figure(figsize=(15,6))
G = nx.DiGraph()
G.add_edges_from([(1, 2),(3,'A')], weight=1)
G.add_edges_from([(2, 3),('A','B')], weight=2)
G.add_edges_from([(3, 1)], weight=3)
edge_labels=dict([((u,v,),d['weight'])
for u,v,d in G.edges(data=True)])
red_edges = [(3,'A')]
edge_colors = ['black' if not edge in red_edges
else 'red' for edge in G.edges()]
pos=nx.spring_layout(G)
nx.draw_networkx_edge_labels(G,pos,edge_labels=edge_labels)
nx.draw(G, pos, with_labels=1,
node_size=node_sizes, node_color=node_colors, cmap=cmap,
edge_color=edge_colors,edge_cmap=plt.cm.Reds)
Podczas rysowania grafów popatrzcie na różne sposoby wizualizacji i wybierzcie ten, który najwięcej mówi o Waszych danych!
f = plt.figure(figsize=(15,15))
f.tight_layout()
# Subplot 1
plt.subplot(2, 2, 1)
nx.draw(G, with_labels=1,
node_size=node_sizes, node_color=node_colors, cmap=cmap,
edge_color=edge_colors,edge_cmap=plt.cm.Reds)
plt.title('Spring Layout (Default)', fontsize=18)
# Subplot 2
plt.subplot(2, 2, 2)
nx.draw_random(G, with_labels=1,
node_size=node_sizes, node_color=node_colors, cmap=cmap,
edge_color=edge_colors,edge_cmap=plt.cm.Reds)
plt.title('Random Layout', fontsize=18)
# Subplot 3
plt.subplot(2, 2, 3)
nx.draw_shell(G, with_labels=1,
node_size=node_sizes, node_color=node_colors, cmap=cmap,
edge_color=edge_colors,edge_cmap=plt.cm.Reds)
plt.title('Shell Layout', fontsize=18)
# Subplot 4
plt.subplot(2, 2, 4)
nx.draw_spectral(G, with_labels=1,
node_size=node_sizes, node_color=node_colors, cmap=cmap,
edge_color=edge_colors,edge_cmap=plt.cm.Reds)
plt.title('Spectral Layout', fontsize=18)
Zawsze możecie zainspirować się galerią z dokumentacji:
Udanego rysowania!
Pozdrawiam serdecznie z całego serducha,