r5py 0.1.1.dev2__py3-none-any.whl → 1.0.0.dev0__py3-none-any.whl
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.
Potentially problematic release.
This version of r5py might be problematic. Click here for more details.
- r5py/__init__.py +6 -1
- r5py/__main__.py +1 -14
- r5py/r5/__init__.py +18 -2
- r5py/r5/{base_travel_time_matrix_computer.py → base_travel_time_matrix.py} +28 -8
- r5py/r5/{detailed_itineraries_computer.py → detailed_itineraries.py} +72 -19
- r5py/r5/direct_leg.py +1 -3
- r5py/r5/regional_task.py +12 -9
- r5py/r5/street_layer.py +1 -0
- r5py/r5/transfer_leg.py +2 -6
- r5py/r5/transit_layer.py +6 -0
- r5py/r5/transit_leg.py +1 -5
- r5py/r5/transport_mode.py +5 -3
- r5py/r5/transport_network.py +16 -7
- r5py/r5/{travel_time_matrix_computer.py → travel_time_matrix.py} +94 -19
- r5py/r5/trip.py +13 -8
- r5py/r5/trip_leg.py +76 -15
- r5py/r5/trip_planner.py +103 -47
- r5py/util/__init__.py +2 -0
- r5py/util/classpath.py +9 -5
- r5py/util/config.py +11 -2
- r5py/util/environment.py +34 -0
- r5py/util/good_enough_equidistant_crs.py +0 -1
- r5py/util/memory_footprint.py +3 -5
- r5py/util/sample_data_set.py +13 -5
- r5py/util/validating_requests_session.py +2 -2
- {r5py-0.1.1.dev2.dist-info → r5py-1.0.0.dev0.dist-info}/METADATA +29 -27
- r5py-1.0.0.dev0.dist-info/RECORD +42 -0
- {r5py-0.1.1.dev2.dist-info → r5py-1.0.0.dev0.dist-info}/WHEEL +1 -1
- r5py/sampledata/_keep/__init__.py +0 -3
- r5py-0.1.1.dev2.dist-info/RECORD +0 -42
- {r5py-0.1.1.dev2.dist-info → r5py-1.0.0.dev0.dist-info}/LICENSE +0 -0
- {r5py-0.1.1.dev2.dist-info → r5py-1.0.0.dev0.dist-info}/top_level.txt +0 -0
r5py/__init__.py
CHANGED
|
@@ -2,21 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
"""Python wrapper for the R5 routing analysis engine."""
|
|
4
4
|
|
|
5
|
-
__version__ = "
|
|
5
|
+
__version__ = "1.0.0dev0"
|
|
6
|
+
|
|
6
7
|
|
|
7
8
|
from .r5 import (
|
|
9
|
+
DetailedItineraries,
|
|
8
10
|
DetailedItinerariesComputer,
|
|
9
11
|
RegionalTask,
|
|
10
12
|
TransportMode,
|
|
11
13
|
TransportNetwork,
|
|
14
|
+
TravelTimeMatrix,
|
|
12
15
|
TravelTimeMatrixComputer,
|
|
13
16
|
)
|
|
14
17
|
|
|
15
18
|
__all__ = [
|
|
19
|
+
"DetailedItineraries",
|
|
16
20
|
"DetailedItinerariesComputer",
|
|
17
21
|
"RegionalTask",
|
|
18
22
|
"TransportMode",
|
|
19
23
|
"TransportNetwork",
|
|
24
|
+
"TravelTimeMatrix",
|
|
20
25
|
"TravelTimeMatrixComputer",
|
|
21
26
|
"__version__",
|
|
22
27
|
]
|
r5py/__main__.py
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
"""A Python wrapper for the R5 routing analysis engine."""
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
from .util import Config
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def main():
|
|
11
|
-
config = Config()
|
|
12
|
-
arguments = config.get_arguments() # noqa F401
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if __name__ == "__main__":
|
|
16
|
-
main()
|
|
3
|
+
"""Python wrapper for the R5 routing analysis engine."""
|
r5py/r5/__init__.py
CHANGED
|
@@ -2,23 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
"""R5 classes."""
|
|
4
4
|
|
|
5
|
+
from .access_leg import AccessLeg
|
|
5
6
|
from .breakdown_stat import BreakdownStat
|
|
6
|
-
from .
|
|
7
|
+
from .detailed_itineraries import DetailedItineraries, DetailedItinerariesComputer
|
|
8
|
+
from .direct_leg import DirectLeg
|
|
9
|
+
from .egress_leg import EgressLeg
|
|
7
10
|
from .regional_task import RegionalTask
|
|
8
11
|
from .scenario import Scenario
|
|
9
12
|
from .street_layer import StreetLayer
|
|
13
|
+
from .transfer_leg import TransferLeg
|
|
14
|
+
from .transit_leg import TransitLeg
|
|
10
15
|
from .transport_mode import TransportMode
|
|
11
16
|
from .transport_network import TransportNetwork
|
|
12
|
-
from .
|
|
17
|
+
from .travel_time_matrix import TravelTimeMatrix, TravelTimeMatrixComputer
|
|
18
|
+
from .trip import Trip
|
|
19
|
+
from .trip_planner import TripPlanner
|
|
13
20
|
|
|
14
21
|
__all__ = [
|
|
22
|
+
"AccessLeg",
|
|
15
23
|
"BreakdownStat",
|
|
24
|
+
"DetailedItineraries",
|
|
16
25
|
"DetailedItinerariesComputer",
|
|
26
|
+
"DirectLeg",
|
|
27
|
+
"EgressLeg",
|
|
17
28
|
"RegionalTask",
|
|
18
29
|
"Scenario",
|
|
19
30
|
"SpeedConfig",
|
|
20
31
|
"StreetLayer",
|
|
32
|
+
"TransferLeg",
|
|
33
|
+
"TransitLeg",
|
|
21
34
|
"TransportMode",
|
|
22
35
|
"TransportNetwork",
|
|
36
|
+
"TravelTimeMatrix",
|
|
23
37
|
"TravelTimeMatrixComputer",
|
|
38
|
+
"Trip",
|
|
39
|
+
"TripPlanner",
|
|
24
40
|
]
|
|
@@ -6,6 +6,7 @@ import math
|
|
|
6
6
|
import multiprocessing
|
|
7
7
|
import warnings
|
|
8
8
|
|
|
9
|
+
import geopandas
|
|
9
10
|
import numpy
|
|
10
11
|
import shapely
|
|
11
12
|
|
|
@@ -14,7 +15,7 @@ from .regional_task import RegionalTask
|
|
|
14
15
|
from .transport_network import TransportNetwork
|
|
15
16
|
|
|
16
17
|
|
|
17
|
-
__all__ = ["
|
|
18
|
+
__all__ = ["BaseTravelTimeMatrix"]
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
# R5 fills cut-off (NULL) values with MAX_INT32
|
|
@@ -26,13 +27,26 @@ MAX_INT32 = (2**31) - 1
|
|
|
26
27
|
NUM_THREADS = math.ceil(multiprocessing.cpu_count() * 0.5)
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
class
|
|
30
|
+
class BaseTravelTimeMatrix(geopandas.GeoDataFrame):
|
|
30
31
|
"""Base class for travel time computers between many origins and destinations."""
|
|
31
32
|
|
|
32
33
|
MAX_INT32 = MAX_INT32
|
|
33
34
|
|
|
34
35
|
NUM_THREADS = NUM_THREADS
|
|
35
36
|
|
|
37
|
+
_r5py_attributes = [
|
|
38
|
+
"_destinations",
|
|
39
|
+
"_destinations_crs",
|
|
40
|
+
"_origins",
|
|
41
|
+
"_origins_crs",
|
|
42
|
+
"destinations",
|
|
43
|
+
"origins",
|
|
44
|
+
"request",
|
|
45
|
+
"snap_to_network",
|
|
46
|
+
"transport_network",
|
|
47
|
+
"verbose",
|
|
48
|
+
]
|
|
49
|
+
|
|
36
50
|
def __init__(
|
|
37
51
|
self,
|
|
38
52
|
transport_network,
|
|
@@ -71,6 +85,8 @@ class BaseTravelTimeMatrixComputer:
|
|
|
71
85
|
``max_time_cycling``, ``max_time_driving``, ``speed_cycling``, ``speed_walking``,
|
|
72
86
|
``max_public_transport_rides``, ``max_bicycle_traffic_stress``
|
|
73
87
|
"""
|
|
88
|
+
geopandas.GeoDataFrame.__init__(self)
|
|
89
|
+
|
|
74
90
|
if not isinstance(transport_network, TransportNetwork):
|
|
75
91
|
transport_network = TransportNetwork(*transport_network)
|
|
76
92
|
self.transport_network = transport_network
|
|
@@ -89,8 +105,16 @@ class BaseTravelTimeMatrixComputer:
|
|
|
89
105
|
|
|
90
106
|
self.verbose = Config().arguments.verbose
|
|
91
107
|
|
|
108
|
+
def __setattr__(self, attr, val):
|
|
109
|
+
"""Catch our own attributes here so we don’t mess with (geo)pandas columns."""
|
|
110
|
+
if attr in self._r5py_attributes:
|
|
111
|
+
object.__setattr__(self, attr, val)
|
|
112
|
+
else:
|
|
113
|
+
super().__setattr__(attr, val)
|
|
114
|
+
|
|
92
115
|
@property
|
|
93
116
|
def destinations(self):
|
|
117
|
+
"""The destinations of this travel time matrix (`geopandas.GeoDataFrame`)."""
|
|
94
118
|
return self._destinations
|
|
95
119
|
|
|
96
120
|
@destinations.setter
|
|
@@ -120,10 +144,7 @@ class BaseTravelTimeMatrixComputer:
|
|
|
120
144
|
return data_set.map(lambda x: numpy.nan if x == MAX_INT32 else x)
|
|
121
145
|
|
|
122
146
|
def _prepare_origins_destinations(self):
|
|
123
|
-
"""
|
|
124
|
-
Make sure we received enough information to route from origins to
|
|
125
|
-
destinations.
|
|
126
|
-
"""
|
|
147
|
+
"""Make sure we received enough information to route from origins to destinations."""
|
|
127
148
|
try:
|
|
128
149
|
self.origins
|
|
129
150
|
except AttributeError as exception:
|
|
@@ -161,10 +182,9 @@ class BaseTravelTimeMatrixComputer:
|
|
|
161
182
|
|
|
162
183
|
setattr(self, f"_{which_end}", points.copy())
|
|
163
184
|
|
|
164
|
-
self.snap_to_network = False # prevent repeated snapping on same point sets
|
|
165
|
-
|
|
166
185
|
@property
|
|
167
186
|
def origins(self):
|
|
187
|
+
"""The origins of this travel time matrix (`geopandas.GeoDataFrame`)."""
|
|
168
188
|
return self._origins
|
|
169
189
|
|
|
170
190
|
@origins.setter
|
|
@@ -7,23 +7,33 @@
|
|
|
7
7
|
import copy
|
|
8
8
|
import warnings
|
|
9
9
|
|
|
10
|
+
try:
|
|
11
|
+
from warnings import deprecated
|
|
12
|
+
except ImportError: # Python<=3.12
|
|
13
|
+
from typing_extensions import deprecated
|
|
14
|
+
|
|
10
15
|
import geopandas
|
|
11
16
|
import joblib
|
|
12
17
|
import pandas
|
|
13
18
|
|
|
14
|
-
from .
|
|
19
|
+
from .base_travel_time_matrix import BaseTravelTimeMatrix
|
|
15
20
|
from .trip import Trip
|
|
16
21
|
from .trip_planner import ACCURATE_GEOMETRIES, TripPlanner
|
|
17
22
|
|
|
18
23
|
|
|
19
|
-
__all__ = ["DetailedItinerariesComputer"]
|
|
24
|
+
__all__ = ["DetailedItineraries", "DetailedItinerariesComputer"]
|
|
20
25
|
|
|
21
26
|
|
|
22
|
-
class
|
|
27
|
+
class DetailedItineraries(BaseTravelTimeMatrix):
|
|
23
28
|
"""Compute detailed itineraries between many origins and destinations."""
|
|
24
29
|
|
|
25
30
|
COLUMNS = ["from_id", "to_id", "option"] + Trip.COLUMNS
|
|
26
31
|
|
|
32
|
+
_r5py_attributes = BaseTravelTimeMatrix._r5py_attributes + [
|
|
33
|
+
"all_to_all",
|
|
34
|
+
"od_pairs",
|
|
35
|
+
]
|
|
36
|
+
|
|
27
37
|
def __init__(
|
|
28
38
|
self,
|
|
29
39
|
transport_network,
|
|
@@ -36,6 +46,10 @@ class DetailedItinerariesComputer(BaseTravelTimeMatrixComputer):
|
|
|
36
46
|
"""
|
|
37
47
|
Compute travel times between many origins and destinations.
|
|
38
48
|
|
|
49
|
+
``r5py.DetailedItineraries`` are child classes of
|
|
50
|
+
``geopandas.GeoDataFrame`` and support all of their methods and
|
|
51
|
+
properties, see https://geopandas.org/en/stable/docs.html
|
|
52
|
+
|
|
39
53
|
Arguments
|
|
40
54
|
---------
|
|
41
55
|
transport_network : r5py.TransportNetwork | tuple(str, list(str), dict)
|
|
@@ -58,10 +72,10 @@ class DetailedItinerariesComputer(BaseTravelTimeMatrixComputer):
|
|
|
58
72
|
if `int`, use `snap_to_network` meters as the search radius.
|
|
59
73
|
force_all_to_all : bool, default False
|
|
60
74
|
If ``origins`` and ``destinations`` have the same length, by
|
|
61
|
-
default, ``
|
|
75
|
+
default, ``DetailedItineraries`` finds routes between pairs
|
|
62
76
|
of origins and destinations, i.e., it routes from origin #1 to
|
|
63
77
|
destination #1, origin #2 to destination #2, ... .
|
|
64
|
-
Set ``
|
|
78
|
+
Set ``force_all_to_all=True`` to route from each origin to all
|
|
65
79
|
destinations (this is the default, if ``origins`` and ``destinations``
|
|
66
80
|
have different lengths, or if ``destinations`` is omitted)
|
|
67
81
|
**kwargs : mixed
|
|
@@ -106,7 +120,14 @@ class DetailedItinerariesComputer(BaseTravelTimeMatrixComputer):
|
|
|
106
120
|
else:
|
|
107
121
|
self.all_to_all = force_all_to_all
|
|
108
122
|
|
|
109
|
-
|
|
123
|
+
data = self._compute()
|
|
124
|
+
with warnings.catch_warnings():
|
|
125
|
+
warnings.simplefilter("ignore", category=FutureWarning)
|
|
126
|
+
for column in data.columns:
|
|
127
|
+
self[column] = data[column]
|
|
128
|
+
self.set_geometry("geometry")
|
|
129
|
+
|
|
130
|
+
def _compute(self):
|
|
110
131
|
"""
|
|
111
132
|
Compute travel times from all origins to all destinations.
|
|
112
133
|
|
|
@@ -114,17 +135,21 @@ class DetailedItinerariesComputer(BaseTravelTimeMatrixComputer):
|
|
|
114
135
|
-------
|
|
115
136
|
geopandas.GeoDataFrame
|
|
116
137
|
The resulting detailed routes. For each origin/destination pair,
|
|
138
|
+
multiple route alternatives (‘options’) might be reported that each
|
|
139
|
+
consist of one or more segments. Each segment represents one row.
|
|
117
140
|
multiple route alternatives (‘options’) might be reported that each consist of
|
|
118
141
|
one or more segments. Each segment represents one row.
|
|
142
|
+
|
|
119
143
|
The data frame comprises of the following columns: `from_id`,
|
|
120
144
|
`to_id`, `option` (`int`), `segment` (`int`), `transport_mode`
|
|
121
145
|
(`r5py.TransportMode`), `departure_time` (`datetime.datetime`),
|
|
122
146
|
`distance` (`float`, metres), `travel_time` (`datetime.timedelta`),
|
|
123
|
-
`wait_time` (`datetime.timedelta`), `
|
|
124
|
-
|
|
125
|
-
|
|
147
|
+
`wait_time` (`datetime.timedelta`), `feed` (`str`, the feed name
|
|
148
|
+
used), `agency_id` (`str` the public transport agency identifier),
|
|
149
|
+
`route_id` (`str`, public transport route ID), `start_stop_id`
|
|
150
|
+
(`str`, the GTFS stop_id for boarding), `end_stop_id` (`str`, the
|
|
151
|
+
GTFS stop_id for alighting), `geometry` (`shapely.LineString`)
|
|
126
152
|
"""
|
|
127
|
-
|
|
128
153
|
self._prepare_origins_destinations()
|
|
129
154
|
|
|
130
155
|
# warn if public transport routes are requested, but R5 has been
|
|
@@ -150,11 +175,12 @@ class DetailedItinerariesComputer(BaseTravelTimeMatrixComputer):
|
|
|
150
175
|
verbose=(10 * self.verbose), # joblib has a funny verbosity scale
|
|
151
176
|
n_jobs=self.NUM_THREADS,
|
|
152
177
|
) as parallel:
|
|
178
|
+
matrices = parallel(
|
|
179
|
+
joblib.delayed(self._travel_details_per_od_pair)(from_id, to_id)
|
|
180
|
+
for _, (from_id, to_id) in self.od_pairs.iterrows()
|
|
181
|
+
)
|
|
153
182
|
od_matrix = pandas.concat(
|
|
154
|
-
|
|
155
|
-
joblib.delayed(self._travel_details_per_od_pair)(from_id, to_id)
|
|
156
|
-
for _, (from_id, to_id) in self.od_pairs.iterrows()
|
|
157
|
-
),
|
|
183
|
+
[matrix.astype(matrices[0].dtypes) for matrix in matrices],
|
|
158
184
|
ignore_index=True,
|
|
159
185
|
)
|
|
160
186
|
|
|
@@ -162,11 +188,7 @@ class DetailedItinerariesComputer(BaseTravelTimeMatrixComputer):
|
|
|
162
188
|
return od_matrix
|
|
163
189
|
|
|
164
190
|
def _prepare_origins_destinations(self):
|
|
165
|
-
"""
|
|
166
|
-
Make sure we received enough information to route from origins to
|
|
167
|
-
destinations.
|
|
168
|
-
"""
|
|
169
|
-
|
|
191
|
+
"""Make sure we received enough information to route from origins to destinations."""
|
|
170
192
|
super()._prepare_origins_destinations()
|
|
171
193
|
|
|
172
194
|
if self.all_to_all:
|
|
@@ -208,3 +230,34 @@ class DetailedItinerariesComputer(BaseTravelTimeMatrixComputer):
|
|
|
208
230
|
# fmt: on
|
|
209
231
|
|
|
210
232
|
return pandas.DataFrame(trips, columns=self.COLUMNS)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@deprecated(
|
|
236
|
+
"Use `DetailedItineraries` instead, `DetailedItinerariesComputer will be deprecated in a future release."
|
|
237
|
+
)
|
|
238
|
+
class DetailedItinerariesComputer:
|
|
239
|
+
"""Compute detailed itineraries between many origins and destinations."""
|
|
240
|
+
|
|
241
|
+
def __init__(self, *args, **kwargs):
|
|
242
|
+
"""Compute detailed itineraries between many origins and destinations."""
|
|
243
|
+
self._detailed_itineraries = DetailedItineraries(*args, **kwargs)
|
|
244
|
+
|
|
245
|
+
def compute_travel_details(self):
|
|
246
|
+
"""
|
|
247
|
+
Compute travel times from all origins to all destinations.
|
|
248
|
+
|
|
249
|
+
Returns
|
|
250
|
+
-------
|
|
251
|
+
geopandas.GeoDataFrame
|
|
252
|
+
The resulting detailed routes. For each origin/destination pair,
|
|
253
|
+
multiple route alternatives (‘options’) might be reported that each consist of
|
|
254
|
+
one or more segments. Each segment represents one row.
|
|
255
|
+
The data frame comprises of the following columns: `from_id`,
|
|
256
|
+
`to_id`, `option` (`int`), `segment` (`int`), `transport_mode`
|
|
257
|
+
(`r5py.TransportMode`), `departure_time` (`datetime.datetime`),
|
|
258
|
+
`distance` (`float`, metres), `travel_time` (`datetime.timedelta`),
|
|
259
|
+
`wait_time` (`datetime.timedelta`), `route` (`str`, public transport
|
|
260
|
+
route number or name), `geometry` (`shapely.LineString`)
|
|
261
|
+
TODO: Add description of output data frame columns and format
|
|
262
|
+
"""
|
|
263
|
+
return self._detailed_itineraries
|
r5py/r5/direct_leg.py
CHANGED
r5py/r5/regional_task.py
CHANGED
|
@@ -53,11 +53,11 @@ class RegionalTask:
|
|
|
53
53
|
A RegionalTask wraps a `com.conveyal.r5.analyst.cluster.RegionalTask`,
|
|
54
54
|
which is used to specify the details of a requested computation.
|
|
55
55
|
RegionalTasks underlie virtually all major computations carried out,
|
|
56
|
-
such as, e.g., `
|
|
56
|
+
such as, e.g., `TravelTimeMatrix` or `AccessibilityEstimator`.
|
|
57
57
|
|
|
58
58
|
In **r5py**, there is usually no need to explicitely create a
|
|
59
59
|
`RegionalTask`. Rather, the constructors to the computation classes
|
|
60
|
-
(`
|
|
60
|
+
(`TravelTimeMatrix`, `AccessibilityEstimator`, ...) accept the
|
|
61
61
|
arguments, and pass them through to an internally handled
|
|
62
62
|
`RegionalTask`.
|
|
63
63
|
|
|
@@ -200,12 +200,16 @@ class RegionalTask:
|
|
|
200
200
|
# The value is a static property of com.conveyal.r5.analyst.cluster.PathResult;
|
|
201
201
|
# static properites of Java classes can be modified in a singleton kind of way
|
|
202
202
|
try:
|
|
203
|
-
|
|
204
|
-
com.conveyal.r5.analyst.cluster.PathResult.maxDestinations,
|
|
205
|
-
len(self.destinations) + 1,
|
|
206
|
-
)
|
|
203
|
+
num_destinations = len(self.destinations)
|
|
207
204
|
except AttributeError:
|
|
208
|
-
|
|
205
|
+
num_destinations = 0
|
|
206
|
+
if (
|
|
207
|
+
num_destinations
|
|
208
|
+
> com.conveyal.r5.analyst.cluster.PathResult.MAX_PATH_DESTINATIONS
|
|
209
|
+
):
|
|
210
|
+
com.conveyal.r5.analyst.cluster.PathResult.MAX_PATH_DESTINATIONS = (
|
|
211
|
+
num_destinations + 1
|
|
212
|
+
)
|
|
209
213
|
|
|
210
214
|
@property
|
|
211
215
|
def departure(self):
|
|
@@ -246,8 +250,7 @@ class RegionalTask:
|
|
|
246
250
|
|
|
247
251
|
@property
|
|
248
252
|
def departure_time_window(self):
|
|
249
|
-
"""Find public transport connections leaving within
|
|
250
|
-
``departure_time_window`` after ``departure`` (datetime.timedelta).
|
|
253
|
+
"""Find public transport connections leaving within ``departure_time_window`` after ``departure`` (datetime.timedelta).
|
|
251
254
|
|
|
252
255
|
**Note:** The value of ``departure_time_window`` should be set with some
|
|
253
256
|
caution. Specifically, setting values near or below the typical headways
|
r5py/r5/street_layer.py
CHANGED
r5py/r5/transfer_leg.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
"""Represent one leg of a trip, specifically transfers between public transport
|
|
5
|
-
vehicles."""
|
|
4
|
+
"""Represent one leg of a trip, specifically transfers between public transport vehicles."""
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
from .direct_leg import DirectLeg
|
|
@@ -12,7 +11,4 @@ __all__ = ["TransferLeg"]
|
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class TransferLeg(DirectLeg):
|
|
15
|
-
"""
|
|
16
|
-
Represent one leg of a trip, specifically transfers between public transport
|
|
17
|
-
vehicles.
|
|
18
|
-
"""
|
|
14
|
+
"""Represent one leg of a trip, specifically transfers between public transport vehicles."""
|
r5py/r5/transit_layer.py
CHANGED
|
@@ -90,12 +90,18 @@ class TransitLayer:
|
|
|
90
90
|
|
|
91
91
|
@functools.cached_property
|
|
92
92
|
def routes(self):
|
|
93
|
+
"""Return a list of GTFS routes."""
|
|
93
94
|
return list(self._transit_layer.routes)
|
|
94
95
|
|
|
95
96
|
@functools.cached_property
|
|
96
97
|
def trip_patterns(self):
|
|
98
|
+
"""Return a list of GTFS trip patterns."""
|
|
97
99
|
return list(self._transit_layer.tripPatterns)
|
|
98
100
|
|
|
101
|
+
def get_stop_id_from_index(self, stop_index):
|
|
102
|
+
"""Get the GTFS stop id for the `stop_index`-th stop of this transit layer."""
|
|
103
|
+
return self._transit_layer.stopIdForIndex[stop_index]
|
|
104
|
+
|
|
99
105
|
|
|
100
106
|
@jpype._jcustomizer.JConversion(
|
|
101
107
|
"com.conveyal.r5.transit.TransitLayer", exact=TransitLayer
|
r5py/r5/transit_leg.py
CHANGED
r5py/r5/transport_mode.py
CHANGED
|
@@ -68,6 +68,7 @@ class TransportMode(enum.Enum):
|
|
|
68
68
|
return None
|
|
69
69
|
|
|
70
70
|
def __add__(self, other):
|
|
71
|
+
"""Combine two transport modes."""
|
|
71
72
|
if isinstance(other, self.__class__):
|
|
72
73
|
return [self, other]
|
|
73
74
|
elif isinstance(other, list):
|
|
@@ -78,6 +79,7 @@ class TransportMode(enum.Enum):
|
|
|
78
79
|
)
|
|
79
80
|
|
|
80
81
|
def __radd__(self, other):
|
|
82
|
+
"""Combine two transport modes."""
|
|
81
83
|
if other == 0: # first iteration of sum()
|
|
82
84
|
return self
|
|
83
85
|
elif isinstance(other, list):
|
|
@@ -87,17 +89,17 @@ class TransportMode(enum.Enum):
|
|
|
87
89
|
|
|
88
90
|
@property
|
|
89
91
|
def is_leg_mode(self):
|
|
90
|
-
"""Can this TransportMode function as a LegMode
|
|
92
|
+
"""Can this TransportMode function as a LegMode?."""
|
|
91
93
|
return self.name in LEG_MODES
|
|
92
94
|
|
|
93
95
|
@property
|
|
94
96
|
def is_street_mode(self):
|
|
95
|
-
"""Can this TransportMode function as a StreetMode
|
|
97
|
+
"""Can this TransportMode function as a StreetMode?."""
|
|
96
98
|
return self.name in STREET_MODES
|
|
97
99
|
|
|
98
100
|
@property
|
|
99
101
|
def is_transit_mode(self):
|
|
100
|
-
"""Can this TransportMode function as a TransitMode
|
|
102
|
+
"""Can this TransportMode function as a TransitMode?."""
|
|
101
103
|
return self.name in TRANSIT_MODES
|
|
102
104
|
|
|
103
105
|
AIR = "AIR"
|
r5py/r5/transport_network.py
CHANGED
|
@@ -89,9 +89,7 @@ class TransportNetwork:
|
|
|
89
89
|
self._transport_network = transport_network
|
|
90
90
|
|
|
91
91
|
def __del__(self):
|
|
92
|
-
"""
|
|
93
|
-
Delete all temporary files upon destruction.
|
|
94
|
-
"""
|
|
92
|
+
"""Delete all temporary files upon destruction."""
|
|
95
93
|
MAX_TRIES = 10
|
|
96
94
|
|
|
97
95
|
# first, close the open osm_file,
|
|
@@ -110,13 +108,23 @@ class TransportNetwork:
|
|
|
110
108
|
del self.transit_layer
|
|
111
109
|
except AttributeError:
|
|
112
110
|
pass
|
|
113
|
-
|
|
111
|
+
try:
|
|
112
|
+
del self._transport_network
|
|
113
|
+
except AttributeError:
|
|
114
|
+
pass
|
|
114
115
|
|
|
115
|
-
time.sleep(0
|
|
116
|
-
|
|
116
|
+
time.sleep(1.0)
|
|
117
|
+
try:
|
|
118
|
+
jpype.java.lang.System.gc()
|
|
119
|
+
except jpype.JVMNotRunning:
|
|
120
|
+
pass
|
|
117
121
|
|
|
118
122
|
# then, try to delete all files in cache directory
|
|
119
|
-
|
|
123
|
+
try:
|
|
124
|
+
temporary_files = [child for child in self._cache_directory.iterdir()]
|
|
125
|
+
except FileNotFoundError: # deleted in the meantime/race condition
|
|
126
|
+
temporary_files = []
|
|
127
|
+
|
|
120
128
|
for _ in range(MAX_TRIES):
|
|
121
129
|
for temporary_file in temporary_files:
|
|
122
130
|
try:
|
|
@@ -206,6 +214,7 @@ class TransportNetwork:
|
|
|
206
214
|
|
|
207
215
|
@property
|
|
208
216
|
def extent(self):
|
|
217
|
+
"""The geographic area covered, as a `shapely.box`."""
|
|
209
218
|
# TODO: figure out how to get the extent of the GTFS schedule,
|
|
210
219
|
# then find the smaller extent of the two (or the larger one?)
|
|
211
220
|
return self.street_layer.extent
|