Upload of networks and pyvis mwe

This commit is contained in:
KM-R 2023-06-04 17:58:55 +02:00 committed by GitHub
parent 1ccb654187
commit 7ca2923d0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 680 additions and 0 deletions

View File

@ -0,0 +1,131 @@
from;to;label
1;50;AR
1;41;V
1;46;WP
1;48;AR
1;40;V
1;48;WP
1;37;AR
2;44;V
2;36;WP
2;50;AR
2;49;V
2;46;WP
2;48;AR
14;36;V
15;38;WP
16;44;AR
17;35;V
18;49;WP
19;31;AR
20;49;V
21;38;WP
22;31;AR
23;32;V
6;31;WP
25;39;AR
26;31;V
27;40;WP
28;46;AR
29;36;V
3;31;WP
1;35;AR
2;35;V
3;42;WP
4;33;AR
5;45;V
6;43;WP
7;45;AR
8;35;V
9;37;WP
10;32;AR
11;38;V
12;37;WP
13;35;AR
14;35;V
15;35;WP
16;35;AR
17;35;V
18;5;WP
19;47;AR
20;45;V
21;44;WP
22;49;AR
4;34;V
5;43;WP
25;43;AR
26;41;V
27;37;WP
28;33;AR
29;35;V
3;32;WP
1;38;AR
2;43;V
3;43;WP
4;35;AR
5;50;V
6;50;WP
6;50;AR
31;40;KOLL
32;41;KOLL
33;37;KOLL
1;38;AR
2;49;V
3;47;WP
4;50;AR
5;41;V
6;40;WP
7;46;AR
8;40;V
9;35;WP
10;32;AR
11;41;V
12;44;WP
13;38;AR
14;34;V
15;44;WP
16;31;AR
17;44;V
18;48;WP
19;32;AR
20;34;V
21;39;WP
22;45;AR
23;41;V
9;37;WP
25;44;AR
26;48;V
27;48;WP
28;47;AR
3;32;V
30;49;WP
1;37;AR
2;39;V
3;40;WP
4;31;AR
5;33;V
6;41;WP
7;32;AR
8;31;V
9;34;WP
10;31;AR
11;35;V
12;38;WP
13;36;AR
14;37;V
15;32;WP
16;45;AR
17;44;V
18;49;WP
19;37;AR
20;41;V
21;43;WP
22;35;AR
10;35;V
24;35;WP
25;50;AR
26;43;V
27;42;WP
28;34;AR
29;32;V
30;40;WP
1 from to label
2 1 50 AR
3 1 41 V
4 1 46 WP
5 1 48 AR
6 1 40 V
7 1 48 WP
8 1 37 AR
9 2 44 V
10 2 36 WP
11 2 50 AR
12 2 49 V
13 2 46 WP
14 2 48 AR
15 14 36 V
16 15 38 WP
17 16 44 AR
18 17 35 V
19 18 49 WP
20 19 31 AR
21 20 49 V
22 21 38 WP
23 22 31 AR
24 23 32 V
25 6 31 WP
26 25 39 AR
27 26 31 V
28 27 40 WP
29 28 46 AR
30 29 36 V
31 3 31 WP
32 1 35 AR
33 2 35 V
34 3 42 WP
35 4 33 AR
36 5 45 V
37 6 43 WP
38 7 45 AR
39 8 35 V
40 9 37 WP
41 10 32 AR
42 11 38 V
43 12 37 WP
44 13 35 AR
45 14 35 V
46 15 35 WP
47 16 35 AR
48 17 35 V
49 18 5 WP
50 19 47 AR
51 20 45 V
52 21 44 WP
53 22 49 AR
54 4 34 V
55 5 43 WP
56 25 43 AR
57 26 41 V
58 27 37 WP
59 28 33 AR
60 29 35 V
61 3 32 WP
62 1 38 AR
63 2 43 V
64 3 43 WP
65 4 35 AR
66 5 50 V
67 6 50 WP
68 6 50 AR
69 31 40 KOLL
70 32 41 KOLL
71 33 37 KOLL
72 1 38 AR
73 2 49 V
74 3 47 WP
75 4 50 AR
76 5 41 V
77 6 40 WP
78 7 46 AR
79 8 40 V
80 9 35 WP
81 10 32 AR
82 11 41 V
83 12 44 WP
84 13 38 AR
85 14 34 V
86 15 44 WP
87 16 31 AR
88 17 44 V
89 18 48 WP
90 19 32 AR
91 20 34 V
92 21 39 WP
93 22 45 AR
94 23 41 V
95 9 37 WP
96 25 44 AR
97 26 48 V
98 27 48 WP
99 28 47 AR
100 3 32 V
101 30 49 WP
102 1 37 AR
103 2 39 V
104 3 40 WP
105 4 31 AR
106 5 33 V
107 6 41 WP
108 7 32 AR
109 8 31 V
110 9 34 WP
111 10 31 AR
112 11 35 V
113 12 38 WP
114 13 36 AR
115 14 37 V
116 15 32 WP
117 16 45 AR
118 17 44 V
119 18 49 WP
120 19 37 AR
121 20 41 V
122 21 43 WP
123 22 35 AR
124 10 35 V
125 24 35 WP
126 25 50 AR
127 26 43 V
128 27 42 WP
129 28 34 AR
130 29 32 V
131 30 40 WP

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,318 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Networkx und Pyvis - Minimal Working Example"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Referenzen: \n",
"- [Networkx Dokumentation](https://networkx.org/documentation/stable/)\n",
"- [Pyvis Dokumentation](https://pyvis.readthedocs.io/en/latest/index.html)\n",
"- [Introduction to Python for Humanists](https://python-textbook.pythonhumanities.com/06_sna/06_01_05_networkx_pyvis.html)\n",
"\n",
"\n",
"Networkx ist eine Python Bibliothek zur Erstellung und Analyse von Netzwerken. Pyvis ist eine Python Bibliothek zur interaktiven Visualisierung von Netzwerkgraphen. Beide können mit `pip` installiert werden. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# install networkx and pyvis using pip\n",
"!pip install networkx\n",
"!pip install pyvis"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Panda Dataframe mit Beispieldaten\n",
"\n",
"Um ein Netzwerk aufbauen zu können, brauchen wir Daten für die Knoten (nodes) und Kanten (edges). Die Daten speichern wir jeweils in einem Panda Dataframe. Pandas kann ebenfalls mit `pip` installiert werden. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# install pandas using pip\n",
"!pip install pandas"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Die Knoten unseres Netzwerks sollen die Unternehmen und Personen darstellen. Eine `id` ermöglicht die eindeutige Identifizierung eines Knoten und hilft Duplikate zu vermeiden. Um Unternehmen von Personen differenzieren zu können, wurde zusätzlich die Information `type` aufgenommen. Sie dient in unserem Beispiel dazu, die Form des Knoten zu bestimmen. Durch `label` bekommt der Knoten eine für den User verständliche Bezeichnung. Weitere Informationen, wie zum Beispiel `branche`, können später für das Mouse Over oder die Größe oder Farbe der Knoten verwendet werden. \n",
"\n",
"Um in einem späteren Schritt die Attribute der Knoten an das Netzwerk zu übergeben, generieren wir zusätzlich eine Spalte `shape`, eine Spalte `color` und eine Spalte `title`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" id label type branche shape color title\n",
"0 1 Firma 1 Company Branche 1 dot #f3e8eeff Firma 1\\nBranche 1\n",
"1 2 Firma 2 Company Branche 2 dot #bacdb0ff Firma 2\\nBranche 2\n",
"2 3 Firma 3 Company Branche 3 dot #729b79ff Firma 3\\nBranche 3\n",
"3 4 Firma 4 Company Branche 4 dot #475b63ff Firma 4\\nBranche 4\n",
"4 5 Firma 5 Company Branche 5 dot #2e2c2fff Firma 5\\nBranche 5\n"
]
}
],
"source": [
"# import pandas\n",
"import pandas as pd\n",
"\n",
"# create dataframe based on the sample data\n",
"df_nodes = pd.read_csv('nodes.csv', sep = ';')\n",
"\n",
"# define shape based on the type\n",
"node_shape = {'Company': 'dot', 'Person': 'triangle'}\n",
"df_nodes['shape'] = df_nodes['type'].map(node_shape)\n",
"\n",
"# define color based on branche\n",
"node_color = {'Branche 1': ' #f3e8eeff', 'Branche 2': '#bacdb0ff', 'Branche 3': '#729b79ff', 'Branche 4': '#475b63ff', 'Branche 5': '#2e2c2fff'}\n",
"df_nodes['color'] = df_nodes['branche'].map(node_color)\n",
"\n",
"# add information column that can be used for the mouse over in the graph\n",
"df_nodes = df_nodes.fillna('')\n",
"df_nodes['title'] = df_nodes['label'] + '\\n' + df_nodes['branche']\n",
"\n",
"# show first five entries of the dataframe\n",
"print(df_nodes.head())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Die Kanten visualisieren die Beziehungen zwischen den Unternehmen und Personen. Um in Pyvis eine Kante darzustellen braucht es minimal die Information zwischen welchen beiden Knoten eine Kante dargestellt werden soll. In den Beispieldaten entspricht dies `from` und `to`. Es wird jeweils auf die eindeutige `id` der jeweiligen Knoten referenziert. `label` bezeichnet hier die Art der Beziehung, z.B. AR = Aufsichtsrat. "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" from to label\n",
"0 1 50 AR\n",
"1 1 41 V\n",
"2 1 46 WP\n",
"3 1 48 AR\n",
"4 1 40 V\n"
]
}
],
"source": [
"# create dataframe based on the sample data\n",
"df_edges = pd.read_csv('edges.csv', sep = ';')\n",
"\n",
"# show first five entries of the dataframe\n",
"print(df_edges.head())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Erstellung eines Netzwerks mit networkx\n",
"\n",
"Zur Erstellung des Netzwerks nutzen wir `networkx`, da diese Bibliothek bessere Analysemöglichkeiten hat als `pyvis`. Das mit `networkx` erstellte Netzwerk können wir später an `pyvis` zur interaktiven Visualisierung übergeben werden. \n",
"\n",
"Wir erstellen die Knoten und Kanten auf Basis unsere beiden Dataframes."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# import networkx\n",
"import networkx as nx\n",
"\n",
"# initiate graph\n",
"graph = nx.MultiGraph()\n",
"\n",
"# create edges from dataframe\n",
"graph = nx.from_pandas_edgelist(df_edges, source = 'from', target = 'to', edge_attr= 'label')\n",
"\n",
"# update node attributes from dataframe\n",
"nodes_attr = df_nodes.set_index('id').to_dict(orient = 'index')\n",
"nx.set_node_attributes(graph, nodes_attr)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Mit Hilfe von `single_source_shortest_path_length` lässt sich die Anzahl der Nachbarn in unterschiedlichen Ebenen bestimmen. Durch die Eingrenzung des `cutoff` listet es alle Nachbarn und bis dahin benötigte Schritte. "
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[{'id': 1, 'k=1': 8, 'k=2': 40, 'k=3': 49}, {'id': 50, 'k=1': 6, 'k=2': 23, 'k=3': 47}, {'id': 41, 'k=1': 8, 'k=2': 28, 'k=3': 48}, {'id': 46, 'k=1': 4, 'k=2': 21, 'k=3': 48}, {'id': 48, 'k=1': 5, 'k=2': 20, 'k=3': 47}]\n"
]
}
],
"source": [
"# create empty list to save k-neighbours for each node\n",
"k_neighbours = []\n",
"\n",
"# loop all nodes in the graph\n",
"for node in graph.nodes:\n",
" # create empty dictionary\n",
" dict = {}\n",
" # get node id\n",
" dict['id'] = node\n",
" # get k-neighbours for k=1,2,3, subtract -1 since output of single_source_shortest_path_length contains node itself\n",
" dict['k=1'] = len(nx.single_source_shortest_path_length(graph, node, cutoff=1))-1\n",
" dict['k=2'] = len(nx.single_source_shortest_path_length(graph, node, cutoff=2))-1\n",
" dict['k=3'] = len(nx.single_source_shortest_path_length(graph, node, cutoff=3))-1\n",
" # append list for each node\n",
" k_neighbours.append(dict)\n",
"\n",
"print(k_neighbours[:5])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visualisierung des Netzwerks mit pyvis\n",
"\n",
"Für die Visualisierung importieren wir `Network` von `pyvis.network` und initialisiern das `pyvis` Netzwerk. Mit der Methode `from_nx` können wir das `networkx` Netzwerk übergeben. \n",
"\n",
"Die Größe der Knoten bestimmen wir je nach Auswahl entweder aufgrund der Anzahl der Verbindungen zu anderen Knoten oder anhand der Eigenvektor-Zentralität. Knoten mit vielen Verbindungen bzw. höherer Zentralität werden größer dargestellt."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# visualize using pyvis\n",
"from pyvis.network import Network\n",
"\n",
"# initiate network\n",
"net = Network(directed=False, neighborhood_highlight=True, bgcolor = \"white\", font_color=\"black\")\n",
"\n",
"# pass networkx graph to pyvis\n",
"net.from_nx(graph)\n",
"\n",
"# set edge options \n",
"net.inherit_edge_colors(False)\n",
"net.set_edge_smooth('dynamic')\n",
"\n",
"# chose size format\n",
"size_type = 'edges' # select 'edges' or 'eigen'\n",
"\n",
"adj_list = net.get_adj_list()\n",
"\n",
"if size_type == 'eigen':\n",
" eigenvector = nx.eigenvector_centrality(graph)\n",
"\n",
"# calculate and update size of the nodes depending on their number of edges\n",
"for node_id, neighbors in adj_list.items():\n",
" if size_type == 'edges':\n",
" size = len(neighbors)*5\n",
" if size_type == 'eigen':\n",
" size = eigenvector[node_id]*200\n",
" next((node.update({'size': size}) for node in net.nodes if node['id'] == node_id), None)\n",
"\n",
"# set the node distance and spring lenght using repulsion\n",
"net.repulsion(node_distance=250, spring_length=150)\n",
"\n",
"# activate physics buttons to further explore the available solvers:\n",
"# barnesHut, forceAtlas2Based, repulsion, hierarchicalRepulsion\n",
"net.show_buttons(filter_=['physics'])\n",
"\n",
"# save graph as HTML\n",
"net.save_graph('networkx_pyvis.html')\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Offene Fragen\n",
"- Gibt es Knoten ohne Verbindung? Wenn erst die Kanten generiert werden, werden diese vermutlich bisher nicht berücksichtigt.\n",
"- Bei der Auswahl eines Unternehmens werden verbundene Knoten nicht farblich angezeigt\n",
"- Bei mehreren Verbindung zwischen zwei Knoten wird derzeit nur die erste angezeigt. Dies kann umgehen werden, wenn man das Netzwerk die Option `directed = True` mitgibt. Allerdings werden dadurch die Kanten zu Pfeilen und man muss bei der Speicherung der Verbindungen aufpassen. Gibt es auch Möglichkeiten für undirected graphs?\n",
"- Sollen die Kanten zusätzlich gewichtet werden? "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Resultierende Anforderungen an die Daten\n",
"\n",
"Relationale Daten für die Kanten und Ecken sind ausreichend. Für die Knoten (= Unternehmen, Personen) werden benötigt:\n",
"- Eindeutige ID\n",
"- Bezeichnung, z.B. Name des Unternehmens bzw. der Person\n",
"- Weitere Informationen, die im Mouse Over angezeigt oder nach denen die Farben oder Größen der Knoten konfiguriert werden sollen\n",
"\n",
"Für die Kanten (= Verbindungen) werden benötigt:\n",
"- Eindeutige IDs zwischen denen die Verbindung besteht\n",
"- Art der Verbindung\n",
"- Ggfs. Gewichtungen\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "aee8b7b246df8f9039afb4144a1f6fd8d2ca17a180786b69acc140d282b71a49"
},
"kernelspec": {
"display_name": "Python 3.10.1 64-bit",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.1"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,51 @@
id;label;type;branche
1;Firma 1;Company;Branche 1
2;Firma 2;Company;Branche 2
3;Firma 3;Company;Branche 3
4;Firma 4;Company;Branche 4
5;Firma 5;Company;Branche 5
6;Firma 6;Company;Branche 1
7;Firma 7;Company;Branche 2
8;Firma 8;Company;Branche 3
9;Firma 9;Company;Branche 4
10;Firma 10;Company;Branche 5
11;Firma 11;Company;Branche 1
12;Firma 12;Company;Branche 2
13;Firma 13;Company;Branche 3
14;Firma 14;Company;Branche 4
15;Firma 15;Company;Branche 5
16;Firma 16;Company;Branche 1
17;Firma 17;Company;Branche 2
18;Firma 18;Company;Branche 3
19;Firma 19;Company;Branche 4
20;Firma 20;Company;Branche 5
21;Firma 21;Company;Branche 1
22;Firma 22;Company;Branche 2
23;Firma 23;Company;Branche 3
24;Firma 24;Company;Branche 4
25;Firma 25;Company;Branche 5
26;Firma 26;Company;Branche 1
27;Firma 27;Company;Branche 2
28;Firma 28;Company;Branche 3
29;Firma 29;Company;Branche 4
30;Firma 30;Company;Branche 5
31;Person 1;Person;
32;Person 2;Person;
33;Person 3;Person;
34;Person 4;Person;
35;Person 5;Person;
36;Person 6;Person;
37;Person 7;Person;
38;Person 8;Person;
39;Person 9;Person;
40;Person 10;Person;
41;Person 11;Person;
42;Person 12;Person;
43;Person 13;Person;
44;Person 14;Person;
45;Person 15;Person;
46;Person 16;Person;
47;Person 17;Person;
48;Person 18;Person;
49;Person 19;Person;
50;Person 20;Person;
1 id label type branche
2 1 Firma 1 Company Branche 1
3 2 Firma 2 Company Branche 2
4 3 Firma 3 Company Branche 3
5 4 Firma 4 Company Branche 4
6 5 Firma 5 Company Branche 5
7 6 Firma 6 Company Branche 1
8 7 Firma 7 Company Branche 2
9 8 Firma 8 Company Branche 3
10 9 Firma 9 Company Branche 4
11 10 Firma 10 Company Branche 5
12 11 Firma 11 Company Branche 1
13 12 Firma 12 Company Branche 2
14 13 Firma 13 Company Branche 3
15 14 Firma 14 Company Branche 4
16 15 Firma 15 Company Branche 5
17 16 Firma 16 Company Branche 1
18 17 Firma 17 Company Branche 2
19 18 Firma 18 Company Branche 3
20 19 Firma 19 Company Branche 4
21 20 Firma 20 Company Branche 5
22 21 Firma 21 Company Branche 1
23 22 Firma 22 Company Branche 2
24 23 Firma 23 Company Branche 3
25 24 Firma 24 Company Branche 4
26 25 Firma 25 Company Branche 5
27 26 Firma 26 Company Branche 1
28 27 Firma 27 Company Branche 2
29 28 Firma 28 Company Branche 3
30 29 Firma 29 Company Branche 4
31 30 Firma 30 Company Branche 5
32 31 Person 1 Person
33 32 Person 2 Person
34 33 Person 3 Person
35 34 Person 4 Person
36 35 Person 5 Person
37 36 Person 6 Person
38 37 Person 7 Person
39 38 Person 8 Person
40 39 Person 9 Person
41 40 Person 10 Person
42 41 Person 11 Person
43 42 Person 12 Person
44 43 Person 13 Person
45 44 Person 14 Person
46 45 Person 15 Person
47 46 Person 16 Person
48 47 Person 17 Person
49 48 Person 18 Person
50 49 Person 19 Person
51 50 Person 20 Person