Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slider to update playback speed #108

Merged
merged 11 commits into from
Dec 14, 2023
39 changes: 33 additions & 6 deletions app/app.py
Original file line number Diff line number Diff line change
@@ -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, State, callback, dcc, html # type: ignore

from . import log

##################
interval = 7000
##################

app = Dash(__package__, use_pages=True, update_title=None)

app.layout = html.Div(
Expand All @@ -17,13 +13,44 @@
},
children=[
dash.page_container,
dcc.Interval(id="figure_interval", interval=interval),
dcc.Store(id="figure_interval", data=0),
dcc.Interval(id="sync_interval", interval=100),
],
)

server = app.server
log.info("Gridlington Visualisation System is running...")


@callback(
[Output("figure_interval", "data")],
[Input("sync_interval", "n_intervals")],
[State("figure_interval", "data")],
)
def update_figure_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_sync (int): Number of times this callback has run
n_intervals_figures (int): Number of times the figures have updated

Returns:
N_INTERVALS_DATA (int): Number of times the data has updated
"""
from .data import N_INTERVALS_DATA

return (
dash.no_update
if n_intervals_figures == N_INTERVALS_DATA
else (N_INTERVALS_DATA,)
)


if __name__ == "__main__":
app.run_server(debug=True)
34 changes: 19 additions & 15 deletions app/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
from . import LIVE_MODEL, log
from .datahub_api import get_opal_data, get_wesim_data # , get_dsr_data

##################
interval = 7000
##################
N_INTERVALS_DATA = 0

DF_OPAL = pd.DataFrame({"Col": [0]})

Expand All @@ -24,37 +22,43 @@
else:
WESIM = {"df": pd.DataFrame({"Col": [0]})}

data_interval = dcc.Interval(id="data_interval", interval=interval)
empty_output = dcc.Store(id="empty", data=[])
data_interval = dcc.Interval(id="data_interval")


@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
global DF_OPAL, N_INTERVALS_DATA

if n_intervals is None:
raise PreventUpdate

data_ended = False
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")
data_ended = True

N_INTERVALS_DATA = n_intervals
return (data_ended,)
6 changes: 4 additions & 2 deletions app/pages/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -90,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,
Expand All @@ -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]:
Expand All @@ -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,
Expand Down
40 changes: 35 additions & 5 deletions app/pages/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
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, empty_output
from ..data import data_interval

dash.register_page(__name__)

Expand Down Expand Up @@ -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=2,
max=10,
step=1,
value=7,
),
style={"width": "100%"},
),
html.Label(
"Update Interval (s)",
style={"text-align": "center"},
),
],
style={
"width": "40%",
"flex-direction": "column",
"justify-content": "center",
"display": "none" if LIVE_MODEL else "flex",
},
),
get_button("default", "iconoir:undo"),
],
),
Expand All @@ -194,7 +216,6 @@ def get_button(func: str, icon: str) -> html.Button:
],
),
data_interval,
empty_output,
],
)

Expand Down Expand Up @@ -305,3 +326,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_data_interval(value: int) -> tuple[int]:
"""Callback to update the data interval."""
log.debug(f"Update interval set to {value} seconds.")
return (value * 1000,)
6 changes: 4 additions & 2 deletions app/pages/market.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -79,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,
Expand All @@ -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]:
Expand All @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions app/pages/marketsreserve.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -76,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,
Expand All @@ -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.
Expand All @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions app/pages/supplydemand.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -77,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,
Expand All @@ -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.
Expand All @@ -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