Querying GTFS feeds

GTFS feeds hold a lot of information about transit services, but much of it is not readily available in their tables. How often does a route run during the morning peak? How long, and how fast, are its trips? gtfstools includes many get_*() functions that extract this kind of information from a feed and return it as a data.table. This vignette will introduce you to some of them:

The other get_*() functions are listed in the function reference. To check which dates have service in several feeds at once, see get_calendar_overlap() and the Checking the calendar overlap of GTFS feeds vignette.

We will start by loading the packages required by this demonstration into the current R session:

library(gtfstools)

Frequencies and timetables

get_route_frequency() counts the trips of each route that depart within a time of day, by service (and by direction, when direction_id is present in trips). Let’s see how often two routes of São Paulo’s feed run from 7 to 9 am:

spo_path <- system.file("extdata/spo_gtfs.zip", package = "gtfstools")
gtfs <- read_gtfs(spo_path)

get_route_frequency(
  gtfs,
  route_id = c("CPTM L07", "2002-10"),
  from = "07:00:00",
  to = "09:00:00"
)
#> Key: <route_id, direction_id, service_id>
#>    route_id direction_id service_id departures mean_headway
#>      <char>        <int>     <char>      <int>        <num>
#> 1:  2002-10            0        USD         20            6
#> 2: CPTM L07            0        USD         20            6
#> 3: CPTM L07            1        USD         20            6

get_stop_frequency() does the same for stops, counting each departure from each stop (except from the last stop of each trip). Use by_route = TRUE to count the departures of each route separately:

get_stop_frequency(
  gtfs,
  stop_id = c("18848", "18960"),
  from = "07:00:00",
  to = "09:00:00"
)
#> Key: <stop_id, service_id>
#>    stop_id service_id departures mean_headway
#>     <char>     <char>      <int>        <num>
#> 1:   18848        USD        223    0.5381166
#> 2:   18960        USD         75    1.6000000

get_stop_timetable() returns the stop times at the given stops on the given dates, together with the information of their trips. Let’s see the first departures from a stop of Berlin’s feed on January 4, 2021 (get_route_timetable() does the same for routes):

ber_path <- system.file("extdata/ber_gtfs.zip", package = "gtfstools")
ber_gtfs <- read_gtfs(ber_path)

timetable <- get_stop_timetable(
  ber_gtfs,
  stop_id = "100000720101",
  date = "2021-01-04"
)
head(timetable[, .(date, trip_id, route_id, trip_headsign, departure_time)])
#>          date   trip_id route_id               trip_headsign departure_time
#>        <Date>    <char>   <char>                      <char>         <char>
#> 1: 2021-01-04 146389715 1923_700 Dallgow-Döberitz, Havelpark       05:05:00
#> 2: 2021-01-04 143766496   1921_3          Falkensee, Bahnhof       05:19:00
#> 3: 2021-01-04 146388926 1922_700          Falkensee, Bahnhof       05:23:00
#> 4: 2021-01-04 146388330 1921_700          Falkensee, Bahnhof       05:51:00
#> 5: 2021-01-04 146388884 1922_700          Falkensee, Bahnhof       05:58:00
#> 6: 2021-01-04 146389713 1923_700 Dallgow-Döberitz, Havelpark       06:05:00

Trip lengths, durations and speeds

get_trip_length() snaps each stop of a trip to the closest point of the trip’s shape, and measures the trip’s length along the shape, from its first to its last stop. Use by = "segment" to get the length between each pair of consecutive stops instead:

trip_ids <- c("CPTM L07-0", "2002-10-0")

# 'unit' argument defaults to "km"
get_trip_length(gtfs, trip_ids)
#>       trip_id   length
#>        <char>    <num>
#> 1:  2002-10-0  6.68867
#> 2: CPTM L07-0 60.58803

With method = "euclidean", lengths are measured as straight lines between stops. The same happens, with a warning, when the feed has no shapes table or its trips have no shape_id. Trips not linked to a usable shape get NA lengths, with a warning.

get_trip_duration() returns the time from the first departure to the last arrival of each trip:

# 'unit' argument defaults to "min"
get_trip_duration(gtfs, trip_ids)
#> Key: <trip_id>
#>       trip_id duration
#>        <char>    <num>
#> 1:  2002-10-0       48
#> 2: CPTM L07-0      136

And get_trip_speed() divides the length of each trip by its duration:

# 'unit' argument defaults to "km/h"
get_trip_speed(gtfs, trip_ids)
#> Key: <trip_id>
#>    route_id    trip_id     speed
#>      <char>     <char>     <num>
#> 1:  2002-10  2002-10-0  8.360838
#> 2: CPTM L07 CPTM L07-0 26.730015

get_route_speed() summarises the speeds of the trips of each route, as calculated by get_trip_speed() (the standard deviation is NA for routes with a single trip, such as 2002-10):

get_route_speed(gtfs, route_id = c("CPTM L07", "2002-10"))
#>    route_id min_speed mean_speed median_speed max_speed     sd_speed
#>      <char>     <num>      <num>        <num>     <num>        <num>
#> 1:  2002-10  8.360838   8.360838     8.360838  8.360838           NA
#> 2: CPTM L07 26.730015  26.730015    26.730015 26.730015 7.944109e-15

Summarising a feed

get_summary() runs a set of diagnostics on a feed, such as the number of routes, trips and stops, and the distributions of trip speeds, lengths and route headways. It returns them as a list of data.tables and writes an HTML report with tables and figures, which is opened in the browser by default in interactive sessions:

feed_summary <- get_summary(spo_path, html_preview = FALSE)

feed_summary$totals
#>               indicator        value   unit
#>                  <char>        <num> <char>
#>  1:          n_agencies 1.000000e+00   <NA>
#>  2:            n_routes 1.900000e+01   <NA>
#>  3:             n_trips 3.600000e+01   <NA>
#>  4:             n_stops 6.540000e+02   <NA>
#>  5:  total_shape_length 8.959281e+02     km
#>  6:   mean_shape_length 2.488689e+01     km
#>  7:   total_trip_length 8.915777e+02     km
#>  8:    mean_trip_length 2.476605e+01     km
#>  9:           vkt_total 8.606771e+08     km
#> 10:      vkt_daily_mean 1.910493e+05 km/day
#> 11: total_trip_duration 4.274667e+01      h
#> 12:  mean_trip_duration 7.124444e+01    min
#> 13:     mean_trip_speed 2.346380e+01   km/h
#> 14:  mean_route_headway 2.443757e+01    min

Note:

The results of these functions are readily available to be further analyzed, or to be combined with the rest of gtfstools’ toolkit. For more information on how to use other functions made available by the package, please see the introductory vignette and the function reference.