diff --git a/assets/style.css b/assets/style.css index e5ca1c5b91469b5bae2c48a7af999aa4a4eb882f..76a37e564827b6bafca72d41ac303d139012d531 100644 --- a/assets/style.css +++ b/assets/style.css @@ -1000,3 +1000,22 @@ td.column-0 { max-width: 100%; min-width: 10%; } + +.toast-body { + padding: .25rem .75rem; +} + + #toast { + left: 340px; + bottom: 72px; + z-index: 10000; + position: absolute; +} + +.fa-caret-down { + color: white; + position: absolute; + top: 59px; + left: 7px; + font-size: xxx-large; +} diff --git a/tabs/forecast.py b/tabs/forecast.py index 30da9490543437b16f2d022d1d770434e0fc1610..a22c56da1d686ea3d23531fa70e291a875e71b6f 100644 --- a/tabs/forecast.py +++ b/tabs/forecast.py @@ -278,6 +278,25 @@ def models_children(start_date=START_DATE, end_date=END_DATE): ) ] +def alert_3day_update(): + """ Create the alert to notify users that after April, 3 days of forecast is now + available for PROB and WAS maps""" + if DELAY_DATE: + date = dt.strptime(DELAY_DATE, "%Y%m%d").strftime("%b %d %Y") + message = "3 day forecast available starting {}".format(date) + return dbc.Toast( + [html.P(message, className="mb1"), + html.I( + className="fa fa-solid fa-caret-down", + )], + id="toast", + header=None, + icon="warning", + duration=10000, + dismissable=True, + ) + return + def prob_children(start_date=START_DATE, end_date=END_DATE): """ Return html for probablility maps""" return [ @@ -290,6 +309,7 @@ def prob_children(start_date=START_DATE, end_date=END_DATE): html.Div( id='prob-graph', className='graph-with-slider'), + alert_3day_update(), html.Div(DISCLAIMER_MODELS, className='disclaimer'), dbc.NavbarSimple([ @@ -327,6 +347,7 @@ def was_children(start_date=START_DATE, end_date=END_DATE): id='was-graph', className='graph-with-slider'), ), + alert_3day_update(), html.Div(DISCLAIMER_MODELS, className='disclaimer'), dbc.NavbarSimple([ diff --git a/tests/test_forecast.py b/tests/test_forecast.py index ae24b6e46e04207c52c1f340e02ea8ea360ccbc9..bcd0166533f9e1555c5830acf81818d6f4543eb7 100644 --- a/tests/test_forecast.py +++ b/tests/test_forecast.py @@ -25,21 +25,38 @@ def test_was_time_bar(): def test_models_children(): assert "[Div(id={'tag': 'tab-name', 'index': 'models'}), Alert(children='To explore the forecast, please select a variable and click on APPLY.', id='alert-forecast', color='primary', duration=6000, fade=True, is_open=True, style={'overflow': 'auto', 'marginBottom': 0}), Div(children=[Container(children=[], id='graph-collection', fluid=True), Div(children=[Span(children=P('Dust data ©2023 WMO Barcelona Dust Regional Center.'), id='forecast-disclaimer')], className='disclaimer')], id='div-collection'), Div([Store(id='model-clicked-coords'), Store(id='current-popups-stored')]), Div(Interval(id='slider-interval', disabled=True, interval=1000, n_intervals=0))" in str(code.models_children('20120120', '20220808')) +def test_alert_3day_update(): + assert str(code.alert_3day_update()) == "Toast(children=[P(children='3 day forecast available starting Apr 01 2023', className='mb1'), I(className='fa fa-solid fa-caret-down')], id='toast', dismissable=True, duration=10000, icon='warning')" + def test_prob_children(): - assert "[Div(id={'tag': 'tab-name', 'index': 'prob'}), Div(id='prob-graph', className='graph-with-slider'), Div(children=[Span(children=P('Dust data ©2023 WMO Barcelona Dust Regional Center.'), id='forecast-disclaimer')], className='disclaimer'), NavbarSimple(children=[Div(children=[Div(children=[Span(children=[DatePickerSingle(date='20220808', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2022, 8, 8, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2022, 8, 8, 0, 0), display_format='DD MMM YYYY', id='prob-date-picker'), Button(id='clear_button')], className='timesliderline'), Span(children=Slider(min=1, max=2, step=1, marks={1: {'label': 'TUE 09'}, 2: {'label': 'WED 10', 'style': {'left': '', 'right': '-40px'}}}, value=1, id='prob-slider-graph'), id='prob-slider-container', className='timesliderline')], className='timeslider'), Div(children=[Span(DropdownMenu(children=[DropdownMenuItem(children='Light', id={'tag': 'view-style', 'index': 'carto-positron'}, active=True), DropdownMenuItem(children='Open street map', id={'tag': 'view-style', 'index': 'open-street-map'}, active=False), DropdownMenuItem(children='Terrain', id={'tag': 'view-style', 'index': 'stamen-terrain'}, active=False), DropdownMenuItem(children='ESRI', id={'tag': 'view-style', 'index': 'esri-world'}, active=False)], id='map-view-dropdown', direction='up', in_navbar=True, label='VIEW'))], id='map-view-dropdown-div')], id='layout-dropdown', className='layout-dropdown')], className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True)]" in str(code.prob_children('20120120', '20220808')) + assert "date='20220808'" in str(code.prob_children('20120120', '20220808')) + assert code.prob_children('20120120', '20220808')[0].id == {'tag': 'tab-name', 'index': 'prob'} + assert str(code.prob_children('20120120', '20220808')[1]) == "Div(id='prob-graph', className='graph-with-slider')" + assert str(code.prob_children('20120120', '20220808')[2]) == "Toast(children=[P(children='3 day forecast available starting Apr 01 2023', className='mb1'), I(className='fa fa-solid fa-caret-down')], id='toast', dismissable=True, duration=10000, icon='warning')" + assert str(code.prob_children('20120120', '20220808')[3]) == "Div(children=[Span(children=P('Dust data ©2023 WMO Barcelona Dust Regional Center.'), id='forecast-disclaimer')], className='disclaimer')" def test_was_children(): - assert """[Div(id={'tag': 'tab-name', 'index': 'was'}), Spinner(Div(children=[Div(id="{'index':'None', 'tag': 'empty-map'}")], id='was-graph', className='graph-with-slider')), Div(children=[Span(children=P('Dust data ©2023 WMO Barcelona Dust Regional Center.'), id='forecast-disclaimer')], className='disclaimer'), NavbarSimple(children=[Div(children=[Div(children=[Span(children=[DatePickerSingle(date='20220808', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2022, 8, 8, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2022, 8, 8, 0, 0), display_format='DD MMM YYYY', id='was-date-picker'), Button(id='clear_button')], className='timesliderline'), Span(children=Slider(min=1, max=2, step=1, marks={1: {'label': 'TUE 09'}, 2: {'label': 'WED 10', 'style': {'left': '', 'right': '-40px'}}}, value=1, id='was-slider-graph'), id='was-slider-container', className='timesliderline')], className='timeslider'), Div(children=[Span(DropdownMenu(children=[DropdownMenuItem(children='Light', id={'tag': 'view-style', 'index': 'carto-positron'}, active=True), DropdownMenuItem(children='Open street map', id={'tag': 'view-style', 'index': 'open-street-map'}, active=False), DropdownMenuItem(children='Terrain', id={'tag': 'view-style', 'index': 'stamen-terrain'}, active=False), DropdownMenuItem(children='ESRI', id={'tag': 'view-style', 'index': 'esri-world'}, active=False)], id='map-view-dropdown', direction='up', in_navbar=True, label='VIEW'))], id='map-view-dropdown-div')], id='layout-dropdown', className='layout-dropdown')], className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True)]""" in str(code.was_children('20120120', '20220808')) + assert "Div(children=[Span(DropdownMenu(children=[DropdownMenuItem(children='Light', id={'tag': 'view-style', 'index': 'carto-positron'}, active=True), DropdownMenuItem(children='Open street map', id={'tag': 'view-style', 'index': 'open-street-map'}, active=False), DropdownMenuItem(children='Terrain', id={'tag': 'view-style', 'index': 'stamen-terrain'}, active=False), DropdownMenuItem(children='ESRI', id={'tag': 'view-style', 'index': 'esri-world'}, active=False)], id='map-view-dropdown', direction='up', in_navbar=True, label='VIEW'))], id='map-view-dropdown-div')], id='layout-dropdown', className='layout-dropdown')], className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True)]" in str(code.was_children('20120120', '20220808')) def test_tab_forecast(): #TEST MODELS - assert "Div(children=[Span(DropdownMenu(children=[DropdownMenuItem(children='Light', id={'tag': 'view-style', 'index': 'carto-positron'}, active=True), DropdownMenuItem(children='Open street map', id={'tag': 'view-style', 'index': 'open-street-map'}, active=False), DropdownMenuItem(children='Terrain', id={'tag': 'view-style', 'index': 'stamen-terrain'}, active=False), DropdownMenuItem(children='ESRI', id={'tag': 'view-style', 'index': 'esri-world'}, active=False)], id='map-view-dropdown', direction='up', in_navbar=True, label='VIEW'))], id='map-view-dropdown-div'), Div(children=[Spinner(children=[Modal(children=[], id='ts-modal', centered=True, is_open=False, size='xl')], id='loading-ts-modal', fullscreen=True, fullscreen_style={'opacity': '0.5', 'zIndex': '200000'}, show_initially=False)], id='open-timeseries')], id='layout-dropdown', className='layout-dropdown')], className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True)], id='forecast-tab', className='horizontal-menu', label='Forecast', value='forecast-tab')" in str(code.tab_forecast('models', '20120120', '20220808')) + assert "id='forecast-tab', className='horizontal-menu', label='Forecast', value='forecast-tab')" in str(code.tab_forecast('models', '20120120', '20220808')) + assert "Div(id={'tag': 'tab-name', 'index': 'models'})" in str(code.tab_forecast('models', '20120120', '20220808').children[0]) + assert "Dust data ©2023 WMO Barcelona Dust Regional Center." in str(code.tab_forecast('models', '20120120', '20220808').children[2]) + assert "date='20220808" in str(code.tab_forecast('models', '20120120', '20220808').children[5]) + #TEST WAS - assert """Tab(children=[Div(id={'tag': 'tab-name', 'index': 'was'}), Spinner(Div(children=[Div(id="{'index':'None', 'tag': 'empty-map'}")], id='was-graph', className='graph-with-slider')), Div(children=[Span(children=P('Dust data ©2023 WMO Barcelona Dust Regional Center.'), id='forecast-disclaimer')], className='disclaimer'), NavbarSimple(children=[Div(children=[Div(children=[Span(children=[DatePickerSingle(date='20220808', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2022, 8, 8, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2022, 8, 8, 0, 0), display_format='DD MMM YYYY', id='was-date-picker'), Button(id='clear_button')], className='timesliderline'), Span(children=Slider(min=1, max=2, step=1, marks={1: {'label': 'TUE 09'}, 2: {'label': 'WED 10', 'style': {'left': '', 'right': '-40px'}}}, value=1, id='was-slider-graph'), id='was-slider-container', className='timesliderline')], className='timeslider'), Div(children=[Span(DropdownMenu(children=[DropdownMenuItem(children='Light', id={'tag': 'view-style', 'index': 'carto-positron'}, active=True), DropdownMenuItem(children='Open street map', id={'tag': 'view-style', 'index': 'open-street-map'}, active=False), DropdownMenuItem(children='Terrain', id={'tag': 'view-style', 'index': 'stamen-terrain'}, active=False), DropdownMenuItem(children='ESRI', id={'tag': 'view-style', 'index': 'esri-world'}, active=False)], id='map-view-dropdown', direction='up', in_navbar=True, label='VIEW'))], id='map-view-dropdown-div')], id='layout-dropdown', className='layout-dropdown')], className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True)], id='forecast-tab', className='horizontal-menu', label='Forecast', value='forecast-tab')""" in str(code.tab_forecast('was', '20120120', '20220808')) + assert "id='forecast-tab', className='horizontal-menu', label='Forecast', value='forecast-tab'" in str(code.tab_forecast('was', '20120120', '20220808')) + assert "Div(id={'tag': 'tab-name', 'index': 'was'})" in str(code.tab_forecast('was', '20120120', '20220808').children[0]) + assert "Toast(children=[P(children='3 day forecast available starting Apr 01 2023', className='mb1')" in str(code.tab_forecast('was', '20120120', '20220808').children[2]) + assert "date='20220808" in str(code.tab_forecast('was', '20120120', '20220808').children[4]) #TEST PROB - assert "Tab(children=[Div(id={'tag': 'tab-name', 'index': 'prob'}), Div(id='prob-graph', className='graph-with-slider'), Div(children=[Span(children=P('Dust data ©2023 WMO Barcelona Dust Regional Center.'), id='forecast-disclaimer')], className='disclaimer'), NavbarSimple(children=[Div(children=[Div(children=[Span(children=[DatePickerSingle(date='20220808', min_date_allowed=datetime.datetime(2012, 1, 20, 0, 0), max_date_allowed=datetime.datetime(2022, 8, 8, 0, 0), placeholder='DD MON YYYY', initial_visible_month=datetime.datetime(2022, 8, 8, 0, 0), display_format='DD MMM YYYY', id='prob-date-picker'), Button(id='clear_button')], className='timesliderline'), Span(children=Slider(min=1, max=2, step=1, marks={1: {'label': 'TUE 09'}, 2: {'label': 'WED 10', 'style': {'left': '', 'right': '-40px'}}}, value=1, id='prob-slider-graph'), id='prob-slider-container', className='timesliderline')], className='timeslider'), Div(children=[Span(DropdownMenu(children=[DropdownMenuItem(children='Light', id={'tag': 'view-style', 'index': 'carto-positron'}, active=True), DropdownMenuItem(children='Open street map', id={'tag': 'view-style', 'index': 'open-street-map'}, active=False), DropdownMenuItem(children='Terrain', id={'tag': 'view-style', 'index': 'stamen-terrain'}, active=False), DropdownMenuItem(children='ESRI', id={'tag': 'view-style', 'index': 'esri-world'}, active=False)], id='map-view-dropdown', direction='up', in_navbar=True, label='VIEW'))], id='map-view-dropdown-div')], id='layout-dropdown', className='layout-dropdown')], className='fixed-bottom navbar-timebar', dark=True, expand='lg', fixed='bottom', fluid=True)], id='forecast-tab', className='horizontal-menu', label='Forecast', value='forecast-tab')" in str(code.tab_forecast('prob', '20120120', '20220808')) + assert "id='forecast-tab', className='horizontal-menu', label='Forecast', value='forecast-tab'" in str(code.tab_forecast('prob', '20120120', '20220808')) + assert "Div(id={'tag': 'tab-name', 'index': 'prob'})" in str(code.tab_forecast('prob', '20120120', '20220808').children[0]) + assert "Toast(children=[P(children='3 day forecast available starting Apr 01 2023', className='mb1')" in str(code.tab_forecast('prob', '20120120', '20220808').children[2]) + assert "date='20220808" in str(code.tab_forecast('prob', '20120120', '20220808').children[4]) def test_expand_dropdown(): assert "{'models': True, 'prob': False, 'was': False}" in str(code.expand_dropdown('models')) diff --git a/tests/test_interp.py b/tests/test_interp.py new file mode 100644 index 0000000000000000000000000000000000000000..15c7ad275684d447b0396908798f938c8918c403 --- /dev/null +++ b/tests/test_interp.py @@ -0,0 +1,29 @@ +import pytest +import importlib +import xarray as xr +import dask +import numpy as np +code = importlib.import_module('preproc.interp') + +# def test_plot_station(): +# assert code.plot_station(0) == 0 +# assert code.plot_station(0) == 1 +# +def test_preprocess(): + # Create sample dataset with 10 timesteps + data = xr.DataArray( + np.random.randn(10, 3, 3), + dims=("time", "lat", "lon"), + coords={"time": range(10), "lat": [10, 20, 30], "lon": [-120, -110, -100]}, + ) + ds = xr.Dataset({"var": data}) + + # Test that preprocess function keeps only first 5 timesteps + preprocessed_ds = code.preprocess(ds, n=5) + assert preprocessed_ds.dims == {"time": 5, "lat": 3, "lon": 3} + assert preprocessed_ds.coords["time"].values.tolist() == [0, 1, 2, 3, 4] + + # Test that preprocess function keeps only first 3 timesteps + preprocessed_ds = code.preprocess(ds, n=3) + assert preprocessed_ds.dims == {"time": 3, "lat": 3, "lon": 3} + assert preprocessed_ds.coords["time"].values.tolist() == [0, 1, 2] diff --git a/tests/test_median_calc.py b/tests/test_median_calc.py new file mode 100644 index 0000000000000000000000000000000000000000..e0d7fccaffb62e4077dc46ea15686b6fd2d1bd4f --- /dev/null +++ b/tests/test_median_calc.py @@ -0,0 +1,9 @@ +import pytest +import importlib +import os +code = importlib.import_module('preproc.median_calc') + +# main_output_path = "/data/products/median/" +# archive_path = os.path.join(main_output_path, "tmp") +# def test_generate_median_file(): +# assert code.generate_median_file('20220505') == 0