-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcachenode2edge2json.py
169 lines (144 loc) · 5.49 KB
/
cachenode2edge2json.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import json
import networkx as nx
import plotly.graph_objects as go
from dash import Dash, dcc, html
from dash.dependencies import Input, Output, State
import pickle
import os
from tqdm import tqdm
import gzip
def load_and_process_data(file_path):
print(f"Loading data from {file_path}...")
with open(file_path, 'r') as f:
data = json.load(f)
G = nx.Graph()
print("Processing nodes...")
for node in tqdm(data['nodes']):
G.add_node(node['id'], **node)
print("Processing edges...")
for edge in tqdm(data['edges']):
G.add_edge(edge['source'], edge['target'], **edge)
return G
def calculate_bounds(G):
longitudes = [node['longitude'] for node in G.nodes.values()]
latitudes = [node['latitude'] for node in G.nodes.values()]
return min(longitudes), max(longitudes), min(latitudes), max(latitudes)
def save_compressed_cache(data, cache_file):
print(f"Saving compressed cache to {cache_file}...")
with gzip.open(cache_file, 'wb') as f:
pickle.dump(data, f)
def load_compressed_cache(cache_file):
if os.path.exists(cache_file):
print(f"Loading compressed cache from {cache_file}...")
with gzip.open(cache_file, 'rb') as f:
return pickle.load(f)
return None
def create_edge_trace(G):
print("Creating edge trace...")
edge_x, edge_y = [], []
for edge in tqdm(G.edges()):
x0, y0 = G.nodes[edge[0]]['longitude'], G.nodes[edge[0]]['latitude']
x1, y1 = G.nodes[edge[1]]['longitude'], G.nodes[edge[1]]['latitude']
edge_x.extend([x0, x1, None])
edge_y.extend([y0, y1, None])
return go.Scattergl(x=edge_x, y=edge_y, mode='lines',
line=dict(width=1, color='rgba(0,0,255,0.2)'),
hoverinfo='none')
def create_node_trace(G):
print("Creating node trace...")
node_x = [node['longitude'] for node in G.nodes.values()]
node_y = [node['latitude'] for node in G.nodes.values()]
node_text = [f"Node ID: {node}" for node in G.nodes()]
return go.Scattergl(x=node_x, y=node_y, mode='markers',
marker=dict(size=2, color='red'),
hoverinfo='text',
text=node_text)
# Main process
print("Starting main process...")
file_path = r"C:\Users\eljapo22\gephi\Node2Edge2JSON\Node2Edge2JSON.json"
cache_file = 'node2edge_cache.gz'
cached_data = load_compressed_cache(cache_file)
if cached_data is None or 'bounds' not in cached_data:
print("Cache not found or outdated. Processing data...")
G = load_and_process_data(file_path)
edge_trace = create_edge_trace(G)
node_trace = create_node_trace(G)
bounds = calculate_bounds(G)
cached_data = {
'edge_trace': edge_trace,
'node_trace': node_trace,
'bounds': bounds
}
save_compressed_cache(cached_data, cache_file)
else:
print("Data loaded from cache.")
edge_trace = cached_data['edge_trace']
node_trace = cached_data['node_trace']
min_longitude, max_longitude, min_latitude, max_latitude = cached_data['bounds']
# Create Dash app
app = Dash(__name__)
# Define the app layout only once
app.layout = html.Div([
html.H1("Node2Edge2JSON Network Visualization"),
dcc.Graph(id='graph', style={'height': '90vh'}, config={'displayModeBar': True, 'scrollZoom': True}),
html.Div(id='click-data')
])
@app.callback(
Output('graph', 'figure'),
Input('graph', 'relayoutData'),
State('graph', 'figure')
)
def update_figure(relayoutData, current_figure):
print("Updating figure...")
if current_figure is None:
# Initial render
fig = go.Figure(data=[edge_trace, node_trace])
layout = dict(
showlegend=False,
hovermode='closest',
margin=dict(b=20,l=5,r=5,t=40),
xaxis=dict(
showgrid=False,
zeroline=False,
showticklabels=False,
range=[min_longitude, max_longitude],
autorange=False,
scaleanchor="y",
scaleratio=1,
),
yaxis=dict(
showgrid=False,
zeroline=False,
showticklabels=False,
range=[min_latitude, max_latitude],
autorange=False,
scaleanchor="x",
scaleratio=1,
),
uirevision='constant'
)
fig.update_layout(layout)
else:
# Subsequent updates
fig = go.Figure(data=current_figure['data'], layout=current_figure['layout'])
if relayoutData is not None:
# Update only specific parts of the layout if changed
updates = {}
if 'xaxis.range[0]' in relayoutData and 'xaxis.range[1]' in relayoutData:
updates['xaxis.range'] = [relayoutData['xaxis.range[0]'], relayoutData['xaxis.range[1]']]
if 'yaxis.range[0]' in relayoutData and 'yaxis.range[1]' in relayoutData:
updates['yaxis.range'] = [relayoutData['yaxis.range[0]'], relayoutData['yaxis.range[1]']]
fig.update_layout(updates)
return fig
@app.callback(
Output('click-data', 'children'),
Input('graph', 'clickData')
)
def display_click_data(clickData):
if clickData is None:
return "Click a node to see its details"
point = clickData['points'][0]
return f"Clicked Point: Longitude {point['x']}, Latitude {point['y']}"
if __name__ == '__main__':
print("Starting server...")
app.run_server(debug=True)