visnetmap 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- visnetmap-0.1.0.dist-info/METADATA +18 -0
- visnetmap-0.1.0.dist-info/RECORD +10 -0
- visnetmap-0.1.0.dist-info/WHEEL +5 -0
- visnetmap-0.1.0.dist-info/licenses/LICENSE +21 -0
- visnetmap-0.1.0.dist-info/top_level.txt +1 -0
- vistNETmap/__init__.py +0 -0
- vistNETmap/base_modes/__init__.py +1 -0
- vistNETmap/base_modes/netmap_base.py +660 -0
- vistNETmap/base_modes/network_visual_save_base.py +1014 -0
- vistNETmap/visNM.py +257 -0
vistNETmap/visNM.py
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
|
|
2
|
+
from base_modes.network_visual_save_base import *
|
|
3
|
+
from base_modes.netmap_base import *
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def remove_duplicate_dicts(dict_list):
|
|
7
|
+
"""Remove duplicate dictionaries (deep equality) while preserving order."""
|
|
8
|
+
seen = set()
|
|
9
|
+
unique_list = []
|
|
10
|
+
for d in dict_list:
|
|
11
|
+
# Convert dict (with nested objects) to a JSON string so it's hashable
|
|
12
|
+
key = json.dumps(d, sort_keys=True)
|
|
13
|
+
if key not in seen:
|
|
14
|
+
seen.add(key)
|
|
15
|
+
unique_list.append(d)
|
|
16
|
+
return unique_list
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def visNET(nodes,edges,network_title='Atsaniik Network', browserView=True, writeHTML='atsaniik_newtork.html', description_df=None, description_title='Peng Atsaniik', min_default_node_size=1, min_default_edge_width=0, maximum_display=20):
|
|
24
|
+
|
|
25
|
+
""" visualize your network with a save button to export selected nodes and edges to JSON files
|
|
26
|
+
Args:
|
|
27
|
+
nodes(Dataframe or List of dict): list of nodes dict e.g. {"id": 1, "label": "Start", "size": 30, "color": "red-spain", "shape": "dot-america", "title": "starting the point"}
|
|
28
|
+
if the shape is image should be converted to base64 through base64_from_loc(image_local_address) or base64_from_url(image_url)
|
|
29
|
+
edges(Dataframe or List of dict): list of edges dict e.g. {"from": 1, "to": 3, "width": 4, "color": {"color": "#C70039-europe"}, "arrows": "to", "title": "from 1 to 3"}
|
|
30
|
+
description_df(dataframe): a dataframe with columns "Name", "Description"
|
|
31
|
+
description_title(str): describe your network in short
|
|
32
|
+
writeHTML(str): output HTML file name
|
|
33
|
+
browserView(bool): whether to open the HTML in a browser
|
|
34
|
+
min_default_node_size(float): minimum node size for initial display
|
|
35
|
+
min_default_edge_width(float): minimum edge width for initial display
|
|
36
|
+
maximum_display(int): maximum number of nodes to display at any time
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if isinstance(nodes, pd.DataFrame) and isinstance(edges, pd.DataFrame):
|
|
44
|
+
|
|
45
|
+
# Function to remove keys with NaN values
|
|
46
|
+
def clean_dict(d):
|
|
47
|
+
return {k: v for k, v in d.items() if not (isinstance(v, float) and pd.isna(v))}
|
|
48
|
+
|
|
49
|
+
# Convert back to list of dicts and remove NaN key-value pairs
|
|
50
|
+
nodes = [clean_dict(row) for row in nodes.to_dict(orient="records")]
|
|
51
|
+
|
|
52
|
+
edges = [clean_dict(row) for row in edges.to_dict(orient="records")]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
elif (isinstance(nodes, list) and all(isinstance(i, dict) for i in nodes)
|
|
57
|
+
and isinstance(edges, list) and all(isinstance(i, dict) for i in edges)):
|
|
58
|
+
nodes = nodes
|
|
59
|
+
edges = edges
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
else:
|
|
63
|
+
print("Nodes and Edges Should be either dataframe or list of dicts in the recommended format")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
nodeIDchecks = []
|
|
70
|
+
for node in nodes:
|
|
71
|
+
nodeIDcheck = node['id']
|
|
72
|
+
nodeIDchecks.append(nodeIDcheck)
|
|
73
|
+
missingNodes = []
|
|
74
|
+
for edge in edges:
|
|
75
|
+
edgeIDcheck = [edge['from'], edge['to']]
|
|
76
|
+
missingNode = [{"id": x} for x in edgeIDcheck if x not in nodeIDchecks]
|
|
77
|
+
if len(missingNode)>0:
|
|
78
|
+
print(f'edge {edge['from']}-{edge['to']} missing nodes description: {missingNode}')
|
|
79
|
+
missingNodes.extend(missingNode)
|
|
80
|
+
|
|
81
|
+
nodes_list1 = nodes + missingNodes
|
|
82
|
+
|
|
83
|
+
nodes_list1 = remove_duplicate_dicts(nodes_list1)
|
|
84
|
+
nodes_list1
|
|
85
|
+
|
|
86
|
+
visnet(nodes_list1, edges, network_title=network_title,description_df=description_df, description_title=description_title, browserView= browserView, writeHTML=writeHTML, min_default_node_size= min_default_node_size, min_default_edge_width=min_default_edge_width, maximum_display=maximum_display)
|
|
87
|
+
|
|
88
|
+
def mapNET(nodes,edges, title="net map", output_html_file='simple.html', maximum_nodes=2):
|
|
89
|
+
"""
|
|
90
|
+
nodes (dataframe or list of dicts): {
|
|
91
|
+
"node": "New York", "lat": 40.7128, "lon": -74.0060, "size": 15,
|
|
92
|
+
"color": "red", "shape": "circle", "node_hover": "The Big Apple, USA"
|
|
93
|
+
}, # shape: circle, triangle, square, star
|
|
94
|
+
edges (dataframe or list of dicts): {
|
|
95
|
+
"node1": "New York", "node2": "Paris", "color": "darkblue", "width": 2,
|
|
96
|
+
"style": "dashed", "arrow": False, "curve": True,
|
|
97
|
+
"edge_hover": any text e.g. "Transatlantic flight"
|
|
98
|
+
"default_size": node size 5
|
|
99
|
+
},
|
|
100
|
+
maximum_nodes: maximum nodes to display initially
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
if isinstance(nodes, pd.DataFrame) and isinstance(edges, pd.DataFrame):
|
|
107
|
+
|
|
108
|
+
# Function to remove keys with NaN values
|
|
109
|
+
def clean_dict(d):
|
|
110
|
+
return {k: v for k, v in d.items() if not (isinstance(v, float) and pd.isna(v))}
|
|
111
|
+
|
|
112
|
+
# Convert back to list of dicts and remove NaN key-value pairs
|
|
113
|
+
nodes = [clean_dict(row) for row in nodes.to_dict(orient="records")]
|
|
114
|
+
|
|
115
|
+
edges = [clean_dict(row) for row in edges.to_dict(orient="records")]
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
elif (isinstance(nodes, list) and all(isinstance(i, dict) for i in nodes)
|
|
120
|
+
and isinstance(edges, list) and all(isinstance(i, dict) for i in edges)):
|
|
121
|
+
nodes = nodes
|
|
122
|
+
edges = edges
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
else:
|
|
126
|
+
print("Nodes and Edges Should be either dataframe or list of dicts in the recommended format")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
netmap(nodes, edges, title=title, output_html_file=output_html_file, maximum_nodes=maximum_nodes)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
gipuzkoa_path = "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Escudo_de_Donostia.svg/800px-Escudo_de_Donostia.svg.png"
|
|
135
|
+
turku_path = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Turku.vaakuna.svg/800px-Turku.vaakuna.svg.png"
|
|
136
|
+
|
|
137
|
+
turku_path2 = r"C:\PhDDocs\pythonPhD\pyBase4All\hyperlinks_scrape\scrapper\network_visual\network_visual\Turku.vaakuna.png"
|
|
138
|
+
gipuzkoa_path2 = r"C:\PhDDocs\pythonPhD\pyBase4All\hyperlinks_scrape\scrapper\network_visual\network_visual\Escudo_de_Donostia.png"
|
|
139
|
+
|
|
140
|
+
turku_img64 = base64_from_loc(turku_path2)
|
|
141
|
+
gipuzkoa_img64 = base64_from_loc(gipuzkoa_path2 )
|
|
142
|
+
|
|
143
|
+
nodes = [
|
|
144
|
+
{"id": 1, "label": "Start", "size": 9, "color": "red-spain", "shape": "dot", "title": "starting the point"},
|
|
145
|
+
{"id": 2, "label": "Process A", "size": 25, "color": "#33FF57-france", "shape": "triangle", "title": "process one"},
|
|
146
|
+
{"id": 3, "label": "Process B", "size": 40, "color": "#3357FF-france", "shape": "box-canada", "title": "process two"},
|
|
147
|
+
{"id": 4, "label": "Critical", "size": 35, "color": "#FFBD33-japan", "shape": "star-asia", "title": "critical point"},
|
|
148
|
+
{"id": 5, "label": "User", "size": 45, "color": "#8D33FF-germany", "shape": "icon-africa",
|
|
149
|
+
"icon": {"face": '"Font Awesome 5 Free"', "code": "\uf007", "size": 50, "color": "#8D33FF-germany"}},
|
|
150
|
+
{"id": 6, "label": "Info A", "size": 48, "color": "#33B5E5-canada", "shape": "icon-africa",
|
|
151
|
+
"icon": {"face": "Font Awesome 5 Brands", "code": "\uf007", "size": 40, "color": "#33B5E5-canada"}},
|
|
152
|
+
{"id": 7, "label": "Image Node A ", "size": 15, "shape": "image-gipuzkoa", "image": gipuzkoa_img64, "color": "#33B5E7-gipuzkoa"},
|
|
153
|
+
{"id": 8, "label": "Gogo", "size": 30, "color": "#FF5733-italy", "shape": "dot", "title": "I am so Alone"},
|
|
154
|
+
{"id": 9, "label": "comecome", "size": 8, "color": "#FF5733-italy", "shape": "dot", "title": "I am so Alone"},
|
|
155
|
+
{"id": 10, "label": "Image Node B", "size": 15, "shape": "image-gipuzkoa", "image": gipuzkoa_img64, "color": "#33B5E7-gipuzkoa"},
|
|
156
|
+
{"id": 11, "label": "Info B", "size": 48, "color": "#33B5E5-canada", "shape": "icon-australia",
|
|
157
|
+
"icon": {"face": "Font Awesome 5 Brands", "code": "\uf05a", "size": 40, "color": "#33B5E5-canada"}},
|
|
158
|
+
{"id": 12, "label": "turku", "size": 15, "shape": "image-turku", "image": turku_img64, "color": "#33B5E6-turku"},
|
|
159
|
+
{"id": 13, "label": "dict", "size": 9, "color": {"background": "yellow-Finland", "border": "green"}, "shape": "dot", "title": "starting the point"},
|
|
160
|
+
{"id":'abcdefg',"label":"abcdefg-label",'shape':'square','size':50},
|
|
161
|
+
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
edges = [
|
|
165
|
+
{"from": 1, "to": 3, "width": 1, "color": {"color": "#C70039-europe"}, "arrows": "to", "title": "from 1 to 3"},
|
|
166
|
+
{"from": 1, "to": 2, "width": 2, "color": {"color": "#C70038-africa"}},
|
|
167
|
+
{"from": 2, "to": 4, "width": 3, "color": {"color": "#581845-africa"}, "arrows": "to", "dashes": True},
|
|
168
|
+
{"from": 2, "to": 5, "width": 4, "color": {"color": "#FFC300-australia"}, "arrows": "to", "smooth": {"type": "curvedCW"}},
|
|
169
|
+
{"from": 3, "to": 3, "width": 5, "color": {"color": "#DAF7A6-america"}, "arrows": "to"},
|
|
170
|
+
{"from": 4, "to": 6, "width": 6, "color": {"color": "#4CAF50-europe"}, "arrows": "to", "smooth": {"type": "curvedCCW"}},
|
|
171
|
+
{"from": 5, "to": 1, "width": 7, "color": {"color": "#2196F3-asia"}, "arrows": "to", "dashes": True},
|
|
172
|
+
{"from": 7, "to": 1, "width": 8, "color": {"color": "#FF00FF-africa"}, "arrows": "to"},
|
|
173
|
+
{"from":14,"to":13}
|
|
174
|
+
]
|
|
175
|
+
visNET(nodes, edges, network_title='small Network', browserView=True, writeHTML='test_small.html', min_default_node_size=1, min_default_edge_width=0, maximum_display=10)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
cities = [
|
|
179
|
+
{"node": "rovaniemi,finland"},
|
|
180
|
+
{
|
|
181
|
+
'node': 'eventti.net',
|
|
182
|
+
'lat': 60.1497055,
|
|
183
|
+
'lon': 24.7376876,
|
|
184
|
+
'size': 10,
|
|
185
|
+
'color': 'blue',
|
|
186
|
+
'shape': 'circle',
|
|
187
|
+
'node_hover': 'eventti.net'
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"node": "New York", "lat": 40.7128, "lon": -74.0060, "size": 15,
|
|
191
|
+
"color": "red", "shape": "circle", "node_hover": "The Big Apple, USA"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"node": "London", "lat": 51.5074, "lon": -0.1278, "size": 12,
|
|
195
|
+
"color": "blue", "shape": "star", "node_hover": "Capital of the UK"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"node": "Tokyo", "lat": 35.6762, "lon": 139.6503, "size": 10,
|
|
199
|
+
"color": "green", "shape": "square", "node_hover": "Capital of Japan"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"node": "Sydney", "lat": -33.8688, "lon": 151.2093, "size": 8,
|
|
203
|
+
"color": "purple", "shape": "circle", "node_hover": "Australia’s coastal gem"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"node": "Paris", "lat": 48.8566, "lon": 2.3522, "size": 11,
|
|
207
|
+
"color": "orange", "shape": "star", "node_hover": "City of Love"
|
|
208
|
+
},
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
connections = [
|
|
212
|
+
{
|
|
213
|
+
"node1": "rovaniemi,finland", "node2": "eventti.net"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"node1": "New York", "node2": "London", "color": "black", "width": 2,
|
|
217
|
+
"style": "solid", "arrow": True, "curve": False,
|
|
218
|
+
"edge_hover": "Flight from NY to London"
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"node1": "Tokyo", "node2": "London", "color": "black", "width": 2,
|
|
222
|
+
"style": "solid", "arrow": True, "curve": False,
|
|
223
|
+
"edge_hover": "Flight tokyo to London"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"node1": "London", "node2": "Tokyo", "color": "blue", "width": 3,
|
|
227
|
+
"style": "solid", "arrow": True, "curve": False,
|
|
228
|
+
"edge_hover": "From London to Tokyo"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"node1": "Tokyo", "node2": "rovaniemi,finland", "color": "red", "width": 10,
|
|
232
|
+
"style": "dashed", "arrow": True, "curve": True,
|
|
233
|
+
"edge_hover": "From Tokyo to Rovaniemi"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"node1": "Tokyo", "node2": "Sydney", "color": "blue", "width": 1,
|
|
237
|
+
"style": "solid", "arrow": True, "curve": False,
|
|
238
|
+
"edge_hover": "Trade route Tokyo ↔ Sydney"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"node1": "Sydney", "node2": "New York", "color": "green", "width": 12,
|
|
242
|
+
"style": "solid", "arrow": True, "curve": True,
|
|
243
|
+
"edge_hover": "Tourist route Sydney–NY"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"node1": "London", "node2": "Paris", "color": "brown", "width": 4,
|
|
247
|
+
"style": "solid", "arrow": True, "curve": False,
|
|
248
|
+
"edge_hover": "Eurostar connection"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"node1": "New York", "node2": "Paris", "color": "darkblue", "width": 2,
|
|
252
|
+
"style": "dashed", "arrow": False, "curve": False,
|
|
253
|
+
"edge_hover": "Transatlantic flight"
|
|
254
|
+
},
|
|
255
|
+
]
|
|
256
|
+
|
|
257
|
+
mapNET(cities, connections, title="net map", output_html_file='simple.html', maximum_nodes=2)
|