Skip to content

Commit 2bd1087

Browse files
author
Joseph Hirsch
committed
⚡ improve performance and 💄 show loading in GUI
1 parent f822b93 commit 2bd1087

File tree

8 files changed

+353
-481
lines changed

8 files changed

+353
-481
lines changed

demonstrator/app.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ def render_tabs_content(tab):
6262
return sites[int(tab)].layout()
6363

6464

65-
data_manager.register_callbacks(app)
6665
controls.register_callbacks(app)
6766

6867
for site in sites:

demonstrator/assets/style.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ body {
8686
}
8787
.main_page_container {
8888
width: 100%;
89-
min-height: 700px;
89+
min-height: 850px;
9090
overflow: none;
9191
display: flex;
9292
flex-flow: column;

demonstrator/data_manager.py

Lines changed: 244 additions & 300 deletions
Large diffs are not rendered by default.

demonstrator/views/bar_charts.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@
44
import plotly.express as px
55
from plotly import graph_objects as go
66

7-
from data_manager import FilterOptions, get_frames_angle
7+
from data_manager import FilterOptions, get_frames_angle, get_headings_hist
88

99

1010

1111

1212
def layout():
1313

1414

15-
return html.Div(className="two_columns", children=[
16-
html.Div(className="graphContainer",id="img_direction"),
17-
html.Div(className="nodeInfo", id="frameList")
15+
return dcc.Loading([
16+
html.Div(className="two_columns", children=[
17+
html.Div(className="graphContainer",id="img_direction"),
18+
html.Div(className="nodeInfo", id="frameList")
19+
])
1820
])
1921

2022
def title():
@@ -25,11 +27,10 @@ def register_callback(app):
2527
g_to_inspection = []
2628
@app.callback(
2729
Output(component_id='frameList', component_property='children'),
28-
State(component_id='data_store', component_property='data'),
2930
State(component_id='filter_store', component_property= 'data'),
3031
Input(component_id={'type':'heading_graph', 'index': ALL}, component_property='clickData'),
3132
)
32-
def update_nodes_table(data_store, filter_store, click_data):
33+
def update_nodes_table(filter_store, click_data):
3334
filter_options = FilterOptions(**filter_store)
3435
if not hasattr(update_nodes_table, 'old_data'):
3536
update_nodes_table.old_data = click_data
@@ -41,21 +42,22 @@ def update_nodes_table(data_store, filter_store, click_data):
4142
changed = g_to_inspection[i]
4243
changed_angle = d['points'][0]['theta']
4344

44-
s = ""
4545
if changed is not None:
4646
frames = get_frames_angle(changed, (changed_angle + 360) % 360, filter_options)
4747
return [html.Img(src=f"/assets/imgs/{'mosaics' if f['path'].startswith('m') else 'frames'}/{f['path']}", style={'width':'100%'}) for f in frames]
4848

4949
update_nodes_table.old_data = click_data
50-
return "Select sector to show frames" if changed is None else s
50+
return "Select sector to show frames"
5151

5252
@app.callback(
5353
Output(component_id='img_direction', component_property='children'),
54-
Input(component_id='data_store', component_property='data'),
54+
Input(component_id='filter_store', component_property='data'),
5555
)
56-
def update_image_table(data):
56+
def update_image_table(filter_options):
57+
filter_options = FilterOptions(**filter_options)
58+
heading_hist = get_headings_hist(filter_options)
5759
graphs = []
58-
for inspection_id, heading_hist in data['heading_hist'].items():
60+
for inspection_id, heading_hist in heading_hist.items():
5961
g_to_inspection.append(inspection_id)
6062
title=f"{heading_hist['ship_name']} on {heading_hist['date']}"
6163
fig = px.bar_polar(heading_hist['data'], r="count", theta="heading", width=800, height=800, title=title)

demonstrator/views/clusters.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from dash import dcc, Input, Output, State, html, dash_table
44
import dash_cytoscape as cyto
55
import plotly.express as px
6-
from data_manager import get_frames_cluster
6+
from data_manager import FilterOptions, get_cluster_table, get_frames_cluster
77

88

99

@@ -35,20 +35,24 @@ def layout():
3535
'sort_action':"native",
3636
'sort_by': [{'column_id': 'quality', 'direction': 'desc'}]
3737
}
38-
return html.Div(className="two_column", children=
38+
return html.Div(className="two_column", children=[dcc.Loading(
3939
[html.Div(className="graphContainer", id="clusters_table_container", children=[dash_table.DataTable(id='clusters_table', columns=columns, **table_options)]),
40-
html.Div(className="nodeInfo", style={'width':'25%'}, id="cluster_info", children=["yes its me"])])
40+
html.Div(className="nodeInfo", style={'width':'25%'}, id="cluster_info", children=[])
41+
])
42+
])
4143

4244
def title():
4345
return 'Clusters'
4446

4547
def register_callback(app):
4648
@app.callback(
4749
Output(component_id='clusters_table', component_property='data'),
48-
Input(component_id='data_store', component_property='data'),
50+
Input(component_id='filter_store', component_property='data'),
4951
)
50-
def update_image_table(data):
51-
return data['clusters_table']
52+
def update_image_table(filter_options):
53+
filter_options = FilterOptions(**filter_options)
54+
cluster_table = get_cluster_table(filter_options)
55+
return cluster_table
5256

5357
@app.callback(
5458
Output(component_id='cluster_info', component_property='children'),

demonstrator/views/graph.py

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@
190190

191191
import networkx as nx
192192

193+
from data_manager import FilterOptions, get_graph_stuff
194+
193195
finding = ['defect', 'corrosion', 'marine_growth', 'paint_peel', 'anode', 'over_board_valve', 'propeller', 'sea_chest_grating', 'bilge_keel']
194196

195197
empty_elements = {
@@ -310,20 +312,19 @@ def title():
310312
def register_callback(app):
311313
@app.callback(
312314
Output(component_id='gr', component_property='elements'),
313-
Input(component_id='data_store', component_property='data'),
314-
State(component_id='filter_store', component_property='data'),
315+
Input(component_id='filter_store', component_property='data'),
315316
)
316-
def update_graph(data, filter_options):
317+
def update_graph(filter_options):
318+
filter_options = FilterOptions(**filter_options)
319+
320+
nodes, similar_to, visually_similar_to, in_inspection, in_mosaic, in_cluster, shows_part, part_of_ship = get_graph_stuff(filter_options)
317321

318-
print('updating graph...')
319322
graph = nx.Graph()
320-
nodes = data['nodes']
321323
if len(nodes) == 0:
322324
return empty_elements
323325

324326

325327
node_tuples = []
326-
#node_tuples = random.sample([(key, value) for key, value in nodes.items()], k=min(len(nodes.items()), 100))
327328
node_tuples = [(key, value) for key, value in nodes.items()]
328329
node_keys = {k for k,_ in node_tuples}
329330

@@ -339,34 +340,34 @@ def update_graph(data, filter_options):
339340
PARTOFS_EDGE_WEIGHT = 0.1
340341
SHOWSPR_EDGE_WEIGHT = 0.1
341342

342-
for n1, n2 in data['in_inspection']:
343+
for n1, n2 in in_inspection:
343344
if not n1 in node_keys or not n2 in node_keys: continue
344345
relcount += 1
345346
graph.add_edge(n1, n2, classes="inspection", weight=ININSPE_EDGE_WEIGHT)
346-
for n1, n2 in data['similar_to']:
347+
for n1, n2 in similar_to:
347348
if not n1 in node_keys or not n2 in node_keys: continue
348349
relcount += 1
349350
graph.add_edge(n1, n2, classes="dashed", weight=SIMILAR_EDGE_WEIGHT)
350-
for n1, n2 in data['visually_similar_to']:
351+
for n1, n2 in visually_similar_to:
351352
if not n1 in node_keys or not n2 in node_keys: continue
352353
relcount += 1
353354
graph.add_edge(n1, n2, classes="dotted", weight=SIMILAR_EDGE_WEIGHT)
354-
for n1, n2 in data['in_mosaic']:
355+
for n1, n2 in in_mosaic:
355356
if not n1 in node_keys or not n2 in node_keys: continue
356357
relcount += 1
357358
replace_with.add((n1, n2))
358359
graph.add_edge(n1, n2)
359360

360-
for n1, n2 in data['in_cluster']:
361+
for n1, n2 in in_cluster:
361362
if not n1 in node_keys or not n2 in node_keys: continue
362363
relcount += 1
363364
graph.add_edge(n1, n2, weight=CLUSTER_EDGE_WEIGHT)
364365

365-
for n1, n2 in data['part_of_ship']:
366+
for n1, n2 in part_of_ship:
366367
if not n1 in node_keys or not n2 in node_keys: continue
367368
relcount += 1
368369
graph.add_edge(n1, n2, weight=PARTOFS_EDGE_WEIGHT)
369-
for n1, n2 in data['shows_part']:
370+
for n1, n2 in shows_part:
370371
if not n1 in node_keys or not n2 in node_keys: continue
371372
relcount += 1
372373
graph.add_edge(n1, n2, weight=SHOWSPR_EDGE_WEIGHT, classes="part")
@@ -378,21 +379,8 @@ def update_graph(data, filter_options):
378379
graph.add_edge(n1, n2, **data)
379380
graph.remove_node(image)
380381

381-
382-
positions_by_pca = {
383-
key: (float(tup['tsne'].split(',')[0]),float(tup['tsne'].split(',')[1]))
384-
385-
for key, tup in node_tuples if 'tsne' in tup}
386-
387-
fixed_positions = [k for k in positions_by_pca.keys()]
388-
print(f"loaded result, got {len(node_tuples)} nodes and {relcount} relationships, layouting...")
389-
390-
#pos = nx.spring_layout(graph, fixed = fixed_positions, pos = positions_by_pca, k=1/math.sqrt(graph.order() + 1), iterations=100)
391-
392382
pos = nx.spring_layout(graph, scale=1000, k=10/math.sqrt(graph.order() + 1), iterations=300, seed=84365)
393-
394383
elmts = redact_json_data(nx.cytoscape_data(graph), pos)['elements']
395-
print(f"done")
396384

397385
return elmts
398386

demonstrator/views/histograms.py

Lines changed: 26 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -2,95 +2,39 @@
22
import dash_cytoscape as cyto
33
import plotly.express as px
44

5+
from data_manager import FilterOptions, get_histogram_data
6+
57

68

79
def layout():
8-
return html.Div([
9-
dcc.Graph(id="q_u_hist"),
10-
dcc.Graph(id="d_hist"),
11-
dcc.Graph(id="mg_hist"),
12-
dcc.Graph(id="sim_hist"),
13-
dcc.Graph(id="vsim_hist")
14-
], className="histogramContainer")
10+
return dcc.Loading([
11+
html.Div(id = 'histogram_container', children=[], className="histogramContainer")
12+
])
1513

1614
def title():
1715
return 'Histograms'
1816

1917
def register_callback(app):
2018
@app.callback(
21-
Output(component_id='q_u_hist', component_property='figure'),
22-
Input(component_id='data_store', component_property='data'),
23-
)
24-
def update_histograms(data):
25-
fig = px.histogram(data['q_hist'], range_x=(0,16), labels=["Image Quality (UCIQE)"], color_discrete_sequence=["darkgray"])
26-
fig.update_layout(
27-
title_text='Image Quality (UCIQE)', # title of plot
28-
xaxis_title_text='Image Quality (UCIQE)', # xaxis label
29-
yaxis_title_text='#Frames', # yaxis label
30-
bargap=0.1, # gap between bars of adjacent location coordinates
31-
showlegend=False,
32-
hovermode=False
33-
)
34-
return fig
35-
36-
@app.callback(
37-
Output(component_id='mg_hist', component_property='figure'),
38-
Input(component_id='data_store', component_property='data'),
39-
)
40-
def update_histograms(data):
41-
fig = px.histogram(data['mg_hist'], labels=["Marine Growth Percentage"], color_discrete_sequence=["darkgray"])
42-
fig.update_layout(
43-
title_text='Marine Growth Percentage', # title of plot
44-
xaxis_title_text='Marine Growth Percentage', # xaxis label
45-
yaxis_title_text='#Mosaics', # yaxis label
46-
bargap=0.1, # gap between bars of adjacent location coordinates
47-
showlegend=False,
48-
hovermode=False
49-
)
50-
return fig
51-
52-
@app.callback(
53-
Output(component_id='vsim_hist', component_property='figure'),
54-
Input(component_id='data_store', component_property='data'),
55-
)
56-
def update_histograms(data):
57-
fig = px.histogram(data['vsim_hist'], labels=['Visual Similarities'], color_discrete_sequence=["darkgray"])
58-
fig.update_layout(
59-
title_text='Visual Similarities', # title of plot
60-
xaxis_title_text='Visual Similarities', # xaxis label
61-
yaxis_title_text='#Frames', # yaxis label
62-
bargap=0.1, # gap between bars of adjacent location coordinates
63-
showlegend=False,
64-
hovermode=False
65-
)
66-
return fig
67-
@app.callback(
68-
Output(component_id='sim_hist', component_property='figure'),
69-
Input(component_id='data_store', component_property='data'),
70-
)
71-
def update_histograms(data):
72-
fig = px.histogram(data['sim_hist'], labels=['Similarities'], color_discrete_sequence=["darkgray"])
73-
fig.update_layout(
74-
title_text='Similarities', # title of plot
75-
xaxis_title_text='Similarities', # xaxis label
76-
yaxis_title_text='#Similarities', # yaxis label
77-
bargap=0.1, # gap between bars of adjacent location coordinates
78-
showlegend=False,
79-
hovermode=False
80-
)
81-
return fig
82-
@app.callback(
83-
Output(component_id='d_hist', component_property='figure'),
84-
Input(component_id='data_store', component_property='data'),
19+
Output(component_id='histogram_container', component_property='children'),
20+
Input(component_id='filter_store', component_property='data'),
8521
)
86-
def update_histograms(data):
87-
fig = px.histogram(data['d_hist'], range_x=(-10,0), labels=['Depth'], color_discrete_sequence=["darkgray"])
88-
fig.update_layout(
89-
title_text='Depth', # title of plot
90-
xaxis_title_text='Depth', # xaxis label
91-
yaxis_title_text='#Frames', # yaxis label
92-
bargap=0.1, # gap between bars of adjacent location coordinates
93-
showlegend=False,
94-
hovermode=False
95-
)
96-
return fig
22+
def update_histograms(filter_options):
23+
filter_options = FilterOptions(**filter_options)
24+
data = get_histogram_data(filter_options)
25+
labels = ['Image Quality (UCIQE)', 'Marine growth percentage', 'Depth', 'Similarities', 'Visual similarities']
26+
x_axes = ['Image Quality (UCIQE)', 'Marine growth percentage', 'Depth', 'Similarities', 'Visual similarities']
27+
y_axes = ['#Frames', '#Mosaics', '#Frames', '#Frames', '#Frames']
28+
histograms = []
29+
for data, label, y_axis, x_axis in zip(data, labels, y_axes, x_axes):
30+
fig = px.histogram(data, labels=[label], color_discrete_sequence=["darkgray"])
31+
fig.update_layout(
32+
title_text=label, # title of plot
33+
xaxis_title_text=x_axis, # xaxis label
34+
yaxis_title_text=y_axis, # yaxis label
35+
bargap=0.1, # gap between bars of adjacent location coordinates
36+
showlegend=False,
37+
hovermode=False
38+
)
39+
histograms.append(dcc.Graph(figure=fig))
40+
return histograms

0 commit comments

Comments
 (0)