From 890375b371266f713ab1a2dc1dd18dc3f1864baa Mon Sep 17 00:00:00 2001 From: Merlin Unterfinger Date: Tue, 8 Oct 2024 14:09:25 +0200 Subject: [PATCH] refactor: move schedule to fleet --- .../app/pages/{03_Depots.py => 01_Depots.py} | 32 ++++++++++--------- rssched/app/pages/01_Schedule.py | 16 ---------- rssched/app/pages/02_Fleet.py | 16 ++++++++-- rssched/app/utils/plot.py | 4 +-- rssched/app/utils/transform.py | 21 ++++++++++++ rssched/visualization/vehicle_type_gantt.py | 7 ++-- 6 files changed, 58 insertions(+), 38 deletions(-) rename rssched/app/pages/{03_Depots.py => 01_Depots.py} (74%) delete mode 100644 rssched/app/pages/01_Schedule.py diff --git a/rssched/app/pages/03_Depots.py b/rssched/app/pages/01_Depots.py similarity index 74% rename from rssched/app/pages/03_Depots.py rename to rssched/app/pages/01_Depots.py index 651f69e..5e8fd19 100644 --- a/rssched/app/pages/03_Depots.py +++ b/rssched/app/pages/01_Depots.py @@ -2,22 +2,35 @@ from rssched.app.utils.io import get_uploaded_data from rssched.app.utils.plot import plot_depots_bar_chart -from rssched.app.utils.transform import flatten_depots +from rssched.app.utils.transform import flatten_depots, get_vehicle_summary from rssched.visualization.depot_loads import plot_depot_vehicle_loads st.title("Depots") request, response, instance_name = get_uploaded_data() -tabs = st.tabs(["Overview", "Details"]) +tabs = st.tabs(["Overview", "Details", "Data"]) df_depots = flatten_depots(request, response) with tabs[0]: - st.plotly_chart(plot_depots_bar_chart(df_depots)) + st.plotly_chart(plot_depots_bar_chart(df_depots, instance_name)) + st.markdown("### Vehicle Demand") + st.dataframe(get_vehicle_summary(response), hide_index=True) - show_aggregated = st.checkbox("Aggregate", value=True) +with tabs[1]: + selected_depot: str = st.selectbox( + "Choose depot to see detailed statistics", + df_depots[df_depots["vehicles"] > 0]["depot_id"].unique(), + ) + st.plotly_chart( + plot_depot_vehicle_loads(request, response, instance_name, selected_depot) + ) + st.dataframe(df_depots[df_depots["depot_id"] == selected_depot], hide_index=True) + +with tabs[2]: + show_aggregated = st.checkbox("Aggregate", value=False) if show_aggregated: df_grouped = ( @@ -29,14 +42,3 @@ st.dataframe(df_grouped, hide_index=True) else: st.dataframe(df_depots, hide_index=True) - - -with tabs[1]: - selected_depot: str = st.selectbox( - "Choose depot to see detailed statistics", - df_depots[df_depots["vehicles"] > 0]["depot_id"].unique(), - ) - st.plotly_chart( - plot_depot_vehicle_loads(request, response, instance_name, selected_depot) - ) - st.dataframe(df_depots[df_depots["depot_id"] == selected_depot], hide_index=True) diff --git a/rssched/app/pages/01_Schedule.py b/rssched/app/pages/01_Schedule.py deleted file mode 100644 index 75e9537..0000000 --- a/rssched/app/pages/01_Schedule.py +++ /dev/null @@ -1,16 +0,0 @@ -import streamlit as st - -from rssched.app.utils.io import get_uploaded_data -from rssched.visualization.vehicle_type_gantt import plot_gantt_per_vehicle_type - -st.title("Schedule") - -request, response, instance_name = get_uploaded_data() - -plots: dict[str, any] = plot_gantt_per_vehicle_type(response, instance_name) - -tabs = st.tabs(plots.keys()) - -for tab, (title, fig) in zip(tabs, plots.items()): - with tab: - st.plotly_chart(fig) diff --git a/rssched/app/pages/02_Fleet.py b/rssched/app/pages/02_Fleet.py index 30f2111..a2586df 100644 --- a/rssched/app/pages/02_Fleet.py +++ b/rssched/app/pages/02_Fleet.py @@ -1,8 +1,11 @@ +from typing import Any + import streamlit as st from rssched.app.utils.io import get_uploaded_data from rssched.visualization.active_events import plot_active_events_over_time from rssched.visualization.fleet_efficiency import plot_fleet_efficiency +from rssched.visualization.vehicle_type_gantt import plot_gantt_per_vehicle_type from rssched.visualization.vehicle_utilization import plot_vehicle_utilization st.title("Fleet") @@ -10,14 +13,21 @@ request, response, instance_name = get_uploaded_data() -tabs = st.tabs(["Active Events", "Vehicle Utilization", "Efficiency"]) +tabs = st.tabs( + ["Vehicle Circuits", "Active Events", "Vehicle Utilization", "Efficiency"] +) with tabs[0]: - st.plotly_chart(plot_active_events_over_time(response, instance_name)) + plots = plot_gantt_per_vehicle_type(response, instance_name) + selected_vehicle_type: str = st.selectbox("Choose vehicle type", plots.keys()) + st.plotly_chart(plots[selected_vehicle_type]) with tabs[1]: - st.plotly_chart(plot_vehicle_utilization(response, instance_name)) + st.plotly_chart(plot_active_events_over_time(response, instance_name)) with tabs[2]: + st.plotly_chart(plot_vehicle_utilization(response, instance_name)) + +with tabs[3]: for fig in plot_fleet_efficiency(response, instance_name): st.plotly_chart(fig) diff --git a/rssched/app/utils/plot.py b/rssched/app/utils/plot.py index e3210f9..43e8beb 100644 --- a/rssched/app/utils/plot.py +++ b/rssched/app/utils/plot.py @@ -3,7 +3,7 @@ from plotly.graph_objs import Figure -def plot_depots_bar_chart(df_depots: pd.DataFrame) -> Figure: +def plot_depots_bar_chart(df_depots: pd.DataFrame, instance_name: str) -> Figure: # Group by depot_id to calculate the total capacity and sort by the number of vehicles df_depots_grouped = ( df_depots[df_depots["vehicles"] > 0] @@ -38,7 +38,7 @@ def plot_depots_bar_chart(df_depots: pd.DataFrame) -> Figure: # Update layout of the bar chart fig.update_layout( barmode="group", # Bars grouped side by side - title="Depot Vehicles and Capacity", + title=f"Depot Usage (Instance: {instance_name})", xaxis_title="Depot ID", # yaxis_title="Count", legend_title="Legend", diff --git a/rssched/app/utils/transform.py b/rssched/app/utils/transform.py index 8f9f333..a9801d1 100644 --- a/rssched/app/utils/transform.py +++ b/rssched/app/utils/transform.py @@ -34,6 +34,27 @@ def get_response_summary(response: Response) -> pd.DataFrame: ) +def get_vehicle_summary(response: Response): + data = [] + + for depot_load in response.schedule.depot_loads: + depot = depot_load.depot + for load in depot_load.load: + vehicle_type = load.vehicle_type + spawn_count = load.spawn_count + data.append( + {"location": depot, "vehicle_type": vehicle_type, "count": spawn_count} + ) + + return ( + pd.DataFrame(data) + .groupby("vehicle_type")["count"] + .sum() + .sort_values() + .reset_index() + ) + + def flatten_depots(request: Request, response: Response) -> pd.DataFrame: df_request = _flatten_request_depots(request.depots) df_response = _flatten_response_depot_loads(response.schedule.depot_loads) diff --git a/rssched/visualization/vehicle_type_gantt.py b/rssched/visualization/vehicle_type_gantt.py index 68d9e20..ef5f48d 100644 --- a/rssched/visualization/vehicle_type_gantt.py +++ b/rssched/visualization/vehicle_type_gantt.py @@ -1,10 +1,13 @@ import plotly.figure_factory as ff +import plotly.graph_objects as go from rssched.model.response import Response from rssched.visualization.colors import EVENT_TYPES -def plot_gantt_per_vehicle_type(response: Response, instance_name: str) -> dict: +def plot_gantt_per_vehicle_type( + response: Response, instance_name: str +) -> dict[str, go.Figure]: figures = {} for vehicle_type in response.schedule.fleet: @@ -39,7 +42,7 @@ def plot_gantt_per_vehicle_type(response: Response, instance_name: str) -> dict: ) figures[vehicle_type.vehicle_type] = ff.create_gantt( vis_data, - title=f"Rolling stock schedule: {vehicle_type.vehicle_type} (instance: {instance_name})", + title=f"Vehicle Circuits '{vehicle_type.vehicle_type}' (instance: {instance_name})", colors=EVENT_TYPES, index_col="Type", show_colorbar=True,