Formula Student Autonomous Systems
The code for the main driverless system
Loading...
Searching...
No Matches
dashboard.py
Go to the documentation of this file.
1import dash
2from dash import dcc, html
3from dash.dependencies import Input, Output, State
4import plotly.express as px
5import pandas as pd
6import os
7import sys
8import shutil
9import atexit
10
11sys.path.append(
12 os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "cloud_storage"))
13)
14from bucket_operations import list_blobs, download_csv_from_bucket_to_folder
15
16# Initialize the Dash app
17app = dash.Dash(__name__)
18app.config.suppress_callback_exceptions = True
19
20# List of available CSV files in the bucket
21csv_files = list_blobs("as_evaluation")
22
23# Define available dashboards
24available_dashboards = [
25 "Evaluator_perception",
26 "Evaluator_state_estimation",
27 "Evaluator_planning",
28 "Evaluator_control",
29 "Perception_exec_time",
30 "State_estimation_exec_time",
31 "Planning_exec_time",
32 "Planning_cone_coloring",
33 "Power_log",
34 "Test",
35]
36
37# Define the main layout of the app
38app.layout = html.Div(
39 [
40 dcc.Store(id="stored-csv-data", storage_type="memory"),
41 html.H1("Select Dashboard"),
42 dcc.Dropdown(
43 id="dashboard-dropdown",
44 options=[
45 {"label": dashboard, "value": dashboard}
46 for dashboard in available_dashboards
47 ],
48 value=None,
49 placeholder="Select a dashboard",
50 ),
51 html.Div(id="dashboard-content"),
52 ]
53)
54
55
56# Define the layout for each dashboard
57def get_dashboard_layout(dashboard):
58 dashboard_conditions = {
59 "Evaluator_perception": "evaluator/perception",
60 "Evaluator_state_estimation": "evaluator/se",
61 "Evaluator_planning": "evaluator/planning",
62 "Evaluator_control": "evaluator/control",
63 "Perception_exec_time": "perception/perception/",
64 "State_estimation_exec_time": "state_est",
65 "Planning_exec_time": "planning_exec_time",
66 "Planning_cone_coloring": "planning_cone_coloring",
67 "Power_log": "power_log",
68 "Test": "test",
69 }
70
71 condition = dashboard_conditions.get(dashboard, "")
72
73 # Filter CSV files based on condition
74 csv_files = [file for file in list_blobs("as_evaluation") if condition in file]
75
76 return html.Div(
77 [
78 html.H2(f"{dashboard} CSV files"),
79 dcc.Dropdown(
80 id=f"csv-dropdown-{dashboard}",
81 options=[{"label": f, "value": f} for f in csv_files],
82 value=[],
83 multi=True,
84 placeholder="Select CSV files",
85 ),
86 html.Div(
87 [
88 dcc.Graph(
89 id=f"graph1-{dashboard}",
90 style={"width": "70%", "height": "500px"},
91 ),
92 html.Div(
93 [
94 html.Label("Y-Axis"),
95 dcc.Dropdown(
96 id=f"graph1-{dashboard}-metrics-dropdown",
97 multi=True,
98 style={"minWidth": "200px"},
99 ),
100 html.Br(),
101 html.Label("X-Axis"),
102 dcc.Dropdown(
103 id=f"x-axis-dropdown-{dashboard}-1",
104 style={"minWidth": "200px"},
105 ),
106 ],
107 id=f"graph1-metrics-{dashboard}",
108 style={"minWidth": "200px", "width": "25%"},
109 ),
110 ],
111 style={"display": "flex"},
112 ),
113 html.Div(
114 [
115 dcc.Graph(
116 id=f"graph2-{dashboard}",
117 style={"width": "70%", "height": "500px"},
118 ),
119 html.Div(
120 [
121 html.Label("Y-Axis"),
122 dcc.Dropdown(
123 id=f"graph2-{dashboard}-metrics-dropdown",
124 multi=True,
125 style={"minWidth": "200px"},
126 ),
127 html.Br(),
128 html.Label("X-Axis"),
129 dcc.Dropdown(
130 id=f"x-axis-dropdown-{dashboard}-2",
131 style={"minWidth": "200px"},
132 ),
133 ],
134 id=f"graph2-metrics-{dashboard}",
135 style={"minWidth": "200px", "width": "25%"},
136 ),
137 ],
138 style={"display": "flex"},
139 ),
140 html.Div(
141 [
142 dcc.Graph(
143 id=f"graph3-{dashboard}",
144 style={"width": "70%", "height": "500px"},
145 ),
146 html.Div(
147 [
148 html.Label("Y-Axis"),
149 dcc.Dropdown(
150 id=f"graph3-{dashboard}-metrics-dropdown",
151 multi=True,
152 style={"minWidth": "200px"},
153 ),
154 html.Br(),
155 html.Label("X-Axis"),
156 dcc.Dropdown(
157 id=f"x-axis-dropdown-{dashboard}-3",
158 style={"minWidth": "200px"},
159 ),
160 ],
161 id=f"graph3-metrics-{dashboard}",
162 style={"minWidth": "200px", "width": "25%"},
163 ),
164 ],
165 style={"display": "flex"},
166 ),
167 html.Div(
168 [
169 dcc.Graph(
170 id=f"graph4-{dashboard}",
171 style={"width": "70%", "height": "500px"},
172 ),
173 html.Div(
174 [
175 html.Label("Y-Axis"),
176 dcc.Dropdown(
177 id=f"graph4-{dashboard}-metrics-dropdown",
178 multi=True,
179 style={"minWidth": "200px"},
180 ),
181 html.Br(),
182 html.Label("X-Axis"),
183 dcc.Dropdown(
184 id=f"x-axis-dropdown-{dashboard}-3",
185 style={"minWidth": "200px"},
186 ),
187 ],
188 id=f"graph4-metrics-{dashboard}",
189 style={"minWidth": "200px", "width": "25%"},
190 ),
191 ],
192 style={"display": "flex"},
193 ),
194 html.Div(
195 [
196 dcc.Graph(
197 id=f"graph5-{dashboard}",
198 style={"width": "70%", "height": "500px"},
199 ),
200 html.Div(
201 [
202 html.Label("Y-Axis"),
203 dcc.Dropdown(
204 id=f"graph5-{dashboard}-metrics-dropdown",
205 multi=True,
206 style={"minWidth": "200px"},
207 ),
208 html.Br(),
209 html.Label("X-Axis"),
210 dcc.Dropdown(
211 id=f"x-axis-dropdown-{dashboard}-3",
212 style={"minWidth": "200px"},
213 ),
214 ],
215 id=f"graph5-metrics-{dashboard}",
216 style={"minWidth": "200px", "width": "25%"},
217 ),
218 ],
219 style={"display": "flex"},
220 ),
221 ]
222 )
223
224
225# Callback to update the layout based on selected dashboard
226@app.callback(
227 Output("dashboard-content", "children"), Input("dashboard-dropdown", "value")
228)
229def update_dashboard(selected_dashboard):
230 """!
231 Update the layout based on the selected dashboard.
232
233 Args:
234 selected_dashboard: The selected dashboard.
235 """
236 if selected_dashboard:
237 return get_dashboard_layout(selected_dashboard)
238 return html.Div()
239
240
241def download_and_combine_csvs(selected_csvs, temp_folder):
242 """!
243 Download and combine the selected CSV files.
244
245 Args:
246 selected_csvs: The selected CSV files.
247 temp_folder: The temporary folder to store the CSV files.
248 """
249 combined_df = pd.DataFrame()
250 for csv in selected_csvs:
251 download_csv_from_bucket_to_folder("as_evaluation", csv, temp_folder, csv)
252 temp_df = pd.read_csv(os.path.join(temp_folder, csv))
253 temp_df["Source"] = csv
254 combined_df = pd.concat([combined_df, temp_df], ignore_index=True)
255 return combined_df
256
257
258def create_update_metric_dropdowns_callback(dashboard, graph_number):
259 @app.callback(
260 [
261 Output(f"graph{graph_number}-{dashboard}-metrics-dropdown", "options"),
262 Output(f"x-axis-dropdown-{dashboard}-{graph_number}", "options"),
263 ],
264 [
265 Input(f"csv-dropdown-{dashboard}", "value"),
266 Input(f"stored-csv-data", "data"),
267 ],
268 State(f"csv-dropdown-{dashboard}", "value"),
269 )
270 def update_metric_dropdowns(selected_csvs, stored_data, current_selected_csvs):
271 """!
272 Update the metric dropdowns based on the selected CSV files.
273
274 Args:
275 selected_csvs: The selected CSV files.
276 stored_data: The stored CSV data.
277 current_selected_csvs: The currently selected CSV files.
278 """
279 if not selected_csvs:
280 return [], []
281
282 temp_folder = "src/cloud_storage/temp"
283 if stored_data is None or set(current_selected_csvs) != set(selected_csvs):
284 combined_df = download_and_combine_csvs(selected_csvs, temp_folder)
285 else:
286 combined_df = pd.read_json(stored_data, orient="split")
287
288 columns = list(combined_df.columns)
289 options = [{"label": col, "value": col} for col in columns]
290
291 return options, options
292
293
294def create_update_graph_callback(graph_id, dashboard, graph_number, graph_type="line"):
295 @app.callback(
296 Output(graph_id, "figure"),
297 [
298 Input(f"csv-dropdown-{dashboard}", "value"),
299 Input(f"graph{graph_number}-{dashboard}-metrics-dropdown", "value"),
300 Input(f"x-axis-dropdown-{dashboard}-{graph_number}", "value"),
301 Input(f"stored-csv-data", "data"),
302 ],
303 State(f"csv-dropdown-{dashboard}", "value"),
304 )
305 def update_graph(
306 selected_csvs, metrics, x_axis, stored_data, current_selected_csvs
307 ):
308 """!
309 Update the graph based on the selected CSV files and metrics.
310 Args:
311 selected_csvs: The selected CSV files.
312 metrics: The selected metrics.
313 x_axis: The selected x-axis.
314 stored_data: The stored CSV data.
315 current_selected_csvs: The currently selected CSV files.
316 """
317 if not selected_csvs or not metrics:
318 return {}
319
320 temp_folder = "src/cloud_storage/temp"
321 if stored_data is None or set(current_selected_csvs) != set(selected_csvs):
322 combined_df = download_and_combine_csvs(selected_csvs, temp_folder)
323 else:
324 combined_df = pd.read_json(stored_data, orient="split")
325
326 if x_axis not in combined_df.columns:
327 x_axis = "time"
328 if "time" not in combined_df.columns:
329 combined_df["time"] = range(len(combined_df))
330
331 df_melted = combined_df.melt(id_vars=[x_axis, "Source"], value_vars=metrics)
332 df_melted["Source_Metric"] = df_melted["Source"] + " - " + df_melted["variable"]
333 df_melted = df_melted[df_melted["variable"].isin(metrics)]
334
335 if graph_type == "line":
336 fig = px.line(
337 df_melted,
338 x=x_axis,
339 y="value",
340 color="Source_Metric",
341 labels={"value": "Metrics", x_axis: x_axis},
342 title="Line Graph",
343 )
344 elif graph_type == "scatter":
345 fig = px.scatter(
346 df_melted,
347 x=x_axis,
348 y="value",
349 color="Source_Metric",
350 labels={"value": "Metrics", x_axis: x_axis},
351 title="Scatter Plot",
352 )
353 elif graph_type == "bar":
354 fig = px.bar(
355 df_melted,
356 x=x_axis,
357 y="value",
358 color="Source_Metric",
359 barmode="group",
360 labels={"value": "Metrics", x_axis: x_axis},
361 title="Bar Chart",
362 )
363 elif graph_type == "heatmap":
364 fig = px.imshow(
365 df_melted.pivot_table(index=x_axis, columns="variable", values="value"),
366 labels={"value": "Metric Value", x_axis: x_axis},
367 title="Heatmap",
368 )
369 return fig
370
371
372# Register callbacks for all dashboards and graphs
373for dashboard in available_dashboards:
379 create_update_graph_callback(f"graph1-{dashboard}", dashboard, 1, "line")
380 create_update_graph_callback(f"graph2-{dashboard}", dashboard, 2, "line")
381 create_update_graph_callback(f"graph3-{dashboard}", dashboard, 3, "scatter")
382 create_update_graph_callback(f"graph4-{dashboard}", dashboard, 4, "bar")
383 create_update_graph_callback(f"graph5-{dashboard}", dashboard, 5, "heatmap")
384
385
386# Cleanup function to remove the temp folder
388 temp_folder = "src/cloud_storage/temp"
389 if os.path.exists(temp_folder):
390 shutil.rmtree(temp_folder)
391
392
393atexit.register(cleanup_temp_folder)
394
395# Run the Dash app
396if __name__ == "__main__":
397 app.run_server(debug=True)
cleanup_temp_folder()
Definition dashboard.py:387
update_dashboard(selected_dashboard)
Update the layout based on the selected dashboard.
Definition dashboard.py:229
create_update_metric_dropdowns_callback(dashboard, graph_number)
Definition dashboard.py:258
download_and_combine_csvs(selected_csvs, temp_folder)
Download and combine the selected CSV files.
Definition dashboard.py:241
get_dashboard_layout(dashboard)
Definition dashboard.py:57
create_update_graph_callback(graph_id, dashboard, graph_number, graph_type="line")
Definition dashboard.py:294