Skip to content

Commit

Permalink
Merge pull request #108 from ImperialCollegeLondon/playback
Browse files Browse the repository at this point in the history
Slider to update playback speed
  • Loading branch information
tsmbland authored Dec 14, 2023
2 parents 7dcc1bc + a881a9f commit a3f21ea
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 34 deletions.
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

0 comments on commit a3f21ea

Please sign in to comment.