Skip to content

Commit b0c1a42

Browse files
authored
Refactor app v1.4 (#38)
1 parent cf7d2cf commit b0c1a42

9 files changed

+618
-319
lines changed

.vscode/settings.json

-5
This file was deleted.

app.py

+57-37
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
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
17
import dash
28
import dash_bootstrap_components as dbc
3-
import pandas as pd
49
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
810
from pyconfig import appConfig
911
from pytemplate import hktemplate
12+
import pyfigure, pyfunc, pylayout, pylayoutfunc # pylint: disable=multiple-imports
1013

1114
pio.templates.default = hktemplate
1215

@@ -17,14 +20,14 @@
1720

1821
# BOOTSRAP THEME
1922
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"
2225
)
2326

2427
# APP
2528
app = dash.Dash(
2629
APP_TITLE,
27-
external_stylesheets=[getattr(dbc.themes, THEME), dbc_css],
30+
external_stylesheets=[getattr(dbc.themes, THEME), DBC_CSS],
2831
title=APP_TITLE,
2932
update_title=UPDATE_TITLE,
3033
meta_tags=[
@@ -39,6 +42,7 @@
3942
pylayout.HTML_TITLE,
4043
pylayout.HTML_ALERT_README,
4144
pylayout.HTML_ROW_BUTTON_UPLOAD,
45+
pylayout.HTML_ROW_BUTTON_EXAMPLE,
4246
pylayout.HTML_ROW_TABLE,
4347
pylayout.HTML_ROW_BUTTON_VIZ,
4448
pylayout.HTML_ROW_OPTIONS_GRAPH_RAINFALL,
@@ -49,11 +53,11 @@
4953
pylayout.HTML_ROW_GRAPH_ANALYSIS,
5054
pylayout.HTML_ROW_GRAPH_CUMSUM,
5155
pylayout.HTML_ROW_GRAPH_CONSISTENCY,
52-
# pylayout.HTML_MADEBY,
56+
html.Hr(),
5357
pylayout.HTML_SUBTITLE,
5458
pylayout.HTML_FOOTER,
5559
],
56-
fluid=True,
60+
fluid=False,
5761
className="dbc",
5862
)
5963

@@ -69,19 +73,32 @@
6973
Input("dcc-upload", "contents"),
7074
State("dcc-upload", "filename"),
7175
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"),
7380
prevent_initial_call=True,
7481
)
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+
7685
ctx = dash.callback_context
7786

7887
if content is not None:
7988
children, dataframe = pyfunc.parse_upload_data(content, filename, filedate)
8089

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)
85102
filename = None
86103
filedate = None
87104

@@ -130,6 +147,8 @@ def callback_upload(content, filename, filedate, _):
130147
prevent_initial_call=True,
131148
)
132149
def callback_visualize(_, table_data, table_columns, graphbar_opt):
150+
"""Callback for visualizing the rainfall data."""
151+
133152
dataframe = pyfunc.transform_to_dataframe(table_data, table_columns)
134153

135154
row_download_table_style = {"visibility": "visible"}
@@ -139,13 +158,13 @@ def callback_visualize(_, table_data, table_columns, graphbar_opt):
139158
button_analyze_outline = False
140159

141160
if dataframe.size > (366 * 8):
142-
fig = pyfigure.figure_scatter(dataframe)
161+
fig = pyfigure.generate_scatter_figure(dataframe)
143162
else:
144163
row_graphbar_options_style = {"visibility": "visible"}
145164
if graphbar_opt in ["group", "stack"]:
146-
fig = pyfigure.figure_bar(dataframe, graphbar_opt)
165+
fig = pyfigure.generate_bar_figure(dataframe, graphbar_opt)
147166
else:
148-
fig = pyfigure.figure_scatter(dataframe)
167+
fig = pyfigure.generate_scatter_figure(dataframe)
149168

150169
return [
151170
fig,
@@ -165,6 +184,7 @@ def callback_visualize(_, table_data, table_columns, graphbar_opt):
165184
prevent_initial_call=True,
166185
)
167186
def callback_download_table(_, table_data, table_columns):
187+
"""Callback for downloading the table data."""
168188
dataframe = pyfunc.transform_to_dataframe(table_data, table_columns)
169189
return dcc.send_data_frame(dataframe.to_csv, "derived_table.csv")
170190

@@ -182,6 +202,7 @@ def callback_download_table(_, table_data, table_columns):
182202
prevent_initial_call=True,
183203
)
184204
def callback_analyze(_, table_data, table_columns):
205+
"""Callback for analyzing the rainfall data."""
185206

186207
button_viz_analysis_disabled = True
187208
button_viz_analysis_outline = True
@@ -200,7 +221,7 @@ def callback_analyze(_, table_data, table_columns):
200221
]
201222

202223
# CUMUMLATIVE SUM
203-
cumsum = pyfunc.calc_cumsum(dataframe)
224+
cumsum = pyfunc.calculate_cumulative_sum(dataframe)
204225

205226
_, table_cumsum = pylayoutfunc.create_table_layout(
206227
cumsum, "table-cumsum", deletable=False
@@ -219,8 +240,12 @@ def callback_analyze(_, table_data, table_columns):
219240
button_viz_analysis_disabled = False
220241
button_viz_analysis_outline = False
221242
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}")
224249

225250
return [
226251
children,
@@ -254,6 +279,7 @@ def callback_download_results(
254279
cumsum_data,
255280
cumsum_columns,
256281
):
282+
"""Callback for downloading the analysis results."""
257283

258284
biweekly = (biweekly_data, biweekly_columns)
259285
monthly = (monthly_data, monthly_columns)
@@ -310,7 +336,7 @@ def callback_graph_analysis(
310336
cumsum_data,
311337
cumsum_columns,
312338
):
313-
from itertools import product
339+
"""Callback for generating the analysis graphs."""
314340

315341
label_periods = ["Biweekly", "Monthly", "Yearly"]
316342
label_maxsum = ["Max + Sum"]
@@ -334,7 +360,7 @@ def callback_graph_analysis(
334360
summary_all.append(dataframe)
335361

336362
graphs_maxsum = [
337-
pyfigure.figure_summary_maxsum(
363+
pyfigure.generate_summary_maximum_sum(
338364
summary,
339365
title=f"<b>{period}: {title}</b>",
340366
period=period,
@@ -343,12 +369,12 @@ def callback_graph_analysis(
343369
for summary, title, period in zip(summary_all, label_maxsum * 3, label_periods)
344370
]
345371
graphs_raindry = [
346-
pyfigure.figure_summary_raindry(
372+
pyfigure.generate_summary_rain_dry(
347373
summary, title=f"<b>{period}: {title}</b>", period=period
348374
)
349375
for summary, title, period in zip(summary_all, label_raindry * 3, label_periods)
350376
]
351-
graph_maxdate = [pyfigure.figure_summary_maxdate(summary_all)]
377+
graph_maxdate = [pyfigure.generate_summary_maximum_date(summary_all)]
352378

353379
all_graphs = graphs_maxsum + graphs_raindry + graph_maxdate
354380
labels = [": ".join(i) for i in product(label_ufunc, label_periods)]
@@ -363,7 +389,8 @@ def callback_graph_analysis(
363389
cumsum = pyfunc.transform_to_dataframe(cumsum_data, cumsum_columns)
364390

365391
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
367394
]
368395

369396
children_cumsum = pylayoutfunc.create_tabcard_graph_layout(
@@ -375,13 +402,15 @@ def callback_graph_analysis(
375402
if cumsum.columns.size == 1:
376403
children_consistency = (
377404
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+
),
379408
config={"staticPlot": True},
380409
),
381410
)
382411
else:
383412
graph_consistency = [
384-
pyfigure.figure_consistency(cumsum, col=station)
413+
pyfigure.generate_scatter_with_trendline(cumsum, data_column=station)
385414
for station in cumsum.columns
386415
]
387416

@@ -392,14 +421,5 @@ def callback_graph_analysis(
392421
return children_analysis, children_cumsum, children_consistency
393422

394423

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-
404424
if __name__ == "__main__":
405425
app.run_server(debug=DEBUG)

app_config.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
DASH_APP:
22
APP_TITLE: Rainfall Data Explorer
33
UPDATE_TITLE: Updating...
4-
DEBUG: False
4+
DEBUG: FALSE
55

66
DASH_THEME:
7-
THEME: COSMO
7+
THEME: ZEPHYR
88

99
TEMPLATE:
1010
LOGO_SOURCE:
1111
WATERMARK_SOURCE:
1212
SHOW_LEGEND_INSIDE: False
1313
SHOW_RANGESELECTOR: False
1414

15-
VERSION: v1.3.0
16-
GITHUB_LINK: https://github.com/fiakoenjiniring/rainfall
17-
GITHUB_REPO: fiakoenjiniring/rainfall
15+
VERSION: v1.4.0
16+
GITHUB_LINK: https://github.com/taruma/rainfall
17+
GITHUB_REPO: taruma/rainfall

pyconfig.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""This module is used to load the configuration file and make it available to the application."""
2+
13
from box import Box
24

35
_CONFIG_PATH = "app_config.yml"

0 commit comments

Comments
 (0)