UrbanAnalyst / gtfsrouter

Routing and analysis engine for GTFS (General Transit Feed Specification) data
https://urbananalyst.github.io/gtfsrouter/
80 stars 17 forks source link

transfer_type 3 is not excluded in routing #76

Closed AlexandraKapp closed 3 years ago

AlexandraKapp commented 3 years ago

I was wondering, why some travel times (for gtfs_traveltime as well as gtfs_route) are so fast in Stuttgart and then realized, that there are some transfers that do not seem possible. E.g. in the example below to transfer from Hauptbahnhof to Staatsgalerie in 0 minutes. Looking into the transfers.txt reveals, that those transfers are actually listed there with 0 min travel time. BUT its transfer_type = 3 "3 - Transfers are not possible between routes at the location." (https://developers.google.com/transit/gtfs/reference#transferstxt)

I assume those transfers are not excluded?

library(gtfsrouter)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

gtfs <- extract_gtfs(file.path("gtfs.zip"))
#> > Unzipping GTFS archive
#> v Unzipped GTFS archive
#> > Extracting GTFS feed
#> v Extracted GTFS feed 
#> > Converting stop times to secondsv Converted stop times to seconds 
#> > Converting transfer times to secondsv Converted transfer times to seconds
ttable <- gtfs_timetable(gtfs, day = "tuesday")

gtfs_route(ttable, "Rohr Bf", "Metzstr", start_time = 8*3600)
#>    route_name     trip_name                     stop_name arrival_time
#> 1          S1 Kirchheim (T)                          Rohr     08:07:00
#> 2          S1 Kirchheim (T)                     Vaihingen     08:10:00
#> 3          S1 Kirchheim (T)                    Österfeld     08:12:00
#> 4          S1 Kirchheim (T)                  Universität     08:14:00
#> 5          S1 Kirchheim (T)                 Schwabstraße     08:20:00
#> 6          S1 Kirchheim (T)                      Feuersee     08:21:00
#> 7          S1 Kirchheim (T)                    Stadtmitte     08:23:00
#> 8          S1 Kirchheim (T) Stuttgart Hauptbahnhof (tief)     08:25:00
#> 9          U2     Neugereut                 Staatsgalerie     08:25:00
#> 10         U2     Neugereut                     Neckartor     08:26:00
#> 11         U2     Neugereut                     Stöckach     08:27:00
#> 12         U2     Neugereut                   Metzstraße     08:29:00
#> 13       <NA>    (transfer)                       Rohr Bf     00:23:00
#>    departure_time
#> 1        08:08:00
#> 2        08:10:00
#> 3        08:12:00
#> 4        08:14:00
#> 5        08:20:00
#> 6        08:22:00
#> 7        08:23:00
#> 8        08:25:00
#> 9        08:25:00
#> 10       08:26:00
#> 11       08:28:00
#> 12       08:29:00
#> 13           <NA>

transfer_ids1 <- ttable$stops[grepl("Stuttgart Hauptbahnhof", ttable$stops$stop_name)] 
transfer_ids2 <- ttable$stops[grepl("Staatsgalerie", ttable$stops$stop_name)] 
head(transfer_ids1)
#>              stop_id                     stop_name stop_lat stop_lon
#> 1: de:08111:6115:1:1 Stuttgart Hauptbahnhof (oben) 48.78475 9.183214
#> 2: de:08111:6115:1:2 Stuttgart Hauptbahnhof (oben) 48.78475 9.183214
#> 3: de:08111:6115:2:3 Stuttgart Hauptbahnhof (oben) 48.78475 9.183214
#> 4: de:08111:6115:2:4 Stuttgart Hauptbahnhof (oben) 48.78475 9.183214
#> 5: de:08111:6115:3:5 Stuttgart Hauptbahnhof (oben) 48.78475 9.183214
#> 6: de:08111:6115:3:6 Stuttgart Hauptbahnhof (oben) 48.78475 9.183214
head(transfer_ids2)
#>               stop_id     stop_name stop_lat stop_lon
#> 1: de:08111:6024:10:1 Staatsgalerie 48.78303 9.187181
#> 2: de:08111:6024:11:2 Staatsgalerie 48.78302 9.187235
#> 3:  de:08111:6024:5:2 Staatsgalerie 48.78270 9.188554
#> 4:  de:08111:6024:5:3 Staatsgalerie 48.78270 9.188554
#> 5:  de:08111:6024:6:1 Staatsgalerie 48.78116 9.187487
#> 6:  de:08111:6024:8:5 Staatsgalerie 48.78116 9.187133
gtfs$transfers %>% 
  filter(from_stop_id %in% transfer_ids1$stop_id) %>% 
  filter(to_stop_id %in% transfer_ids2$stop_id)
#>             from_stop_id         to_stop_id transfer_type min_transfer_time
#>   1: de:08111:6118:1:102  de:08111:6024:8:5             3                 0
#>   2: de:08111:6118:1:102  de:08111:6024:5:3             3                 0
#>   3: de:08111:6118:1:102  de:08111:6024:5:2             3                 0
#>   4: de:08111:6118:1:102  de:08111:6024:6:1             3                 0
#>   5: de:08111:6118:1:102 de:08111:6024:10:1             3                 0
#>  ---                                                                       
#>  98:  de:08111:6115:8:16  de:08111:6024:5:3             3                 0
#>  99:  de:08111:6115:8:16  de:08111:6024:5:2             3                 0
#> 100:  de:08111:6115:8:16  de:08111:6024:6:1             3                 0
#> 101:  de:08111:6115:8:16 de:08111:6024:10:1             3                 0
#> 102:  de:08111:6115:8:16 de:08111:6024:11:2             3                 0

Created on 2021-02-09 by the reprex package (v0.3.0)

mpadge commented 3 years ago

Thanks @AlexandraKapp, you were right that those weren't being excluded. This is now the result, using what I think is the same feed, taken from here. Before this fix I saw the same result you pasted above, and with the above commit now see this:

library (gtfsrouter)
packageVersion ("gtfsrouter")
#>[1] '0.0.4.177'
gtfs <- extract_gtfs("stuttgart.zip")
#> ▶ Unzipping GTFS archive
#> Warning in utils::unzip(filename, exdir = tempdir()): error -1 in extracting
#> from zip file
#> ✔ Unzipped GTFS archive
#> ▶ Extracting GTFS feed
#> Warning in data.table::fread(flist[f], integer64 = "character",
#> showProgress = FALSE, : Discarded single-line footer: <<"51.T0.80-627-
#> j21-1.20.R","14:42:00","14:42:00","de:08115:4761:1:3","2","","0>>
#> ✔ Extracted GTFS feed 
#> ▶ Converting stop times to seconds✔ Converted stop times to seconds 
#> ▶ Converting transfer times to seconds✔ Converted transfer times to seconds
ttable <- gtfs_timetable(gtfs, day = "tuesday")
gtfs_route(ttable, "Rohr Bf", "Metzstr", start_time = 8*3600)
#>    route_name             trip_name               stop_name arrival_time
#> 1          81        Büsnauer Platz                 Rohr Bf     08:03:00
#> 2          81        Büsnauer Platz              Rohr Mitte     08:04:00
#> 3          81        Büsnauer Platz         Hegel-Gymnasium     08:06:00
#> 4          81        Büsnauer Platz          Waldburgstraße     08:07:00
#> 5          81        Büsnauer Platz           Vaihingen ZOB     08:08:00
#> 6          81        Büsnauer Platz     Fanny-Leicht-Straße     08:10:00
#> 7          U3          Vaihingen Bf              Jurastraße     08:15:00
#> 8          U3          Vaihingen Bf            Vaihingen Bf     08:17:00
#> 9          U1 Fellbach Lutherkirche            Vaihingen Bf     08:20:00
#> 10         U1 Fellbach Lutherkirche Vaihingen Schillerplatz     08:21:00
#> 11         U1 Fellbach Lutherkirche             Fauststraße     08:22:00
#> 12         U1 Fellbach Lutherkirche       Vaihingen Viadukt     08:23:00
#> 13         U1 Fellbach Lutherkirche         Engelboldstraße     08:24:00
#> 14         U1 Fellbach Lutherkirche               Kaltental     08:25:00
#> 15         U1 Fellbach Lutherkirche                 Waldeck     08:26:00
#> 16         U1 Fellbach Lutherkirche       Heslach Vogelrain     08:28:00
#> 17         U1 Fellbach Lutherkirche         Südheimer Platz     08:29:00
#> 18         U1 Fellbach Lutherkirche               Bihlplatz     08:31:00
#> 19         U1 Fellbach Lutherkirche   Erwin-Schoettle-Platz     08:33:00
#> 20         U1 Fellbach Lutherkirche             Marienplatz     08:34:00
#> 21         U1 Fellbach Lutherkirche  Österreichischer Platz     08:36:00
#> 22         U1 Fellbach Lutherkirche                 Rathaus     08:37:00
#> 23         U1 Fellbach Lutherkirche         Charlottenplatz     08:39:00
#> 24         U1 Fellbach Lutherkirche           Staatsgalerie     08:41:00
#> 25         U1 Fellbach Lutherkirche               Neckartor     08:42:00
#> 26         U1 Fellbach Lutherkirche                Stöckach     08:43:00
#> 27         U1 Fellbach Lutherkirche              Metzstraße     08:45:00
#>    departure_time
#> 1        08:04:00
#> 2        08:05:00
#> 3        08:06:00
#> 4        08:07:00
#> 5        08:09:00
#> 6        08:10:00
#> 7        08:15:00
#> 8        08:17:00
#> 9        08:20:00
#> 10       08:21:00
#> 11       08:22:00
#> 12       08:23:00
#> 13       08:24:00
#> 14       08:25:00
#> 15       08:26:00
#> 16       08:28:00
#> 17       08:29:00
#> 18       08:31:00
#> 19       08:33:00
#> 20       08:35:00
#> 21       08:36:00
#> 22       08:38:00
#> 23       08:40:00
#> 24       08:41:00
#> 25       08:42:00
#> 26       08:44:00
#> 27       08:45:00

Created on 2021-02-10 by the reprex package (v1.0.0)

The only difficulty was working out exactly where to filter out the transfer_type == 3 values. I think I've done that in the best place, which is as part of the gtfs_timetable() call. That is the final function used to transform feeds prior to calling any of the actual routing functions, so should ensure that no matter what is done to the transfer table in the meantime, the filtering will always be applied. Other code is also necessary to check the general sanity of the transfer table, mostly to ensure that transfer_type = 3 values are only ever applied to single unique pairs of stops. The final function is here.