Skip to content

Commit 36e3e3c

Browse files
committed
Minor code improvements
1 parent b548c85 commit 36e3e3c

File tree

1 file changed

+85
-89
lines changed

1 file changed

+85
-89
lines changed

app/streamlit_app.py

Lines changed: 85 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import json
23
import time
34
import io
@@ -46,6 +47,16 @@
4647
More details on **[GitHub]({GIT_REPO_URL})**.
4748
'''
4849

50+
FOOTER = f'''
51+
If you find this app useful, please consider leaving a :star: on **[GitHub]({GIT_REPO_URL})**.
52+
'''
53+
54+
ICON_PATH = 'app/logo_icon.png'
55+
56+
LOGO_PATH = 'app/logo_hori.png'
57+
58+
APP_TITLE = 'TDA Mapper App'
59+
4960
# V_* are reusable values for widgets
5061

5162
V_LENS_IDENTITY = 'Identity'
@@ -224,51 +235,16 @@ def get_data_summary(df_X, df_y):
224235
return df_summary
225236

226237

227-
def graph_download_button(mapper_graph):
228-
mapper_adj = {} if mapper_graph is None else adjacency_data(mapper_graph)
229-
mapper_json = json.dumps(mapper_adj, default=int)
230-
st.download_button(
231-
'📥 Download Mapper Graph',
232-
data=get_gzip_bytes(mapper_json),
233-
disabled=nx.is_empty(mapper_graph),
234-
use_container_width=True,
235-
file_name=f'mapper_graph_{int(time.time())}.json.gzip')
236-
237-
238-
def set_headings():
239-
page_title = 'TDA Mapper App'
240-
default_page_icon = '🔮'
241-
default_heading = '🔮 TDA Mapper App'
242-
logo_icon_path = 'app/logo_icon.png'
243-
logo_hori_path = 'app/logo_hori.png'
244-
try:
245-
with open(logo_icon_path, 'r', encoding='utf-8') as _:
246-
page_icon = logo_icon_path
247-
except FileNotFoundError as _:
248-
page_icon = default_page_icon
249-
st.set_page_config(
250-
page_icon=page_icon,
251-
page_title=page_title,
252-
menu_items={
253-
'Report a bug': REPORT_BUG,
254-
'About': ABOUT})
255-
try:
256-
with open(logo_hori_path, 'r', encoding='utf-8') as _:
257-
with st.sidebar:
258-
st.image(logo_hori_path, use_column_width=True)
259-
st.image(logo_hori_path, use_column_width=True)
260-
except FileNotFoundError as err:
261-
print(err)
262-
st.sidebar.header(default_heading)
263-
st.header(default_heading)
264-
finally:
265-
st.sidebar.markdown('#')
266-
st.sidebar.markdown(DESCRIPTION)
267-
st.sidebar.markdown('#')
268-
st.markdown('#')
238+
def get_graph_caption(mapper_graph):
239+
nodes_num = 0
240+
edges_num = 0
241+
if mapper_graph is not None:
242+
nodes_num = mapper_graph.number_of_nodes()
243+
edges_num = mapper_graph.number_of_edges()
244+
return f'{nodes_num} nodes, {edges_num} edges'
269245

270246

271-
def graph_histogram(mapper_graph):
247+
def get_graph_histogram(mapper_graph):
272248
ccs = nx.connected_components(mapper_graph)
273249
size = nx.get_node_attributes(mapper_graph, ATTR_SIZE)
274250
node_cc, node_size = {}, {}
@@ -283,18 +259,15 @@ def graph_histogram(mapper_graph):
283259
node_size_max = u_size
284260
if cc_len > node_cc_max:
285261
node_cc_max = cc_len
286-
287262
arr_size = np.array([node_size[u]/node_size_max for u in mapper_graph.nodes()])
288263
arr_cc = np.array([node_cc[u]/node_cc_max for u in mapper_graph.nodes()])
289-
290264
df = pd.DataFrame(dict(
291265
series=np.concatenate((
292266
['node size (rel.)'] * len(arr_size),
293267
['conn. comp. size (rel.)'] * len(arr_cc))),
294268
data=np.concatenate((
295269
arr_size,
296270
arr_cc))))
297-
298271
fig = px.histogram(
299272
df,
300273
nbins=20,
@@ -323,24 +296,48 @@ def graph_histogram(mapper_graph):
323296
return fig
324297

325298

326-
def get_graph_caption(mapper_graph):
327-
nodes_num = 0
328-
edges_num = 0
329-
if mapper_graph is not None:
330-
nodes_num = mapper_graph.number_of_nodes()
331-
edges_num = mapper_graph.number_of_edges()
332-
return f'{nodes_num} nodes, {edges_num} edges'
299+
def graph_download_button(mapper_graph):
300+
mapper_adj = {} if mapper_graph is None else adjacency_data(mapper_graph)
301+
mapper_json = json.dumps(mapper_adj, default=int)
302+
return st.download_button(
303+
'📥 Download Mapper Graph',
304+
data=get_gzip_bytes(mapper_json),
305+
disabled=nx.is_empty(mapper_graph),
306+
use_container_width=True,
307+
file_name=f'mapper_graph_{int(time.time())}.json.gzip')
333308

334309

335-
def wrap_callback(cont, msg, func):
336-
def _func(*args, **kwargs):
337-
with cont:
338-
with st.spinner(msg):
339-
func(*args, **kwargs)
340-
return _func
310+
def set_page_config():
311+
icon = ICON_PATH if os.path.exists(ICON_PATH) else '🔮'
312+
st.set_page_config(
313+
page_icon=icon,
314+
page_title=APP_TITLE,
315+
menu_items={
316+
'Report a bug': REPORT_BUG,
317+
'About': ABOUT})
318+
341319

320+
def set_sidebar_headings():
321+
with st.sidebar:
322+
if os.path.exists(LOGO_PATH):
323+
st.image(LOGO_PATH, width=200)
324+
else:
325+
st.header(f'🔮 {APP_TITLE}')
326+
st.markdown('#')
327+
st.markdown(DESCRIPTION)
328+
st.markdown('#')
329+
330+
331+
def set_main_headings():
332+
st.subheader('')
333+
if os.path.exists(LOGO_PATH):
334+
st.image(LOGO_PATH, width=400)
335+
else:
336+
st.header(f'🔮 {APP_TITLE}')
337+
st.markdown('#')
342338

343-
def _load_data(data_source):
339+
340+
def _update_data(data_source):
344341
X, y = pd.DataFrame(), pd.DataFrame()
345342
if isinstance(data_source, io.BytesIO):
346343
X, y = pd.read_csv(data_source), pd.DataFrame()
@@ -359,7 +356,7 @@ def _load_data(data_source):
359356

360357

361358
def data_section():
362-
st.subheader('📊 Data')
359+
st.subheader('📊 Data', anchor=False)
363360
col_0, col_1 = st.columns([2, 4])
364361
col_2, col_3 = st.columns([2, 4])
365362
with col_0:
@@ -380,7 +377,7 @@ def data_section():
380377
'⏳ Loading Data...',
381378
'📦 Load',
382379
use_container_width=True,
383-
on_click=_load_data,
380+
on_click=_update_data,
384381
args=(data_source,))
385382
df_X = st.session_state[S_RESULTS].df_X
386383
df_y = st.session_state[S_RESULTS].df_y
@@ -391,8 +388,25 @@ def data_section():
391388
st.caption(get_data_caption(df_X, df_y))
392389

393390

391+
def _update_mapper(X, lens, cover, clustering):
392+
mapper_algo = MapperAlgorithm(
393+
cover=cover,
394+
clustering=FailSafeClustering(
395+
clustering=clustering,
396+
verbose=False))
397+
mapper_graph = mapper_algo.fit_transform(X, lens)
398+
st.session_state[S_RESULTS].set_mapper(mapper_graph)
399+
st.toast('Successfully Computed Mapper', icon='✅')
400+
auto_rendering = st.session_state[S_RESULTS].auto_rendering
401+
if auto_rendering is False:
402+
st.toast('Automatic Rendering Disabled: Graph Too Large', icon='⚠️')
403+
404+
394405
def settings_tab(X):
395-
tab_0, tab_1, tab_2 = st.tabs(['🔎 Lens', '🌐 Cover', '🧮 Clustering'])
406+
tab_0, tab_1, tab_2 = st.tabs([
407+
'🔎 Lens',
408+
'🌐 Cover',
409+
'🧮 Clustering'])
396410
h = 300
397411
b = False
398412
with tab_0:
@@ -449,22 +463,8 @@ def settings_tab(X):
449463
return lens, cover, clustering
450464

451465

452-
def _update_mapper(X, lens, cover, clustering):
453-
mapper_algo = MapperAlgorithm(
454-
cover=cover,
455-
clustering=FailSafeClustering(
456-
clustering=clustering,
457-
verbose=False))
458-
mapper_graph = mapper_algo.fit_transform(X, lens)
459-
st.session_state[S_RESULTS].set_mapper(mapper_graph)
460-
st.toast('Successfully Computed Mapper', icon='✅')
461-
auto_rendering = st.session_state[S_RESULTS].auto_rendering
462-
if auto_rendering is False:
463-
st.toast('Automatic Rendering Disabled: Graph Too Large', icon='⚠️')
464-
465-
466466
def settings_section():
467-
st.subheader('⚙️ Mapper Settings')
467+
st.subheader('⚙️ Mapper Settings', anchor=False)
468468
X = st.session_state[S_RESULTS].X
469469
col_0, col_1 = st.columns([2, 4])
470470
col_2, col_3 = st.columns([2, 4])
@@ -484,7 +484,7 @@ def settings_section():
484484

485485
with col_1:
486486
with st.container(border=True):
487-
fig_hist = graph_histogram(mapper_graph)
487+
fig_hist = get_graph_histogram(mapper_graph)
488488
st.plotly_chart(
489489
fig_hist,
490490
use_container_width=True,
@@ -508,7 +508,7 @@ def _update_fig(seed, colors):
508508

509509

510510
def rendering_section():
511-
st.subheader('🔮 Mapper Graph')
511+
st.subheader('🔮 Mapper Graph', anchor=False)
512512
df_summary = st.session_state[S_RESULTS].df_summary
513513
df_X = st.session_state[S_RESULTS].df_X
514514
df_y = st.session_state[S_RESULTS].df_y
@@ -570,23 +570,19 @@ def rendering_section():
570570
use_container_width=True)
571571

572572

573-
574-
575-
576-
577573
def main():
578-
set_headings()
574+
set_page_config()
575+
set_main_headings()
576+
set_sidebar_headings()
579577
if S_RESULTS not in st.session_state:
580578
st.session_state[S_RESULTS] = Results()
581579
data_section()
582580
st.markdown('#')
583581
settings_section()
584582
st.markdown('#')
585583
rendering_section()
586-
st.markdown(f'''
587-
---
588-
If you find this app useful, please consider leaving a :star: on **[GitHub]({GIT_REPO_URL})**.
589-
''')
584+
st.divider()
585+
st.markdown(FOOTER)
590586

591587

592588
main()

0 commit comments

Comments
 (0)