Skip to content

Commit

Permalink
Reorganize callbacks and implement add gap
Browse files Browse the repository at this point in the history
Separate loading session info and laps after the load session button is clicked into two functions.

Driver dropdowns are now set when session info changes.

Y-axis option dropdowns are set when lap data changes.
  • Loading branch information
Casper-Guo committed Aug 10, 2024
1 parent 4c01ae0 commit cfd6d51
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 18 deletions.
101 changes: 84 additions & 17 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@

import f1_visualization.plotly_dash.graphs as pg
from f1_visualization._consts import CURRENT_SEASON, SPRINT_FORMATS
from f1_visualization.plotly_dash.layout import (
app_layout,
)
from f1_visualization.plotly_dash.layout import app_layout, line_y_options, scatter_y_options
from f1_visualization.visualization import get_session_info, load_laps

Session_info: TypeAlias = tuple[int, str, list[str]]
Expand Down Expand Up @@ -151,11 +149,7 @@ def enable_load_session(season: int | None, event: str | None, session: str | No


@callback(
Output("drivers", "options"),
Output("drivers", "value"),
Output("drivers", "disabled"),
Output("session-info", "data"),
Output("laps", "data"),
Input("load-session", "n_clicks"),
State("season", "value"),
State("event", "value"),
Expand All @@ -169,27 +163,100 @@ def get_session_metadata(
event: str,
session: str,
teammate_comp: bool,
) -> tuple[list[str], list, bool, Session_info, dict]:
) -> tuple[list[str], list, bool, Session_info]:
"""
Store session metadata and populate driver dropdown.
Store round number, event name, and the list of drivers into browser cache.
Can assume that season, event, and session are all set (not None).
"""
round_number, event_name, drivers = get_session_info(
season, event, session, teammate_comp=teammate_comp
)

return (round_number, event_name, drivers)


@callback(
Output("laps", "data"),
Input("load-session", "n_clicks"),
State("season", "value"),
State("event", "value"),
State("session", "value"),
prevent_initial_call=True,
)
def get_session_laps(
_: int, # ignores actual_value of n_clicks
season: int,
event: str,
session: str,
) -> dict:
"""
Save the laps of the selected session into browser cache.
Can assume that season, event, and session are all set (not None).
"""
included_laps = DF_DICT[season][session]
included_laps = included_laps[included_laps["RoundNumber"] == round_number]
included_laps = included_laps[included_laps["EventName"] == event]
included_laps = df_convert_timedelta(included_laps)

return (
drivers,
drivers,
False,
(round_number, event_name, drivers),
included_laps.to_dict(),
)
return included_laps.to_dict()


@callback(
Output("drivers", "options"),
Output("drivers", "value"),
Output("drivers", "disabled"),
Output("gap-drivers", "options"),
Output("gap-drivers", "value"),
Output("gap-drivers", "disabled"),
Input("session-info", "data"),
prevent_initial_call=True,
)
def set_driver_dropdowns(session_info: Session_info):
"""Configure driver dropdowns."""
drivers = session_info[2]
return drivers, drivers, False, drivers, None, False


@callback(
Output("scatter-y", "options"),
Output("line-y", "options"),
Input("laps", "data"),
prevent_initial_call=True,
)
def set_y_axis_dropdowns(data: dict) -> list[dict[str, str]]:
"""Update y axis options based on the columns in the laps dataframe."""

def readable_gap_col_name(col: str) -> str:
"""Convert Pandas GapTox column names to the more readable Gap to x."""
return f"Gap to {col[-3:]} (s)"

gap_cols = filter(lambda x: x.startswith("Gap"), data.keys())
gap_col_options = [{"label": readable_gap_col_name(col), "value": col} for col in gap_cols]
return scatter_y_options + gap_col_options, line_y_options + gap_col_options


@callback(
Output("laps", "data", allow_duplicate=True),
Input("add-gap", "n_clicks"),
State("gap-drivers", "value"),
State("laps", "data"),
running=[
(Output("gap-drivers", "disabled"), True, False),
(Output("add-gap", "disabled"), True, False),
(Output("add-gap", "children"), "Calculating...", "Add Gap"),
(Output("add-gap", "color"), "warning", "success"),
],
prevent_initial_call=True,
)
def add_gap_to_driver(_: int, drivers: list[str], data: dict) -> dict:
"""Amend the dataframe in cache and add driver gap columns."""
laps = pd.DataFrame.from_dict(data)
for driver in drivers:
if f"GapTo{driver}" not in laps.columns:
laps = add_gap(driver, laps)

return laps.to_dict()


@callback(
Expand Down
2 changes: 1 addition & 1 deletion f1_visualization/plotly_dash/graphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def stats_lineplot(
)

fig = shade_sc_periods(fig, sc_laps, vsc_laps)
if y == "Position":
if y == "Position" or y.startswith("Gap"):
fig.update_yaxes(autorange="reversed")

num_laps = included_laps["LapNumber"].max()
Expand Down

0 comments on commit cfd6d51

Please sign in to comment.