eflips-eval 1.2.1__tar.gz → 1.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {eflips_eval-1.2.1 → eflips_eval-1.2.2}/PKG-INFO +1 -1
- {eflips_eval-1.2.1 → eflips_eval-1.2.2}/eflips/eval/input/prepare.py +36 -23
- {eflips_eval-1.2.1 → eflips_eval-1.2.2}/eflips/eval/input/visualize.py +15 -1
- {eflips_eval-1.2.1 → eflips_eval-1.2.2}/pyproject.toml +1 -1
- {eflips_eval-1.2.1 → eflips_eval-1.2.2}/LICENSE.md +0 -0
- {eflips_eval-1.2.1 → eflips_eval-1.2.2}/README.md +0 -0
- {eflips_eval-1.2.1 → eflips_eval-1.2.2}/eflips/eval/input/__init__.py +0 -0
- {eflips_eval-1.2.1 → eflips_eval-1.2.2}/eflips/eval/output/__init__.py +0 -0
- {eflips_eval-1.2.1 → eflips_eval-1.2.2}/eflips/eval/output/prepare.py +0 -0
- {eflips_eval-1.2.1 → eflips_eval-1.2.2}/eflips/eval/output/visualize.py +0 -0
|
@@ -1,26 +1,10 @@
|
|
|
1
|
+
from collections import Counter
|
|
1
2
|
from datetime import datetime
|
|
2
3
|
from typing import Dict, List
|
|
3
4
|
|
|
4
5
|
import pandas as pd
|
|
5
6
|
import sqlalchemy
|
|
6
|
-
from eflips.model import Rotation, Trip
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def rotation_name_for_sorting(rotation_name: str) -> str:
|
|
10
|
-
"""
|
|
11
|
-
Takes a rotation name, which in the BVG is a string of two numbers separated by a '/' character, and returns a string
|
|
12
|
-
that can be used for sorting. The first part of the string is returned for BVG rotations.
|
|
13
|
-
|
|
14
|
-
Other rotation names are not supported and will return the rotation name itself.
|
|
15
|
-
|
|
16
|
-
:param rotation_name: The rotation name
|
|
17
|
-
:return: a sortable string
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
if rotation_name is not None and "/" in rotation_name:
|
|
21
|
-
return rotation_name.split("/")[0]
|
|
22
|
-
else:
|
|
23
|
-
return rotation_name
|
|
7
|
+
from eflips.model import Rotation, Trip, Route
|
|
24
8
|
|
|
25
9
|
|
|
26
10
|
def rotation_info(
|
|
@@ -40,6 +24,9 @@ def rotation_info(
|
|
|
40
24
|
- time_start: the departure of the first trip
|
|
41
25
|
- time_end: the arrival of the last trip
|
|
42
26
|
- line_name: the name of the line, which is the first part of the rotation name. Used for sorting
|
|
27
|
+
- line_is_unified: True if the rotation only contains one line
|
|
28
|
+
- start_station: the name of the departure station
|
|
29
|
+
- end_station: the name of the arrival station
|
|
43
30
|
|
|
44
31
|
:param scenario_id: The scenario id for which to create the dataframe
|
|
45
32
|
:param session: An sqlalchemy session to an eflips-model database
|
|
@@ -49,7 +36,22 @@ def rotation_info(
|
|
|
49
36
|
|
|
50
37
|
result: List[Dict[str, int | float | str | datetime]] = []
|
|
51
38
|
|
|
52
|
-
rotations =
|
|
39
|
+
rotations = (
|
|
40
|
+
session.query(Rotation)
|
|
41
|
+
.filter(Rotation.scenario_id == scenario_id)
|
|
42
|
+
.options(
|
|
43
|
+
sqlalchemy.orm.joinedload(Rotation.trips)
|
|
44
|
+
.joinedload(Trip.route)
|
|
45
|
+
.joinedload(Route.line),
|
|
46
|
+
sqlalchemy.orm.joinedload(Rotation.vehicle_type),
|
|
47
|
+
sqlalchemy.orm.joinedload(Rotation.trips)
|
|
48
|
+
.joinedload(Trip.route)
|
|
49
|
+
.joinedload(Route.departure_station),
|
|
50
|
+
sqlalchemy.orm.joinedload(Rotation.trips)
|
|
51
|
+
.joinedload(Trip.route)
|
|
52
|
+
.joinedload(Route.arrival_station),
|
|
53
|
+
)
|
|
54
|
+
)
|
|
53
55
|
|
|
54
56
|
if rotation_ids is not None:
|
|
55
57
|
if isinstance(rotation_ids, int):
|
|
@@ -62,6 +64,16 @@ def rotation_info(
|
|
|
62
64
|
for trip in rotation.trips:
|
|
63
65
|
distance += trip.route.distance / 1000
|
|
64
66
|
|
|
67
|
+
# We want to be able to sort and/or group by line. Therefore we need to identify the predominant line name for each
|
|
68
|
+
# rotation.
|
|
69
|
+
line_names: Dict[str, int] = {}
|
|
70
|
+
for trip in rotation.trips:
|
|
71
|
+
line_name = trip.route.line.name
|
|
72
|
+
if line_name not in line_names:
|
|
73
|
+
line_names[line_name] = 0
|
|
74
|
+
line_names[line_name] += 1
|
|
75
|
+
line_name = Counter(line_names).most_common(1)[0][0]
|
|
76
|
+
|
|
65
77
|
result.append(
|
|
66
78
|
{
|
|
67
79
|
"rotation_id": rotation.id,
|
|
@@ -69,16 +81,17 @@ def rotation_info(
|
|
|
69
81
|
"vehicle_type_id": rotation.vehicle_type_id,
|
|
70
82
|
"vehicle_type_name": rotation.vehicle_type.name,
|
|
71
83
|
"total_distance": distance,
|
|
84
|
+
"line_name": line_name,
|
|
85
|
+
"line_is_unified": len(line_names)
|
|
86
|
+
== 1, # True if there is only one line in the rotation
|
|
72
87
|
"time_start": rotation.trips[0].departure_time,
|
|
73
88
|
"time_end": rotation.trips[-1].arrival_time,
|
|
89
|
+
"start_station": rotation.trips[0].route.departure_station.name,
|
|
90
|
+
"end_station": rotation.trips[-1].route.arrival_station.name,
|
|
74
91
|
}
|
|
75
92
|
)
|
|
76
93
|
|
|
77
|
-
# We want to properly sort by rotation name, which is a bit intricate, as it's a string of two numbers divided by a
|
|
78
|
-
# '/' character. We can't just sort by the string, as "10/11" would come after "10/1". We need to split the string
|
|
79
|
-
# into its components and sort by them.
|
|
80
94
|
df = pd.DataFrame(result)
|
|
81
|
-
df["line_name"] = df["rotation_name"].apply(rotation_name_for_sorting)
|
|
82
95
|
|
|
83
96
|
df.sort_values(by=["line_name", "time_start"], inplace=True)
|
|
84
97
|
|
|
@@ -19,6 +19,9 @@ def rotation_info(prepared_data: pd.DataFrame) -> go.Figure:
|
|
|
19
19
|
- time_start: the departure of the first trip
|
|
20
20
|
- time_end: the arrival of the last trip
|
|
21
21
|
- line_name: the name of the line, which is the first part of the rotation name. Used for sorting
|
|
22
|
+
- line_is_unified: True if the rotation only contains one line
|
|
23
|
+
- start_station: the name of the departure station
|
|
24
|
+
- end_station: the name of the arrival station
|
|
22
25
|
|
|
23
26
|
:return: A plotly figure object
|
|
24
27
|
"""
|
|
@@ -30,11 +33,22 @@ def rotation_info(prepared_data: pd.DataFrame) -> go.Figure:
|
|
|
30
33
|
y="rotation_name",
|
|
31
34
|
color="total_distance",
|
|
32
35
|
labels={
|
|
36
|
+
"time_start": "Departure Time",
|
|
37
|
+
"time_end": "Arrival Time",
|
|
33
38
|
"rotation_name": "Rotation Name",
|
|
34
39
|
"total_distance": "Total Distance (km)",
|
|
35
40
|
"line_name": "Line Name",
|
|
41
|
+
"vehicle_type_name": "Vehicle Type Name",
|
|
42
|
+
"start_station": "Start Station",
|
|
43
|
+
"end_station": "End Station",
|
|
36
44
|
},
|
|
37
|
-
|
|
45
|
+
hover_name="rotation_name",
|
|
46
|
+
hover_data=[
|
|
47
|
+
"vehicle_type_name",
|
|
48
|
+
"total_distance",
|
|
49
|
+
"start_station",
|
|
50
|
+
"end_station",
|
|
51
|
+
],
|
|
38
52
|
pattern_shape="line_name",
|
|
39
53
|
)
|
|
40
54
|
fig.update_layout(legend_orientation="h")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|