Skip to content

Commit f670d36

Browse files
committed
Add efficiency pie chart, still need to define the service day, which is cyclical
1 parent a06f254 commit f670d36

File tree

5 files changed

+105
-2
lines changed

5 files changed

+105
-2
lines changed

rssched/cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import typer
55
from typer import Argument, echo
6-
6+
import time
77
from rssched.io.reader import import_response
88
from rssched.visualization.plot import generate_plots
99

@@ -16,6 +16,7 @@ def main(source: Annotated[Path, Argument()]):
1616
response = import_response(source)
1717
for fig in generate_plots(response, source.stem):
1818
fig.show()
19+
time.sleep(0.5)
1920

2021

2122
if __name__ == "__main__":

rssched/visualization/colors.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,13 @@
22
"ServiceTrip": "rgb(183, 183, 183)",
33
"MaintenanceSlot": "rgb(45, 50, 125)",
44
"DeadHeadTrip": "rgb(235, 0, 0)",
5+
"Idle": "rgb(252, 187, 0)",
56
}
7+
8+
COLORS = [
9+
"rgb(20, 58, 133)",
10+
"rgb(111, 34, 130)",
11+
"rgb(232, 78, 16)",
12+
"rgb(255, 222, 21)",
13+
"rgb(0, 151, 59)",
14+
]
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import pandas as pd
2+
import plotly.graph_objects as go
3+
4+
from rssched.model.response import Response
5+
from rssched.visualization.colors import EVENT_TYPES
6+
7+
8+
def summarize_vehicle_activities(response):
9+
activities = []
10+
11+
for fleet in response.schedule.fleet:
12+
vehicle_type = fleet.vehicle_type
13+
14+
for vehicle in fleet.vehicles:
15+
vehicle_id = vehicle.id
16+
times = []
17+
18+
for segment in vehicle.departure_segments:
19+
times.append(("ServiceTrip", segment.departure, segment.arrival))
20+
for slot in vehicle.maintenance_slots:
21+
times.append(("MaintenanceSlot", slot.start, slot.end))
22+
for trip in vehicle.dead_head_trips:
23+
times.append(("DeadHeadTrip", trip.departure, trip.arrival))
24+
25+
times.sort(key=lambda x: x[1])
26+
27+
last_end_time = None
28+
29+
for activity_type, start, end in times:
30+
duration = (end - start).total_seconds() / 3600
31+
activities.append(
32+
{
33+
"vehicle_id": vehicle_id,
34+
"vehicle_type": vehicle_type,
35+
"activity_type": activity_type,
36+
"duration": duration,
37+
"start_time": start,
38+
"end_time": end,
39+
}
40+
)
41+
42+
if last_end_time is not None and start > last_end_time:
43+
idle_duration = (start - last_end_time).total_seconds() / 3600
44+
activities.append(
45+
{
46+
"vehicle_id": vehicle_id,
47+
"vehicle_type": vehicle_type,
48+
"activity_type": "Idle",
49+
"duration": idle_duration,
50+
"start_time": last_end_time,
51+
"end_time": start,
52+
}
53+
)
54+
55+
last_end_time = end
56+
57+
df_activities = pd.DataFrame(activities)
58+
return df_activities
59+
60+
61+
def plot_fleet_efficiency(response: Response, instance_name: str):
62+
df = summarize_vehicle_activities(response)
63+
64+
vehicle_types = df["vehicle_type"].unique()
65+
66+
figs = []
67+
68+
for v_type in vehicle_types:
69+
filtered_df = df[df["vehicle_type"] == v_type]
70+
grouped = filtered_df.groupby("activity_type")["duration"].sum().reset_index()
71+
fig = go.Figure(
72+
data=[
73+
go.Pie(
74+
labels=grouped["activity_type"],
75+
values=grouped["duration"],
76+
textinfo="label+percent",
77+
insidetextorientation="radial",
78+
marker_colors=[
79+
EVENT_TYPES[atype] for atype in grouped["activity_type"]
80+
],
81+
)
82+
]
83+
)
84+
fig.update_layout(
85+
title=f"Activity Distribution: {v_type} (instance: {instance_name})"
86+
)
87+
figs.append(fig)
88+
89+
return figs

rssched/visualization/plot.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from rssched.model.response import Response
22
from rssched.visualization.active_events import plot_active_events_over_time
3+
from rssched.visualization.fleet_efficiency import plot_fleet_efficiency
34
from rssched.visualization.vehicle_type_gantt import plot_gantt_per_vehicle_type
45
from rssched.visualization.vehicle_utilization import plot_vehicle_utilization
56

@@ -8,4 +9,5 @@ def generate_plots(response: Response, instance_name: str):
89
figures = plot_gantt_per_vehicle_type(response, instance_name)
910
figures.append(plot_active_events_over_time(response, instance_name))
1011
figures.append(plot_vehicle_utilization(response, instance_name))
12+
figures.extend(plot_fleet_efficiency(response, instance_name))
1113
return figures

rssched/visualization/vehicle_utilization.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import plotly.express as px
33

44
from rssched.model.response import Response
5+
from rssched.visualization.colors import COLORS
56

67

78
def plot_vehicle_utilization(response: Response, instance_name: str):
@@ -28,11 +29,12 @@ def plot_vehicle_utilization(response: Response, instance_name: str):
2829
y="Duration",
2930
color="Vehicle Type",
3031
title=f"Vehicle Utilization (instance: {instance_name})",
32+
color_discrete_sequence=COLORS,
3133
labels={"Duration": "Total Hours"},
3234
)
3335
fig.update_layout(
3436
xaxis_title="Vehicle ID",
35-
yaxis_title="Total Utilization [h]",
37+
yaxis_title="Service Trip Time [h]",
3638
xaxis={"categoryorder": "total descending"},
3739
)
3840
fig.update_layout(hovermode="x", hoverdistance=50)

0 commit comments

Comments
 (0)