Telemetry-Analysis / src /dash_callbacks.py
nasim-raj-laskar
Fizz
af286ff
import html
from dash import ClientsideFunction, Input, Output, State, dcc, no_update #type: ignore
from .dash_data import load_session
from .dash_figures import multiline, track_map
def register_callbacks(app, cfg: dict):
sessions_dir = cfg["output"]["sessions_dir"]
theme = cfg["theme"]
chart_cfg = cfg["charts"]
tabs_cfg = cfg["tabs"]
tab_plots = {t["id"]: t.get("plots", []) for t in tabs_cfg}
@app.callback(Output("session-header", "children"), Input("session-select", "value"))
def update_header(session):
if not session:
return ""
_, info = load_session(sessions_dir, session)
track = html.escape(info["track"])
if info.get("track_configuration"):
track += f" ({html.escape(info['track_configuration'])})"
car = html.escape(str(info['car']))
max_rpm = html.escape(str(info['max_rpm']))
max_fuel = html.escape(str(info['max_fuel_kg']))
return f"Car: {car} | Track: {track} | Max RPM: {max_rpm} | Fuel: {max_fuel} kg"
# show/hide the two content areas based on active tab
@app.callback(
Output("tab-content", "style"),
Output("map-tab-content", "style"),
Input("tabs", "value"),
)
def toggle_content_areas(tab):
show = {"display": "block", "marginTop": "12px"}
hide = {"display": "none", "marginTop": "12px"}
if tab == "map":
return hide, show
return show, hide
# regular (non-map) tabs
@app.callback(
Output("tab-content", "children"),
Input("session-select", "value"),
Input("tabs", "value"),
)
def update_tab(session, tab):
if not session or tab == "map":
return ""
df, _ = load_session(sessions_dir, session)
return [
dcc.Graph(
id=f"g-{p['id']}",
figure=multiline(df, p, theme, chart_cfg),
config={"displayModeBar": False},
)
for p in tab_plots.get(tab, [])
]
# rebuild map figure when session or colour changes
@app.callback(
Output("g-map", "figure"),
Output("map-slider", "max"),
Output("map-pos-store","data"),
Input("session-select", "value"),
Input("map-color-select", "value"),
)
def update_map(session, color_col):
if not session:
return no_update, no_update, no_update
df, _ = load_session(sessions_dir, session)
if "pos_x" not in df.columns or "pos_z" not in df.columns:
return no_update, no_update, no_update
fig = track_map(df, 0, color_col or "speed_kmh", theme)
store = {"pos_x": df["pos_x"].tolist(), "pos_z": df["pos_z"].tolist()}
return fig, len(df) - 1, store
# move car marker — pure JS, no server round-trip
app.clientside_callback(
ClientsideFunction(namespace="map", function_name="move_marker"),
Output("map-dummy", "data"),
Input("map-slider", "value"),
State("map-pos-store", "data"),
prevent_initial_call=True,
)