Usage

Python

R5py exposes some of R5’s functionality via its Python API, in a syntax similar to r5r’s. At the time of this writing, only the computation of travel time matrices has been fully implemented.

Below, you find a minimal example of computing a travel time matrix:

Load transport network

Virtually all operations of r5py require a transport network. As input files to construct a transport network topology, r5py needs the following data sets:

In this example, we use data from Helsinki metropolitan area, which you can find in the source code repository of r5py in docs/data/. The street network is a cropped and filtered extract of OpenStreetMap (© OpenStreetMap contributors, ODbL license), the GTFS transport schedule is a cropped and minimised copy of Helsingin seudun liikenne’s (HSL) open data set Creative Commons BY 4.0.

To import the street and public transport networks, instantiate an r5py.TransportNetwork with the file paths to the OSM extract and the GTFS files:

[2]:
from r5py import TransportNetwork

transport_network = TransportNetwork(
    "data/kantakaupunki.osm.pbf",
    [
        "data/GTFS.zip"
    ]
)
Could not find R5 jar, trying to download it from upstream
Successfully downloaded r5-v6.6-all.jar.
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.mapdb.Volume$ByteBufferVol (file:/home/docs/.cache/r5py/r5-v6.6-all.jar) to method java.nio.DirectByteBuffer.cleaner()
WARNING: Please consider reporting this to the maintainers of org.mapdb.Volume$ByteBufferVol
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

Compute a travel time matrix

A travel time matrix is a data set detailing the travel costs (e.g., time) from each point to each point in a set of origins and destinations in a study area.

For the sake of this exercise, we will create a regular grid of points covering parts of Helsinki.

[3]:
import itertools
import geopandas
import numpy

south_west = (24.91, 60.19)
north_east = (24.97, 60.24)

coordinates =  itertools.product(
    numpy.arange(south_west[0], north_east[0], 0.005),
    numpy.arange(south_west[1], north_east[1], 0.005)
)

x, y = zip(*coordinates)

grid_points = geopandas.GeoDataFrame({
    "id": range(len(list(x))),
    "geometry": geopandas.GeoSeries.from_xy(
     x, y, crs="EPSG:4326"
    ),

})

grid_points
Warning: SIGINT handler expected:libjvm.so+0xbdcd90  found:libpython3.10.so.1.0+0x27b160
Running in non-interactive shell, SIGINT handler is replaced by shell
Signal Handlers:
SIGSEGV: [libjvm.so+0xbdca50], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO
SIGBUS: [libjvm.so+0xbdca50], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO
SIGFPE: [libjvm.so+0xbdca50], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO
SIGPIPE: [libjvm.so+0xbdca50], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO
SIGXFSZ: [libjvm.so+0xbdca50], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO
SIGILL: [libjvm.so+0xbdca50], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO
SIGUSR2: [libjvm.so+0xbdc8f0], sa_mask[0]=00000000000000000000000000000000, sa_flags=SA_RESTART|SA_SIGINFO
SIGHUP: [libjvm.so+0xbdcd90], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO
SIGINT: [libpython3.10.so.1.0+0x27b160], sa_mask[0]=00000000000000000000000000000000, sa_flags=SA_ONSTACK
SIGTERM: [libjvm.so+0xbdcd90], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO
SIGQUIT: [libjvm.so+0xbdcd90], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO
[3]:
id geometry
0 0 POINT (24.91000 60.19000)
1 1 POINT (24.91000 60.19500)
2 2 POINT (24.91000 60.20000)
3 3 POINT (24.91000 60.20500)
4 4 POINT (24.91000 60.21000)
... ... ...
127 127 POINT (24.96500 60.22000)
128 128 POINT (24.96500 60.22500)
129 129 POINT (24.96500 60.23000)
130 130 POINT (24.96500 60.23500)
131 131 POINT (24.96500 60.24000)

132 rows × 2 columns

[4]:
grid_points.explore(marker_kwds={"radius": 6, "color": "red"})
[4]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Now, to compute a travel time matrix between all grid_points, we first instantiate an r5py.TravelTimeMatrixComputer with the transport network we created earlier, and a list of origins (since we don’t specify a separate set of destinations, r5py will use the same points as destinations and produce a full set of origins and destinations). The constructor also accepts all parameters of RegionalTask, such as transport modes, or walking speed.

Calling compute_travel_times() on the instance will return a pandas.DataFrame with travel times between all points.

[5]:
import datetime

from r5py import TravelTimeMatrixComputer, TransitMode, LegMode


travel_time_matrix = TravelTimeMatrixComputer(
    transport_network,
    origins=grid_points,
    departure=datetime.datetime(2022,2,22,8,30),
    transport_modes=[TransitMode.TRANSIT, LegMode.WALK],
    #percentiles=[1,25,50,75,99],
    #breakdown=True
)
travel_times = travel_time_matrix.compute_travel_times()
travel_times
[5]:
from_id to_id travel_time
0 0 0 0
1 0 1 13
2 0 2 21
3 0 3 25
4 0 4 26
... ... ... ...
127 131 127 34
128 131 128 31
129 131 129 20
130 131 130 12
131 131 131 0

17424 rows × 3 columns

The values in the travel_time column are travel times between the points identified by from_id and to_id, in minutes.

The median travel time to or from a certain point gives a good estimate of the overall accessibility to or from it, in relation to other points:

[6]:
travel_times.groupby("from_id")["travel_time"].median()
[6]:
from_id
0      31.0
1      31.0
2      35.5
3      30.5
4      30.0
       ...
127    28.0
128    29.0
129    26.0
130    28.0
131    36.5
Name: travel_time, Length: 132, dtype: float64
[7]:
travel_times.groupby("from_id")["travel_time"].median().median()
[7]:
29.0