From 1ca2e7e976998fdd6302cfb10aa3de92a7d3d2c7 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Tue, 12 Dec 2023 11:43:39 +0000 Subject: [PATCH 01/11] Add dummy slider --- app/pages/control.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/app/pages/control.py b/app/pages/control.py index 860228f..2faded7 100644 --- a/app/pages/control.py +++ b/app/pages/control.py @@ -171,11 +171,33 @@ def get_button(func: str, icon: str) -> html.Button: "display": "flex", "justify-content": "space-around", "padding": "10px", - "width": "66%", - "margin": "auto", }, children=[ get_button("update", "mdi:tick"), + html.Div( + children=[ + html.Div( + dcc.Slider( + id="update-interval-slider", + min=1, + max=10, + step=1, + value=7, + ), + style={"width": "100%"}, + ), + html.Label( + "Update Interval (s)", + style={"text-align": "center"}, + ), + ], + style={ + "width": "40%", + "display": "flex", + "flex-direction": "column", + "justify-content": "center", + }, + ), get_button("default", "iconoir:undo"), ], ), From fcbb67966b2cfbf920c3ccebbe8a67b60023e791 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Tue, 12 Dec 2023 12:09:12 +0000 Subject: [PATCH 02/11] Callback to data interval --- app/pages/control.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/pages/control.py b/app/pages/control.py index 2faded7..7ddd74a 100644 --- a/app/pages/control.py +++ b/app/pages/control.py @@ -327,3 +327,12 @@ def default_button_click(n_clicks: int | None) -> list[str]: get_default("PC02-Left"), get_default("PC02-Right"), ] + + +@callback( + [Output("data_interval", "interval")], [Input("update-interval-slider", "value")] +) +def update_interval(value: int) -> list[int]: + """Returns the update interval value.""" + log.debug(f"Update interval set to {value} seconds.") + return [value * 1000] From c6f91031107b2ef9e34695e8677baeb82b534ba7 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Tue, 12 Dec 2023 15:03:26 +0000 Subject: [PATCH 03/11] Terminate updates at end of pre-set data --- app/data.py | 23 +++++++++++++---------- app/pages/control.py | 5 ++--- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/app/data.py b/app/data.py index 67d0612..91a0250 100644 --- a/app/data.py +++ b/app/data.py @@ -25,22 +25,22 @@ WESIM = {"df": pd.DataFrame({"Col": [0]})} data_interval = dcc.Interval(id="data_interval", interval=interval) -empty_output = dcc.Store(id="empty", data=[]) @callback( - [Output("empty", "data")], + [Output("data_interval", "disabled")], [Input("data_interval", "n_intervals")], ) -def update_data(n_intervals: int) -> tuple[list[None],]: - """Function to update the data. +def update_data(n_intervals: int) -> tuple[bool,]: + """Function to update OPAL data. Args: - n_intervals (int): The number of times this page has updated. - indexes by 1 every 7 seconds. + n_intervals (int): The number of times the data has updated. + indexes by 1 every interval. Returns: - Opal data dictionary + tuple[bool,]: Boolean that specifies whether the iterator should + terminate """ global DF_OPAL @@ -49,12 +49,15 @@ def update_data(n_intervals: int) -> tuple[list[None],]: raise PreventUpdate if LIVE_MODEL: - log.debug("Updating plots from live model") + log.debug("Updating data from live model") data_opal = get_opal_data() DF_OPAL = pd.DataFrame(**data_opal) # type: ignore[call-overload] else: from .pre_set_data import OPAL_DATA - log.debug("Updating plots with pre-set data") + log.debug("Updating pre-set data") DF_OPAL = OPAL_DATA.loc[:n_intervals] - return ([],) + if n_intervals == len(OPAL_DATA): + log.debug("Reached end of pre-set data") + return (True,) + return (False,) diff --git a/app/pages/control.py b/app/pages/control.py index 7ddd74a..709f6ee 100644 --- a/app/pages/control.py +++ b/app/pages/control.py @@ -6,7 +6,7 @@ from .. import core_api as core from .. import log -from ..data import data_interval, empty_output +from ..data import data_interval dash.register_page(__name__) @@ -182,7 +182,7 @@ def get_button(func: str, icon: str) -> html.Button: min=1, max=10, step=1, - value=7, + value=data_interval.interval / 1000, ), style={"width": "100%"}, ), @@ -216,7 +216,6 @@ def get_button(func: str, icon: str) -> html.Button: ], ), data_interval, - empty_output, ], ) From ba18de7a40762577410068ff7bd82d784668e074 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Tue, 12 Dec 2023 16:01:38 +0000 Subject: [PATCH 04/11] Log messages for figures --- app/data.py | 7 ++++--- app/pages/agent.py | 4 +++- app/pages/market.py | 4 +++- app/pages/marketsreserve.py | 4 +++- app/pages/supplydemand.py | 4 +++- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/data.py b/app/data.py index 91a0250..75f4aeb 100644 --- a/app/data.py +++ b/app/data.py @@ -25,6 +25,7 @@ WESIM = {"df": pd.DataFrame({"Col": [0]})} data_interval = dcc.Interval(id="data_interval", interval=interval) +data_ended = False @callback( @@ -43,7 +44,7 @@ def update_data(n_intervals: int) -> tuple[bool,]: terminate """ - global DF_OPAL + global DF_OPAL, data_ended if n_intervals is None: raise PreventUpdate @@ -59,5 +60,5 @@ def update_data(n_intervals: int) -> tuple[bool,]: DF_OPAL = OPAL_DATA.loc[:n_intervals] if n_intervals == len(OPAL_DATA): log.debug("Reached end of pre-set data") - return (True,) - return (False,) + data_ended = True + return (data_ended,) diff --git a/app/pages/agent.py b/app/pages/agent.py index 99fb8e1..e4ab1cf 100644 --- a/app/pages/agent.py +++ b/app/pages/agent.py @@ -14,6 +14,7 @@ import plotly.graph_objects as go # type: ignore from dash import Input, Output, callback, dcc # type: ignore +from .. import log from ..figures import ( generate_agent_activity_breakdown_fig, generate_dsr_commands_fig, @@ -99,7 +100,7 @@ def update_figures( Args: n_intervals (int): The number of times this page has updated. - indexes by 1 every 7 seconds. + indexes by 1 every interval. Returns: tuple[go.Figure, go.Figure, go.Figure, go.Figure, px.line]: @@ -113,6 +114,7 @@ def update_figures( agent_activity_breakdown_fig = generate_agent_activity_breakdown_fig(DF_OPAL) ev_charging_breakdown_fig = generate_ev_charging_breakdown_fig(DF_OPAL) dsr_commands_fig = generate_dsr_commands_fig(DF_OPAL) + log.debug("Updating figures on Agent page") return ( map_fig, sld_fig, diff --git a/app/pages/market.py b/app/pages/market.py index c9bd706..7f197c7 100644 --- a/app/pages/market.py +++ b/app/pages/market.py @@ -14,6 +14,7 @@ from dash import Input, Output, callback, dcc # type: ignore from plotly import graph_objects as go # type: ignore +from .. import log from ..figures import ( generate_dsr_commands_fig, generate_dsr_fig, @@ -88,7 +89,7 @@ def update_figures( Args: n_intervals (int): The number of times this page has updated. - indexes by 1 every 7 seconds. + indexes by 1 every interval. Returns: tuple[px.line, go.Figure, go.Figure, px.line]: @@ -100,6 +101,7 @@ def update_figures( intraday_market_bids_fig = generate_intraday_market_bids_fig(DF_OPAL) dsr_fig = generate_dsr_fig(df) # TODO: replace with df_dsr when available dsr_commands_fig = generate_dsr_commands_fig(DF_OPAL) + log.debug("Updating figures on Market page") return ( energy_deficit_fig, intraday_market_bids_fig, diff --git a/app/pages/marketsreserve.py b/app/pages/marketsreserve.py index 37489cf..c68e063 100644 --- a/app/pages/marketsreserve.py +++ b/app/pages/marketsreserve.py @@ -13,6 +13,7 @@ from dash import Input, Output, callback, dcc # type: ignore from plotly import graph_objects as go # type: ignore +from .. import log from ..data import WESIM from ..figures import ( generate_balancing_market_fig, @@ -85,7 +86,7 @@ def update_figures( Args: n_intervals (int): The number of times this page has updated. - indexes by 1 every 7 seconds. + indexes by 1 every interval. Returns: tuple[go.Figure, go.Figure]: The new figures. @@ -94,6 +95,7 @@ def update_figures( balancing_market_fig = generate_balancing_market_fig(DF_OPAL) intraday_market_sys_fig = generate_intraday_market_sys_fig(DF_OPAL) + log.debug("Updating figures of Markets and Reserve page") return ( balancing_market_fig, intraday_market_sys_fig, diff --git a/app/pages/supplydemand.py b/app/pages/supplydemand.py index 1fa129c..cfe8cda 100644 --- a/app/pages/supplydemand.py +++ b/app/pages/supplydemand.py @@ -13,6 +13,7 @@ import plotly.express as px # type: ignore from dash import Input, Output, callback, dcc # type: ignore +from .. import log from ..figures import ( generate_gen_split_fig, generate_system_freq_fig, @@ -86,7 +87,7 @@ def update_figures( Args: n_intervals (int): The number of times this page has updated. - indexes by 1 every 7 seconds. + indexes by 1 every interval. Returns: tuple[px.pie, px.line, px.line, px.line]: The new figures. @@ -97,4 +98,5 @@ def update_figures( total_gen_fig = generate_total_gen_fig(DF_OPAL) total_dem_fig = generate_total_dem_fig(DF_OPAL) system_freq_fig = generate_system_freq_fig(DF_OPAL) + log.debug("Updating figures on Supply & Demand page") return gen_split_fig, total_gen_fig, total_dem_fig, system_freq_fig From 5026579e86acc21dbc53edf9da2611dddb97eff4 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Tue, 12 Dec 2023 16:26:10 +0000 Subject: [PATCH 05/11] Synchronise figure updates with data updates --- app/app.py | 29 +++++++++++++++++++++++------ app/data.py | 6 +----- app/pages/control.py | 10 ++++++++-- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/app/app.py b/app/app.py index f3f0c5f..99e87e3 100644 --- a/app/app.py +++ b/app/app.py @@ -1,13 +1,9 @@ """Sets up the server for the Dash app.""" import dash # type: ignore -from dash import Dash, dcc, html # type: ignore +from dash import Dash, Input, Output, callback, dcc, html # type: ignore from . import log -################## -interval = 7000 -################## - app = Dash(__package__, use_pages=True, update_title=None) app.layout = html.Div( @@ -17,7 +13,7 @@ }, children=[ dash.page_container, - dcc.Interval(id="figure_interval", interval=interval), + dcc.Interval(id="figure_interval"), ], ) @@ -25,5 +21,26 @@ log.info("Gridlington Visualisation System is running...") +@callback( + [Output("figure_interval", "disabled"), Output("figure_interval", "interval")], + [Input("figure_interval", "n_intervals")], +) +def update_interval( + n_intervals: int, +) -> tuple[bool, int]: + """_summary_. + + Args: + n_intervals (int): _description_ + + Returns: + tuple[bool, int]: _description_ + """ + from .data import data_ended + from .pages.control import interval + + return (data_ended, interval) + + if __name__ == "__main__": app.run_server(debug=True) diff --git a/app/data.py b/app/data.py index 75f4aeb..2a5c8a8 100644 --- a/app/data.py +++ b/app/data.py @@ -6,10 +6,6 @@ from . import LIVE_MODEL, log from .datahub_api import get_opal_data, get_wesim_data # , get_dsr_data -################## -interval = 7000 -################## - DF_OPAL = pd.DataFrame({"Col": [0]}) WESIM_START_DATE = "2035-01-22 00:00" # corresponding to hour 0 TODO: check @@ -24,7 +20,7 @@ else: WESIM = {"df": pd.DataFrame({"Col": [0]})} -data_interval = dcc.Interval(id="data_interval", interval=interval) +data_interval = dcc.Interval(id="data_interval") data_ended = False diff --git a/app/pages/control.py b/app/pages/control.py index 709f6ee..1da29cf 100644 --- a/app/pages/control.py +++ b/app/pages/control.py @@ -10,6 +10,9 @@ dash.register_page(__name__) +################## +interval = 7000 +################## options = [key for key in core.INIT_SECTIONS.keys() if key != "Control"] @@ -179,10 +182,10 @@ def get_button(func: str, icon: str) -> html.Button: html.Div( dcc.Slider( id="update-interval-slider", - min=1, + min=2, max=10, step=1, - value=data_interval.interval / 1000, + value=interval / 1000, ), style={"width": "100%"}, ), @@ -333,5 +336,8 @@ def default_button_click(n_clicks: int | None) -> list[str]: ) def update_interval(value: int) -> list[int]: """Returns the update interval value.""" + global interval + log.debug(f"Update interval set to {value} seconds.") + interval = value * 1000 return [value * 1000] From cf4fe9db14da236b4d98b7e88a134c8491eccd33 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Tue, 12 Dec 2023 16:34:48 +0000 Subject: [PATCH 06/11] Docstrings --- app/app.py | 11 ++++++----- app/pages/control.py | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/app.py b/app/app.py index 99e87e3..ef127cc 100644 --- a/app/app.py +++ b/app/app.py @@ -25,21 +25,22 @@ [Output("figure_interval", "disabled"), Output("figure_interval", "interval")], [Input("figure_interval", "n_intervals")], ) -def update_interval( +def update_figure_interval( n_intervals: int, ) -> tuple[bool, int]: - """_summary_. + """Callback to synchronise the figure interval with the data interval. Args: - n_intervals (int): _description_ + n_intervals (int): Number of times the figures have updated Returns: - tuple[bool, int]: _description_ + data_ended (bool): Whether the data has ended + interval (int): The interval between updates """ from .data import data_ended from .pages.control import interval - return (data_ended, interval) + return data_ended, interval if __name__ == "__main__": diff --git a/app/pages/control.py b/app/pages/control.py index 1da29cf..e5927f4 100644 --- a/app/pages/control.py +++ b/app/pages/control.py @@ -334,8 +334,8 @@ def default_button_click(n_clicks: int | None) -> list[str]: @callback( [Output("data_interval", "interval")], [Input("update-interval-slider", "value")] ) -def update_interval(value: int) -> list[int]: - """Returns the update interval value.""" +def update_data_interval(value: int) -> list[int]: + """Callback to update the data interval.""" global interval log.debug(f"Update interval set to {value} seconds.") From e12bd375dc9b3e09af374fbb073049619f43c94a Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Tue, 12 Dec 2023 16:57:12 +0000 Subject: [PATCH 07/11] Switch list to tuple for consistency --- app/pages/control.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/pages/control.py b/app/pages/control.py index e5927f4..8cfbd50 100644 --- a/app/pages/control.py +++ b/app/pages/control.py @@ -334,10 +334,10 @@ def default_button_click(n_clicks: int | None) -> list[str]: @callback( [Output("data_interval", "interval")], [Input("update-interval-slider", "value")] ) -def update_data_interval(value: int) -> list[int]: +def update_data_interval(value: int) -> tuple[int]: """Callback to update the data interval.""" global interval log.debug(f"Update interval set to {value} seconds.") interval = value * 1000 - return [value * 1000] + return (interval,) From 4bb61756d5f6b1c8e2d62acca7dfd81a02144694 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 13 Dec 2023 11:53:10 +0000 Subject: [PATCH 08/11] Separate synchronisation interval --- app/app.py | 3 ++- app/pages/control.py | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/app.py b/app/app.py index ef127cc..c27549e 100644 --- a/app/app.py +++ b/app/app.py @@ -14,6 +14,7 @@ children=[ dash.page_container, dcc.Interval(id="figure_interval"), + dcc.Interval(id="sync_interval", interval=1000), ], ) @@ -23,7 +24,7 @@ @callback( [Output("figure_interval", "disabled"), Output("figure_interval", "interval")], - [Input("figure_interval", "n_intervals")], + [Input("sync_interval", "n_intervals")], ) def update_figure_interval( n_intervals: int, diff --git a/app/pages/control.py b/app/pages/control.py index 8cfbd50..08b1010 100644 --- a/app/pages/control.py +++ b/app/pages/control.py @@ -10,9 +10,7 @@ dash.register_page(__name__) -################## interval = 7000 -################## options = [key for key in core.INIT_SECTIONS.keys() if key != "Control"] From 1c38cdf3177ef23580c65938eff4654b200a79fd Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 13 Dec 2023 13:28:12 +0000 Subject: [PATCH 09/11] Better synchronisation method --- app/app.py | 34 +++++++++++++++++++++------------- app/data.py | 8 ++++++-- app/pages/agent.py | 2 +- app/pages/market.py | 2 +- app/pages/marketsreserve.py | 2 +- app/pages/supplydemand.py | 2 +- 6 files changed, 31 insertions(+), 19 deletions(-) diff --git a/app/app.py b/app/app.py index c27549e..7e04606 100644 --- a/app/app.py +++ b/app/app.py @@ -1,6 +1,6 @@ """Sets up the server for the Dash app.""" import dash # type: ignore -from dash import Dash, Input, Output, callback, dcc, html # type: ignore +from dash import Dash, Input, Output, State, callback, dcc, html # type: ignore from . import log @@ -13,8 +13,8 @@ }, children=[ dash.page_container, - dcc.Interval(id="figure_interval"), - dcc.Interval(id="sync_interval", interval=1000), + dcc.Store(id="figure_interval", data=0), + dcc.Interval(id="sync_interval", interval=100), ], ) @@ -23,25 +23,33 @@ @callback( - [Output("figure_interval", "disabled"), Output("figure_interval", "interval")], + [Output("figure_interval", "data")], [Input("sync_interval", "n_intervals")], + [State("figure_interval", "data")], ) def update_figure_interval( - n_intervals: int, -) -> tuple[bool, int]: - """Callback to synchronise the figure interval with the data interval. + n_intervals_sync: int, + n_intervals_figures: int, +) -> tuple[int]: + """Callback to synchronise figure_interval with data_interval. + + This pulls in N_INTERVALS_DATA (number of times the data has updated) from + the data module and increments figure_interval accordingly. Args: - n_intervals (int): Number of times the figures have updated + n_intervals_sync (int): Number of times this callback has run + n_intervals_figures (int): Number of times the figures have updated Returns: - data_ended (bool): Whether the data has ended - interval (int): The interval between updates + N_INTERVALS_DATA (int): Number of times the data has updated """ - from .data import data_ended - from .pages.control import interval + from .data import N_INTERVALS_DATA - return data_ended, interval + return ( + dash.no_update + if n_intervals_figures == N_INTERVALS_DATA + else (N_INTERVALS_DATA,) + ) if __name__ == "__main__": diff --git a/app/data.py b/app/data.py index 2a5c8a8..8969001 100644 --- a/app/data.py +++ b/app/data.py @@ -6,6 +6,8 @@ from . import LIVE_MODEL, log from .datahub_api import get_opal_data, get_wesim_data # , get_dsr_data +N_INTERVALS_DATA = 0 + DF_OPAL = pd.DataFrame({"Col": [0]}) WESIM_START_DATE = "2035-01-22 00:00" # corresponding to hour 0 TODO: check @@ -21,7 +23,6 @@ WESIM = {"df": pd.DataFrame({"Col": [0]})} data_interval = dcc.Interval(id="data_interval") -data_ended = False @callback( @@ -40,11 +41,12 @@ def update_data(n_intervals: int) -> tuple[bool,]: terminate """ - global DF_OPAL, data_ended + global DF_OPAL, N_INTERVALS_DATA if n_intervals is None: raise PreventUpdate + data_ended = False if LIVE_MODEL: log.debug("Updating data from live model") data_opal = get_opal_data() @@ -57,4 +59,6 @@ def update_data(n_intervals: int) -> tuple[bool,]: if n_intervals == len(OPAL_DATA): log.debug("Reached end of pre-set data") data_ended = True + + N_INTERVALS_DATA = n_intervals return (data_ended,) diff --git a/app/pages/agent.py b/app/pages/agent.py index e4ab1cf..b8e36f2 100644 --- a/app/pages/agent.py +++ b/app/pages/agent.py @@ -91,7 +91,7 @@ Output("ev_charging_breakdown_fig", "figure"), Output("dsr_commands_fig", "figure"), ], - [Input("figure_interval", "n_intervals")], + [Input("figure_interval", "data")], ) def update_figures( n_intervals: int, diff --git a/app/pages/market.py b/app/pages/market.py index 7f197c7..b1f0a0f 100644 --- a/app/pages/market.py +++ b/app/pages/market.py @@ -80,7 +80,7 @@ Output("graph-dsr", "figure"), Output("graph-dsr-commands", "figure"), ], - [Input("figure_interval", "n_intervals")], + [Input("figure_interval", "data")], ) def update_figures( n_intervals: int, diff --git a/app/pages/marketsreserve.py b/app/pages/marketsreserve.py index c68e063..e719fc8 100644 --- a/app/pages/marketsreserve.py +++ b/app/pages/marketsreserve.py @@ -77,7 +77,7 @@ Output("balancing_market_fig", "figure"), Output("intraday_market_sys_fig", "figure"), ], - [Input("figure_interval", "n_intervals")], + [Input("figure_interval", "data")], ) def update_figures( n_intervals: int, diff --git a/app/pages/supplydemand.py b/app/pages/supplydemand.py index cfe8cda..930897e 100644 --- a/app/pages/supplydemand.py +++ b/app/pages/supplydemand.py @@ -78,7 +78,7 @@ Output("graph-demand", "figure"), Output("graph-freq", "figure"), ], - [Input("figure_interval", "n_intervals")], + [Input("figure_interval", "data")], ) def update_figures( n_intervals: int, From 0dadec9dbdebf95e9d17fdefac6d024c28e3c62f Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Wed, 13 Dec 2023 14:11:17 +0000 Subject: [PATCH 10/11] Remove unised variable --- app/pages/control.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/pages/control.py b/app/pages/control.py index 08b1010..8ca7d71 100644 --- a/app/pages/control.py +++ b/app/pages/control.py @@ -10,7 +10,6 @@ dash.register_page(__name__) -interval = 7000 options = [key for key in core.INIT_SECTIONS.keys() if key != "Control"] @@ -183,7 +182,7 @@ def get_button(func: str, icon: str) -> html.Button: min=2, max=10, step=1, - value=interval / 1000, + value=7, ), style={"width": "100%"}, ), @@ -334,8 +333,5 @@ def default_button_click(n_clicks: int | None) -> list[str]: ) def update_data_interval(value: int) -> tuple[int]: """Callback to update the data interval.""" - global interval - log.debug(f"Update interval set to {value} seconds.") - interval = value * 1000 - return (interval,) + return (value * 1000,) From a881a9fb82dd4cb5a73d007b3b52d6e748569393 Mon Sep 17 00:00:00 2001 From: Tom Bland Date: Thu, 14 Dec 2023 20:11:45 +0000 Subject: [PATCH 11/11] Hide slider when running live model --- app/pages/control.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/pages/control.py b/app/pages/control.py index 8ca7d71..981bc1e 100644 --- a/app/pages/control.py +++ b/app/pages/control.py @@ -4,8 +4,8 @@ from dash import Input, Output, State, callback, ctx, dcc, html # type: ignore from dash_iconify import DashIconify # type: ignore +from .. import LIVE_MODEL, log from .. import core_api as core -from .. import log from ..data import data_interval dash.register_page(__name__) @@ -193,9 +193,9 @@ def get_button(func: str, icon: str) -> html.Button: ], style={ "width": "40%", - "display": "flex", "flex-direction": "column", "justify-content": "center", + "display": "none" if LIVE_MODEL else "flex", }, ), get_button("default", "iconoir:undo"),