1
+ """Main Dash App for Rainfall Analysis"""
2
+
3
+ from itertools import product
4
+ from pathlib import Path
5
+ from dash import dcc , html , Input , Output , State
6
+ import pandas as pd
1
7
import dash
2
8
import dash_bootstrap_components as dbc
3
- import pandas as pd
4
9
import plotly .io as pio
5
- import pyfigure , pyfunc , pylayout , pylayoutfunc
6
- from dash import dcc , html , Input , Output , State
7
- from pathlib import Path
8
10
from pyconfig import appConfig
9
11
from pytemplate import hktemplate
12
+ import pyfigure , pyfunc , pylayout , pylayoutfunc # pylint: disable=multiple-imports
10
13
11
14
pio .templates .default = hktemplate
12
15
17
20
18
21
# BOOTSRAP THEME
19
22
THEME = appConfig .DASH_THEME .THEME
20
- dbc_css = (
21
- "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates@V1.0.4 /dbc.min.css"
23
+ DBC_CSS = (
24
+ "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates@V1.1.2 /dbc.min.css"
22
25
)
23
26
24
27
# APP
25
28
app = dash .Dash (
26
29
APP_TITLE ,
27
- external_stylesheets = [getattr (dbc .themes , THEME ), dbc_css ],
30
+ external_stylesheets = [getattr (dbc .themes , THEME ), DBC_CSS ],
28
31
title = APP_TITLE ,
29
32
update_title = UPDATE_TITLE ,
30
33
meta_tags = [
39
42
pylayout .HTML_TITLE ,
40
43
pylayout .HTML_ALERT_README ,
41
44
pylayout .HTML_ROW_BUTTON_UPLOAD ,
45
+ pylayout .HTML_ROW_BUTTON_EXAMPLE ,
42
46
pylayout .HTML_ROW_TABLE ,
43
47
pylayout .HTML_ROW_BUTTON_VIZ ,
44
48
pylayout .HTML_ROW_OPTIONS_GRAPH_RAINFALL ,
49
53
pylayout .HTML_ROW_GRAPH_ANALYSIS ,
50
54
pylayout .HTML_ROW_GRAPH_CUMSUM ,
51
55
pylayout .HTML_ROW_GRAPH_CONSISTENCY ,
52
- # pylayout.HTML_MADEBY ,
56
+ html . Hr () ,
53
57
pylayout .HTML_SUBTITLE ,
54
58
pylayout .HTML_FOOTER ,
55
59
],
56
- fluid = True ,
60
+ fluid = False ,
57
61
className = "dbc" ,
58
62
)
59
63
69
73
Input ("dcc-upload" , "contents" ),
70
74
State ("dcc-upload" , "filename" ),
71
75
State ("dcc-upload" , "last_modified" ),
72
- Input ("button-skip" , "n_clicks" ),
76
+ Input ("button-example-1" , "n_clicks" ),
77
+ Input ("button-example-2" , "n_clicks" ),
78
+ Input ("button-example-3" , "n_clicks" ),
79
+ Input ("button-example-4" , "n_clicks" ),
73
80
prevent_initial_call = True ,
74
81
)
75
- def callback_upload (content , filename , filedate , _ ):
82
+ def callback_upload (content , filename , filedate , _b1 , _b2 , _b3 , _b4 ):
83
+ """Callback for uploading data and displaying the table."""
84
+
76
85
ctx = dash .callback_context
77
86
78
87
if content is not None :
79
88
children , dataframe = pyfunc .parse_upload_data (content , filename , filedate )
80
89
81
- if ctx .triggered [0 ]["prop_id" ] == "button-skip.n_clicks" :
82
- dataframe = pd .read_csv (
83
- Path (r"./example_7Y5S.csv" ), index_col = 0 , parse_dates = True
84
- )
90
+ example_data = {
91
+ "button-example-1.n_clicks" : r"./example_7Y5S.csv" ,
92
+ "button-example-2.n_clicks" : r"./example_2Y4S_named.csv" ,
93
+ "button-example-3.n_clicks" : r"./example_9Y1S_named.csv" ,
94
+ "button-example-4.n_clicks" : r"./example_1Y7S_named.csv" ,
95
+ }
96
+
97
+ context_trigger_prop_id = ctx .triggered [0 ]["prop_id" ]
98
+
99
+ if context_trigger_prop_id in example_data :
100
+ example_file = example_data [context_trigger_prop_id ]
101
+ dataframe = pd .read_csv (Path (example_file ), index_col = 0 , parse_dates = True )
85
102
filename = None
86
103
filedate = None
87
104
@@ -130,6 +147,8 @@ def callback_upload(content, filename, filedate, _):
130
147
prevent_initial_call = True ,
131
148
)
132
149
def callback_visualize (_ , table_data , table_columns , graphbar_opt ):
150
+ """Callback for visualizing the rainfall data."""
151
+
133
152
dataframe = pyfunc .transform_to_dataframe (table_data , table_columns )
134
153
135
154
row_download_table_style = {"visibility" : "visible" }
@@ -139,13 +158,13 @@ def callback_visualize(_, table_data, table_columns, graphbar_opt):
139
158
button_analyze_outline = False
140
159
141
160
if dataframe .size > (366 * 8 ):
142
- fig = pyfigure .figure_scatter (dataframe )
161
+ fig = pyfigure .generate_scatter_figure (dataframe )
143
162
else :
144
163
row_graphbar_options_style = {"visibility" : "visible" }
145
164
if graphbar_opt in ["group" , "stack" ]:
146
- fig = pyfigure .figure_bar (dataframe , graphbar_opt )
165
+ fig = pyfigure .generate_bar_figure (dataframe , graphbar_opt )
147
166
else :
148
- fig = pyfigure .figure_scatter (dataframe )
167
+ fig = pyfigure .generate_scatter_figure (dataframe )
149
168
150
169
return [
151
170
fig ,
@@ -165,6 +184,7 @@ def callback_visualize(_, table_data, table_columns, graphbar_opt):
165
184
prevent_initial_call = True ,
166
185
)
167
186
def callback_download_table (_ , table_data , table_columns ):
187
+ """Callback for downloading the table data."""
168
188
dataframe = pyfunc .transform_to_dataframe (table_data , table_columns )
169
189
return dcc .send_data_frame (dataframe .to_csv , "derived_table.csv" )
170
190
@@ -182,6 +202,7 @@ def callback_download_table(_, table_data, table_columns):
182
202
prevent_initial_call = True ,
183
203
)
184
204
def callback_analyze (_ , table_data , table_columns ):
205
+ """Callback for analyzing the rainfall data."""
185
206
186
207
button_viz_analysis_disabled = True
187
208
button_viz_analysis_outline = True
@@ -200,7 +221,7 @@ def callback_analyze(_, table_data, table_columns):
200
221
]
201
222
202
223
# CUMUMLATIVE SUM
203
- cumsum = pyfunc .calc_cumsum (dataframe )
224
+ cumsum = pyfunc .calculate_cumulative_sum (dataframe )
204
225
205
226
_ , table_cumsum = pylayoutfunc .create_table_layout (
206
227
cumsum , "table-cumsum" , deletable = False
@@ -219,8 +240,12 @@ def callback_analyze(_, table_data, table_columns):
219
240
button_viz_analysis_disabled = False
220
241
button_viz_analysis_outline = False
221
242
row_button_download_analysis_style = {"visibility" : "visible" }
222
- except Exception as e :
223
- children = html .Div (f"SOMETHING ERROR { e } " )
243
+ except (TypeError , ValueError ) as e :
244
+ children = html .Div (
245
+ f"Input data or columns are not in the expected format: { e } "
246
+ )
247
+ except KeyError as e :
248
+ children = html .Div (f"Dataframe does not have the expected columns: { e } " )
224
249
225
250
return [
226
251
children ,
@@ -254,6 +279,7 @@ def callback_download_results(
254
279
cumsum_data ,
255
280
cumsum_columns ,
256
281
):
282
+ """Callback for downloading the analysis results."""
257
283
258
284
biweekly = (biweekly_data , biweekly_columns )
259
285
monthly = (monthly_data , monthly_columns )
@@ -310,7 +336,7 @@ def callback_graph_analysis(
310
336
cumsum_data ,
311
337
cumsum_columns ,
312
338
):
313
- from itertools import product
339
+ """Callback for generating the analysis graphs."""
314
340
315
341
label_periods = ["Biweekly" , "Monthly" , "Yearly" ]
316
342
label_maxsum = ["Max + Sum" ]
@@ -334,7 +360,7 @@ def callback_graph_analysis(
334
360
summary_all .append (dataframe )
335
361
336
362
graphs_maxsum = [
337
- pyfigure .figure_summary_maxsum (
363
+ pyfigure .generate_summary_maximum_sum (
338
364
summary ,
339
365
title = f"<b>{ period } : { title } </b>" ,
340
366
period = period ,
@@ -343,12 +369,12 @@ def callback_graph_analysis(
343
369
for summary , title , period in zip (summary_all , label_maxsum * 3 , label_periods )
344
370
]
345
371
graphs_raindry = [
346
- pyfigure .figure_summary_raindry (
372
+ pyfigure .generate_summary_rain_dry (
347
373
summary , title = f"<b>{ period } : { title } </b>" , period = period
348
374
)
349
375
for summary , title , period in zip (summary_all , label_raindry * 3 , label_periods )
350
376
]
351
- graph_maxdate = [pyfigure .figure_summary_maxdate (summary_all )]
377
+ graph_maxdate = [pyfigure .generate_summary_maximum_date (summary_all )]
352
378
353
379
all_graphs = graphs_maxsum + graphs_raindry + graph_maxdate
354
380
labels = [": " .join (i ) for i in product (label_ufunc , label_periods )]
@@ -363,7 +389,8 @@ def callback_graph_analysis(
363
389
cumsum = pyfunc .transform_to_dataframe (cumsum_data , cumsum_columns )
364
390
365
391
graph_cumsum = [
366
- pyfigure .figure_cumsum_single (cumsum , col = station ) for station in cumsum .columns
392
+ pyfigure .generate_cumulative_sum (cumsum , data_column = station )
393
+ for station in cumsum .columns
367
394
]
368
395
369
396
children_cumsum = pylayoutfunc .create_tabcard_graph_layout (
@@ -375,13 +402,15 @@ def callback_graph_analysis(
375
402
if cumsum .columns .size == 1 :
376
403
children_consistency = (
377
404
dcc .Graph (
378
- figure = pyfigure .figure_empty (text = "Not Available for Single Station" ),
405
+ figure = pyfigure .generate_empty_figure (
406
+ text = "Not Available for Single Station"
407
+ ),
379
408
config = {"staticPlot" : True },
380
409
),
381
410
)
382
411
else :
383
412
graph_consistency = [
384
- pyfigure .figure_consistency (cumsum , col = station )
413
+ pyfigure .generate_scatter_with_trendline (cumsum , data_column = station )
385
414
for station in cumsum .columns
386
415
]
387
416
@@ -392,14 +421,5 @@ def callback_graph_analysis(
392
421
return children_analysis , children_cumsum , children_consistency
393
422
394
423
395
- @app .callback (
396
- Output ("row-troubleshoot" , "children" ),
397
- Input ("button-troubleshoot" , "n_clicks" ),
398
- prevent_initial_call = True ,
399
- )
400
- def _callback_troubleshoot (_ ):
401
- return html .Div ("troubleshoot" )
402
-
403
-
404
424
if __name__ == "__main__" :
405
425
app .run_server (debug = DEBUG )
0 commit comments