Skip to content

Commit d241d37

Browse files
committed
Readded timings
1 parent fc8b29a commit d241d37

File tree

2 files changed

+301
-228
lines changed

2 files changed

+301
-228
lines changed

pages/data.py

Lines changed: 197 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -172,157 +172,172 @@ def render_content(
172172
start_date, end_date, timezone, n_intervals, key_list, current_page,
173173
loaded_uuids_store, all_data_loaded
174174
):
175-
initial_batch_size = 10 # Define the batch size for loading UUIDs
176-
177-
# Update selected tab
178-
selected_tab = tab
179-
logging.debug(f"Callback - {selected_tab} Stage 1: Selected tab updated.")
180-
181-
# Handle the UUIDs tab without fullscreen loading spinner
182-
if tab == 'tab-uuids-datatable':
183-
start_time = time.time()
184-
logging.debug(f"Callback - {selected_tab} Stage 2: Handling UUIDs tab.")
185-
186-
# Ensure store_uuids contains the key 'data' which is a list of dictionaries
187-
if not isinstance(store_uuids, dict) or 'data' not in store_uuids:
188-
logging.error(f"Expected store_uuids to be a dict with a 'data' key, but got {type(store_uuids)}")
189-
return html.Div([html.P("Data structure error.")]), loaded_uuids_store, True
190-
191-
uuids_list = store_uuids['data']
192-
193-
# Ensure uuids_list is a list for slicing
194-
if not isinstance(uuids_list, list):
195-
logging.error(f"Expected store_uuids['data'] to be a list but got {type(uuids_list)}")
196-
return html.Div([html.P("Data structure error.")]), loaded_uuids_store, True
197-
198-
loaded_data = loaded_uuids_store.get('data', [])
199-
total_loaded = len(loaded_data)
200-
201-
# Handle lazy loading
202-
if not loaded_uuids_store.get('loaded', False):
203-
total_to_load = total_loaded + initial_batch_size
204-
total_to_load = min(total_to_load, len(uuids_list)) # Avoid loading more than available
205-
206-
logging.debug(f"Callback - {selected_tab} Stage 3: Loading next batch of UUIDs from {total_loaded} to {total_to_load}.")
207-
208-
new_data = uuids_list[total_loaded:total_to_load]
209-
210-
if new_data:
211-
# Process and append the new data to the loaded store
212-
processed_data = db_utils.add_user_stats(new_data, initial_batch_size)
213-
loaded_data.extend(processed_data)
214-
215-
# Update the store with the new data
216-
loaded_uuids_store['data'] = loaded_data # Mark all data as loaded if done
217-
loaded_uuids_store['loaded'] = len(loaded_data) >= len(uuids_list)
218-
219-
logging.debug(f"Callback - {selected_tab} Stage 4: New batch loaded. Total loaded: {len(loaded_data)}.")
220-
221-
# Prepare the data to be displayed
222-
columns = perm_utils.get_uuids_columns() # Get the relevant columns
223-
df = pd.DataFrame(loaded_data)
224-
225-
if df.empty or not perm_utils.has_permission('data_uuids'):
226-
logging.debug(f"Callback - {selected_tab} Error Stage: No data available or permission issues.")
227-
return html.Div([html.P("No data available or you don't have permission.")]), loaded_uuids_store, True
228-
229-
df = df.drop(columns=[col for col in df.columns if col not in columns])
230-
231-
logging.debug(f"Callback - {selected_tab} Stage 5: Returning appended data to update the UI.")
232-
content = html.Div([
233-
populate_datatable(df, table_id='uuid-table', page_current=current_page), # Pass current_page
234-
html.P(
235-
f"Showing {len(loaded_data)} of {len(uuids_list)} UUIDs." +
236-
(f" Loading 10 more..." if not loaded_uuids_store.get('loaded', False) else ""),
237-
style={'margin': '15px 5px'}
175+
with ect.Timer() as total_timer:
176+
initial_batch_size = 10 # Define the batch size for loading UUIDs
177+
178+
# Stage 1: Update selected tab
179+
selected_tab = tab
180+
logging.debug(f"Callback - {selected_tab} Stage 1: Selected tab updated.")
181+
182+
# Handle the UUIDs tab without fullscreen loading spinner
183+
if tab == 'tab-uuids-datatable':
184+
with ect.Timer() as handle_uuids_timer:
185+
logging.debug(f"Callback - {selected_tab} Stage 2: Handling UUIDs tab.")
186+
187+
# Ensure store_uuids contains the key 'data' which is a list of dictionaries
188+
if not isinstance(store_uuids, dict) or 'data' not in store_uuids:
189+
logging.error(f"Expected store_uuids to be a dict with a 'data' key, but got {type(store_uuids)}")
190+
return html.Div([html.P("Data structure error.")]), loaded_uuids_store, True
191+
192+
uuids_list = store_uuids['data']
193+
194+
# Ensure uuids_list is a list for slicing
195+
if not isinstance(uuids_list, list):
196+
logging.error(f"Expected store_uuids['data'] to be a list but got {type(uuids_list)}")
197+
return html.Div([html.P("Data structure error.")]), loaded_uuids_store, True
198+
199+
loaded_data = loaded_uuids_store.get('data', [])
200+
total_loaded = len(loaded_data)
201+
202+
# Handle lazy loading
203+
if not loaded_uuids_store.get('loaded', False):
204+
total_to_load = total_loaded + initial_batch_size
205+
total_to_load = min(total_to_load, len(uuids_list)) # Avoid loading more than available
206+
207+
logging.debug(f"Callback - {selected_tab} Stage 3: Loading next batch of UUIDs from {total_loaded} to {total_to_load}.")
208+
209+
new_data = uuids_list[total_loaded:total_to_load]
210+
211+
if new_data:
212+
# Process and append the new data to the loaded store
213+
processed_data = db_utils.add_user_stats(new_data, initial_batch_size)
214+
loaded_data.extend(processed_data)
215+
216+
# Update the store with the new data
217+
loaded_uuids_store['data'] = loaded_data # Mark all data as loaded if done
218+
loaded_uuids_store['loaded'] = len(loaded_data) >= len(uuids_list)
219+
220+
logging.debug(f"Callback - {selected_tab} Stage 4: New batch loaded. Total loaded: {len(loaded_data)}.")
221+
222+
# Prepare the data to be displayed
223+
columns = perm_utils.get_uuids_columns() # Get the relevant columns
224+
df = pd.DataFrame(loaded_data)
225+
226+
if df.empty or not perm_utils.has_permission('data_uuids'):
227+
logging.debug(f"Callback - {selected_tab} Error Stage: No data available or permission issues.")
228+
return html.Div([html.P("No data available or you don't have permission.")]), loaded_uuids_store, True
229+
230+
df = df.drop(columns=[col for col in df.columns if col not in columns])
231+
232+
logging.debug(f"Callback - {selected_tab} Stage 5: Returning appended data to update the UI.")
233+
content = html.Div([
234+
populate_datatable(df, table_id='uuid-table', page_current=current_page), # Pass current_page
235+
html.P(
236+
f"Showing {len(loaded_data)} of {len(uuids_list)} UUIDs." +
237+
(f" Loading 10 more..." if not loaded_uuids_store.get('loaded', False) else ""),
238+
style={'margin': '15px 5px'}
239+
)
240+
])
241+
242+
return content, loaded_uuids_store, False if not loaded_uuids_store['loaded'] else True
243+
244+
esdsq.store_dashboard_time(
245+
"admin/data/render_content/handle_uuids_tab",
246+
handle_uuids_timer
238247
)
239-
])
240248

241-
elapsed_time = time.time() - start_time
242-
logging.info(f"Callback - {selected_tab} Stage 6: Total Time for UUIDs Tab: {elapsed_time:.2f} seconds")
249+
# Handle Trips tab
250+
elif tab == 'tab-trips-datatable':
251+
with ect.Timer() as handle_trips_timer:
252+
logging.debug(f"Callback - {selected_tab} Stage 2: Handling Trips tab.")
243253

244-
return content, loaded_uuids_store, False if not loaded_uuids_store['loaded'] else True
254+
data = store_trips["data"]
255+
columns = perm_utils.get_allowed_trip_columns()
256+
columns.update(col['label'] for col in perm_utils.get_allowed_named_trip_columns())
257+
columns.update(store_trips["userinputcols"])
258+
has_perm = perm_utils.has_permission('data_trips')
245259

246-
# Handle other tabs normally
247-
elif tab == 'tab-trips-datatable':
248-
start_time = time.time()
249-
logging.debug(f"Callback - {selected_tab} Stage 2: Handling Trips tab.")
260+
df = pd.DataFrame(data)
261+
if df.empty or not has_perm:
262+
logging.debug(f"Callback - {selected_tab} Error Stage: No data available or permission issues.")
263+
return None, loaded_uuids_store, True
250264

251-
data = store_trips["data"]
252-
columns = perm_utils.get_allowed_trip_columns()
253-
columns.update(col['label'] for col in perm_utils.get_allowed_named_trip_columns())
254-
columns.update(store_trips["userinputcols"])
255-
has_perm = perm_utils.has_permission('data_trips')
265+
df = df.drop(columns=[col for col in df.columns if col not in columns])
266+
df = clean_location_data(df)
256267

257-
df = pd.DataFrame(data)
258-
if df.empty or not has_perm:
259-
logging.debug(f"Callback - {selected_tab} Error Stage: No data available or permission issues.")
260-
return None, loaded_uuids_store, True
268+
trips_table = populate_datatable(df)
261269

262-
df = df.drop(columns=[col for col in df.columns if col not in columns])
263-
df = clean_location_data(df)
264-
265-
trips_table = populate_datatable(df)
266-
elapsed_time = time.time() - start_time
267-
logging.info(f"Callback - {selected_tab} Stage 3: Total Time for Trips Tab: {elapsed_time:.2f} seconds")
268-
269-
return html.Div([
270-
html.Button('Display columns with raw units', id='button-clicked', n_clicks=0, style={'marginLeft': '5px'}),
271-
trips_table
272-
]), loaded_uuids_store, True
273-
274-
elif tab == 'tab-demographics-datatable':
275-
start_time = time.time()
276-
logging.debug(f"Callback - {selected_tab} Stage 2: Handling Demographics tab.")
277-
278-
data = store_demographics["data"]
279-
has_perm = perm_utils.has_permission('data_demographics')
280-
281-
if len(data) == 1:
282-
data = list(data.values())[0]
283-
columns = list(data[0].keys())
284-
elif len(data) > 1:
285-
if not has_perm:
286-
return None, loaded_uuids_store, True
287-
return html.Div([
288-
dcc.Tabs(id='subtabs-demographics', value=list(data.keys())[0], children=[
289-
dcc.Tab(label=key, value=key) for key in data
290-
]),
291-
html.Div(id='subtabs-demographics-content')
292-
]), loaded_uuids_store, True
293-
294-
elapsed_time = time.time() - start_time
295-
logging.info(f"Callback - {selected_tab} Stage 3: Total Time for Demographics Tab: {elapsed_time:.2f} seconds")
296-
297-
elif tab == 'tab-trajectories-datatable':
298-
start_time = time.time()
299-
logging.debug(f"Callback - {selected_tab} Stage 2: Handling Trajectories tab.")
300-
301-
(start_date, end_date) = iso_to_date_only(start_date, end_date)
302-
# Fetch new data based on the selected key_list from the keylist-switch
303-
if store_trajectories == {} or key_list:
304-
store_trajectories = update_store_trajectories(start_date, end_date, timezone, store_excluded_uuids, key_list)
305-
306-
data = store_trajectories.get("data", [])
307-
if data:
308-
columns = list(data[0].keys())
309-
columns = perm_utils.get_trajectories_columns(columns)
310-
has_perm = perm_utils.has_permission('data_trajectories')
311-
312-
df = pd.DataFrame(data)
313-
if df.empty or not has_perm:
314-
logging.debug(f"Callback - {selected_tab} Error Stage: No data available or permission issues.")
315-
return None, loaded_uuids_store, True
270+
return html.Div([
271+
html.Button('Display columns with raw units', id='button-clicked', n_clicks=0, style={'marginLeft': '5px'}),
272+
trips_table
273+
]), loaded_uuids_store, True
274+
275+
esdsq.store_dashboard_time(
276+
"admin/data/render_content/handle_trips_tab",
277+
handle_trips_timer
278+
)
279+
280+
# Handle Demographics tab
281+
elif tab == 'tab-demographics-datatable':
282+
with ect.Timer() as handle_demographics_timer:
283+
data = store_demographics["data"]
284+
has_perm = perm_utils.has_permission('data_demographics')
285+
286+
if len(data) == 1:
287+
data = list(data.values())[0]
288+
columns = list(data[0].keys())
289+
elif len(data) > 1:
290+
if not has_perm:
291+
return None, loaded_uuids_store, True
292+
return html.Div([
293+
dcc.Tabs(id='subtabs-demographics', value=list(data.keys())[0], children=[
294+
dcc.Tab(label=key, value=key) for key in data
295+
]),
296+
html.Div(id='subtabs-demographics-content')
297+
]), loaded_uuids_store, True
298+
299+
esdsq.store_dashboard_time(
300+
"admin/data/render_content/handle_demographics_tab",
301+
handle_demographics_timer
302+
)
303+
304+
# Handle Trajectories tab
305+
elif tab == 'tab-trajectories-datatable':
306+
with ect.Timer() as handle_trajectories_timer:
307+
(start_date, end_date) = iso_to_date_only(start_date, end_date)
308+
# Fetch new data based on the selected key_list from the keylist-switch
309+
if store_trajectories == {} or key_list:
310+
store_trajectories = update_store_trajectories(start_date, end_date, timezone, store_excluded_uuids, key_list)
311+
312+
data = store_trajectories.get("data", [])
313+
if data:
314+
columns = list(data[0].keys())
315+
columns = perm_utils.get_trajectories_columns(columns)
316+
has_perm = perm_utils.has_permission('data_trajectories')
317+
318+
df = pd.DataFrame(data)
319+
if df.empty or not has_perm:
320+
logging.debug(f"Callback - {selected_tab} Error Stage: No data available or permission issues.")
321+
return None, loaded_uuids_store, True
316322

317-
df = df.drop(columns=[col for col in df.columns if col not in columns])
323+
df = df.drop(columns=[col for col in df.columns if col not in columns])
318324

319-
elapsed_time = time.time() - start_time
320-
logging.info(f"Callback - {selected_tab} Stage 3: Total Time for Trajectories Tab: {elapsed_time:.2f} seconds")
325+
return populate_datatable(df), loaded_uuids_store, True
321326

322-
return populate_datatable(df), loaded_uuids_store, True
327+
esdsq.store_dashboard_time(
328+
"admin/data/render_content/handle_trajectories_tab",
329+
handle_trajectories_timer
330+
)
331+
332+
# Handle unhandled tabs or errors
333+
else:
334+
logging.debug(f"Callback - {selected_tab} Error Stage: No data loaded or unhandled tab.")
335+
return None, loaded_uuids_store, True
323336

324-
# Default case: if no data is loaded or the tab is not handled
325-
logging.debug(f"Callback - {selected_tab} Error Stage: No data loaded or unhandled tab.")
337+
esdsq.store_dashboard_time(
338+
"admin/data/render_content/total_time",
339+
total_timer
340+
)
326341
return None, loaded_uuids_store, True
327342

328343
# Handle subtabs for demographic table when there are multiple surveys
@@ -422,27 +437,47 @@ def update_dropdowns_trips(n_clicks, button_label):
422437

423438

424439
def populate_datatable(df, table_id='', page_current=0):
425-
if not isinstance(df, pd.DataFrame):
426-
raise PreventUpdate
427-
return dash_table.DataTable(
428-
id=table_id,
429-
# columns=[{"name": i, "id": i} for i in df.columns],
430-
data=df.to_dict('records'),
431-
export_format="csv",
432-
filter_options={"case": "sensitive"},
433-
# filter_action="native",
434-
sort_action="native", # give user capability to sort columns
435-
sort_mode="single", # sort across 'multi' or 'single' columns
436-
page_current=page_current, # set to current page
437-
page_size=50, # number of rows visible per page
438-
style_cell={
439-
'textAlign': 'left',
440-
# 'minWidth': '100px',
441-
# 'width': '100px',
442-
# 'maxWidth': '100px',
443-
},
444-
style_table={'overflowX': 'auto'},
445-
css=[{"selector":".show-hide", "rule":"display:none"}]
440+
with ect.Timer() as total_timer:
441+
# Stage 1: Check if df is a DataFrame and raise PreventUpdate if not
442+
with ect.Timer() as stage1_timer:
443+
if not isinstance(df, pd.DataFrame):
444+
raise PreventUpdate
445+
esdsq.store_dashboard_time(
446+
"admin/data/populate_datatable/check_dataframe_type",
447+
stage1_timer
448+
)
449+
450+
# Stage 2: Create DataTable
451+
with ect.Timer() as stage2_timer:
452+
table = dash_table.DataTable(
453+
id=table_id,
454+
# columns=[{"name": i, "id": i} for i in df.columns],
455+
data=df.to_dict('records'),
456+
export_format="csv",
457+
filter_options={"case": "sensitive"},
458+
# filter_action="native",
459+
sort_action="native", # give user capability to sort columns
460+
sort_mode="single", # sort across 'multi' or 'single' columns
461+
page_current=page_current, # set to current page
462+
page_size=50, # number of rows visible per page
463+
style_cell={
464+
'textAlign': 'left',
465+
# 'minWidth': '100px',
466+
# 'width': '100px',
467+
# 'maxWidth': '100px',
468+
},
469+
style_table={'overflowX': 'auto'},
470+
css=[{"selector":".show-hide", "rule":"display:none"}]
471+
)
472+
esdsq.store_dashboard_time(
473+
"admin/db_utils/populate_datatable/create_datatable",
474+
stage2_timer
475+
)
476+
477+
esdsq.store_dashboard_time(
478+
"admin/db_utils/populate_datatable/total_time",
479+
total_timer
446480
)
481+
return table
482+
447483

448-
return result

0 commit comments

Comments
 (0)