diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index bfc9f4d..27d3f20 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -20,6 +20,7 @@ jobs: group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + MOBILITY_DATABASE: ${{ secrets.MOBILITY_DATABASE }} permissions: contents: write steps: diff --git a/R/query_mobilitydatabase.R b/R/query_mobilitydatabase.R index a6eb28c..d369b5d 100644 --- a/R/query_mobilitydatabase.R +++ b/R/query_mobilitydatabase.R @@ -1,7 +1,8 @@ #' Query Mobility Database API for GTFS feeds # #' -#' @param token String. Access token. +#' @param access_token String. (Optional when refresh_token) Access token. +#' @param refresh_token String. (Optional when access_token) Refresh token. #' @param bounding_filter_method. String. (Default `partially_enclosed`) Filtering method to use with the dataset_latitudes and dataset_longitudes parameters. #' @param limit. Integer. (Default 10) The number of items to be returned. #' @param offset. Integer. (Default 0) Offset of the first item to return. @@ -12,7 +13,9 @@ #' @param is_official. Boolean. (Optional) Default `FALSE`. If TRUE, only return official feeds. #' #' @details -#' This method queries \href{https://mobilitydatabase.org/}{Mobility Database} API, allowing to get a list of GTFS feeds documented at this platform. To use it, an access token must be provided. It can be obtained for free at Mobility Database website.\cr\cr +#' This method queries \href{https://mobilitydatabase.org/}{Mobility Database} API, allowing to get a list of GTFS feeds documented at this platform. +#' To use it, an access or a refresh token must be provided. +#' It can be obtained for free at Mobility Database website.\cr\cr #' For more details on the parameters, refer to \url{https://mobilitydata.github.io/mobility-feed-api/SwaggerUI/index.html#/feeds/getGtfsFeeds}.\cr\cr #' Some useful columns of the returned data.frame (refer to the API documentation for a full list) are: #' \itemize{ @@ -26,15 +29,15 @@ #' #' @examples #' \dontrun{ -#' feeds <- GTFShift::query_mobilitydatabase(myToken, country_code="PT", is_official=TRUE) +#' feeds <- GTFShift::query_mobilitydatabase(refresh_token="myToken", country_code="PT", is_official=TRUE) #' } #' #' @import httr #' @import dplyr -#' @importFrom gtfsrouter extract_gtfs gtfs_transfer_table #' #' @export -query_mobilitydatabase <- function(token, +query_mobilitydatabase <- function(access_token = NA, + refresh_token = NA, bounding_filter_method = "partially_enclosed", limit = 10, offset = 0, @@ -43,16 +46,34 @@ query_mobilitydatabase <- function(token, municipality = NA, bbox = NA, is_official = NA - ) { + # Validate parameters + if (is.na(access_token) && is.na(refresh_token)) { + stop("No token provided! At least one of the access or refresh tokens must be provided as an argument.") + } + + # If refresh token, get access token from API + if (is.na(access_token) && !is.na(refresh_token)) { + body <- sprintf('{"refresh_token": "%s"}', refresh_token) + response <- POST( + "https://api.mobilitydatabase.org/v1/tokens", + add_headers(`Content-Type` = "application/json"), + body = body + ) + content <- content(response, as = "parsed") + if(http_error(response)) { + stop(sprintf("Mobility database bad response: %s", http_status(response))) + } + access_token <- content$access_token + } + + # Query mobility database url <- "https://api.mobilitydatabase.org/v1/gtfs_feeds" - params <- list( - bounding_filter_method=bounding_filter_method, - limit = limit, - offset = offset - ) + params <- list(bounding_filter_method = bounding_filter_method, + limit = limit, + offset = offset) if (!is.na(country_code)) params["country_code"] = country_code if (!is.na(subdivision_name)) params["subdivision_name"] = subdivision_name if (!is.na(municipality)) params["municipality"] = municipality @@ -67,7 +88,7 @@ query_mobilitydatabase <- function(token, query = params, add_headers( `accept` = "application/json", - `Authorization` = sprintf("Bearer %s", token) + `Authorization` = sprintf("Bearer %s", access_token) ) ) diff --git a/_pkgdown.yml b/_pkgdown.yml index f9f5b41..2ea6bc9 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -3,9 +3,10 @@ template: bootstrap: 5 reference: - - title: Read + - title: Get GTFS feeds contents: - load_feed + - query_mobilitydatabase - title: Filter contents: - starts_with("filter_") @@ -17,7 +18,15 @@ reference: contents: - unify - starts_with("create_") - - title: External data + - title: Open Street Maps contents: - - starts_with("query_") - starts_with("osm_") +articles: + - title: Articles + navbar: ~ + contents: + - download + - filter + - unify + - analyse + - osm diff --git a/man/query_mobilitydatabase.Rd b/man/query_mobilitydatabase.Rd index 0cd04a9..d63f148 100644 --- a/man/query_mobilitydatabase.Rd +++ b/man/query_mobilitydatabase.Rd @@ -5,7 +5,8 @@ \title{Query Mobility Database API for GTFS feeds} \usage{ query_mobilitydatabase( - token, + access_token = NA, + refresh_token = NA, bounding_filter_method = "partially_enclosed", limit = 10, offset = 0, @@ -17,7 +18,9 @@ query_mobilitydatabase( ) } \arguments{ -\item{token}{String. Access token.} +\item{access_token}{String. (Optional when refresh_token) Access token.} + +\item{refresh_token}{String. (Optional when access_token) Refresh token.} \item{municipality}{String. (Optional) List only feeds with the specified value. Can be a partial match. Case insensitive.} @@ -42,7 +45,9 @@ data.frame with query results Query Mobility Database API for GTFS feeds } \details{ -This method queries \href{https://mobilitydatabase.org/}{Mobility Database} API, allowing to get a list of GTFS feeds documented at this platform. To use it, an access token must be provided. It can be obtained for free at Mobility Database website.\cr\cr +This method queries \href{https://mobilitydatabase.org/}{Mobility Database} API, allowing to get a list of GTFS feeds documented at this platform. +To use it, an access or a refresh token must be provided. +It can be obtained for free at Mobility Database website.\cr\cr For more details on the parameters, refer to \url{https://mobilitydata.github.io/mobility-feed-api/SwaggerUI/index.html#/feeds/getGtfsFeeds}.\cr\cr Some useful columns of the returned data.frame (refer to the API documentation for a full list) are: \itemize{ @@ -53,7 +58,7 @@ Some useful columns of the returned data.frame (refer to the API documentation f } \examples{ \dontrun{ -feeds <- GTFShift::query_mobilitydatabase(myToken, country_code="PT", is_official=TRUE) +feeds <- GTFShift::query_mobilitydatabase(refresh_token="myToken", country_code="PT", is_official=TRUE) } } diff --git a/vignettes/analyse.Rmd b/vignettes/analyse.Rmd index bd5d97a..d866ee4 100644 --- a/vignettes/analyse.Rmd +++ b/vignettes/analyse.Rmd @@ -1,8 +1,8 @@ --- -title: "Analyse GTFS feeds" +title: "4. Analyse GTFS feeds" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Analyse GTFS feeds} + %\VignetteIndexEntry{4. Analyse GTFS feeds} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- diff --git a/vignettes/download.Rmd b/vignettes/download.Rmd index 476eb0d..bca132b 100644 --- a/vignettes/download.Rmd +++ b/vignettes/download.Rmd @@ -1,8 +1,8 @@ --- -title: "Download transit data" +title: "1. Getting transit data" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Download transit data} + %\VignetteIndexEntry{1. Getting transit data} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -32,12 +32,28 @@ library(tidytransit) # Introduction -Performing analysis over transit requires data on the operation and infrastructure. -GTFShift includes some built in methods that can you assist gathering it. +Performing analysis over transit requires data on the operation and infrastructure. [GTFS](https://gtfs.org/) is an open standard that offers this information in a simple and complete way. -# Download GTFS files +GTFShift includes some built in methods that can assist gathering it, explored in this article. -## Use open catalogues +# Read a GTFS file + +GTFShift makes use of several R packages to implement its features, but most of it is built upon [tidytransit](https://r-transit.github.io/tidytransit/), so all the methods that accept a GTFS object should be a `tidygtfs` object. + +To create it, you can either use `GTFShift::load_feed` or the tidytransit method, `tidytransit::read_gtfs`. Actually, `GTFShift::load_feed` is an extension of the last, with the additional features of scanning the feed for any integrity errors and fixing them automatically, as well as the option to store it locally. + +```{r eval = FALSE} +# Using tidytransit +gtfs <- tidytransit::load_feed("https://operator.com/gtfs.zip") + +# Using GTFShift +gtfs <- GTFShift::load_feed("https://operator.com/gtfs.zip") +``` + + +# Find GTFS feeds + +## Using open catalogues The gathering of the GTFS files can be simplified by using public archives like [mobilitydatabase.org](https://mobilitydatabase.org/) or [transit.land](https://www.transit.land/). @@ -46,30 +62,19 @@ It queries the `/v1/gtfs_feeds` API endpoint, returning a list of GTFS feeds wit To use it, an access token must be provided. It can be obtained for free at Mobility Database [website](https://mobilitydatabase.org/account). - -```{r eval=FALSE, message=FALSE, warning=FALSE} +```{r} # usethis::edit_r_environ() # to set MOBILITY_DATABASE variable for this code chunk to work -feeds = GTFShift::query_mobilitydatabase(Sys.getenv("MOBILITY_DATABASE"), - country_code="PT") -``` - -```r +feeds <- GTFShift::query_mobilitydatabase(refresh_token = Sys.getenv("MOBILITY_DATABASE"), country_code="PT") feeds[1:4, c("provider", "status", "producer_url")] -#> provider status -#> 1 A Onda - Mobilidade Urbana active -#> 2 Apanha-me! - Transportes Urbanos active -#> 3 Carris Metropolitana active -#> 4 Cascais Próxima, E.M., S.A. active -#> producer_url -#> 1 https://drive.google.com/uc?export=download&id=1aPfsxHqopxxcjV8HlRzImzxh_a6zRxGp -#> 2 https://drive.google.com/uc?export=download&id=1w92h129CWNSoImBRZQOWT6KRPzSFwJ42 -#> 3 https://api.carrismetropolitana.pt/gtfs -#> 4 https://drive.google.com/uc?export=download&id=13ucYiAJRtu-gXsLa02qKJrGOgDjbnUWX + +gtfs <- GTFShift::load_feed(feeds[c(1), ]$producer_url) +summary(gtfs) ``` -## Use GTFShift incorporated database for Portugal + +## Using GTFShift incorporated database for Portugal This library offers a small database with a compilation of GTFS files for Portuguese operators. It is a CSV file, available at `extdata/gtfs_sources_pt.csv`, and has the following attributes: @@ -84,70 +89,9 @@ This library offers a small database with a compilation of GTFS files for Portug data = read.csv(system.file("extdata", "gtfs_sources_pt.csv", package = "GTFShift")) summary(data) data[1:4,] -``` -## Download and validate integrity - -`GTFShift` library offers a method to download and fix any integrity violations at GTFS files: `load_feed()`. -It fixes inconsistencies on the `stop_times.txt` and missing `shapes.txt` files and returns a tidygtfs object, that can be used in any other method of GTFShift or tidyrtransit packages. - -```{r message=TRUE, warning=TRUE} -# DOWNLOAD GTFS and store it locally -gtfs = GTFShift::load_feed(data[data$ID=="cp",]$URL) +gtfs <- GTFShift::load_feed(data[c(1), ]$URL) summary(gtfs) ``` -# Download bus lanes - -Bus lanes can improve bus transit operation. Understanding their spatial distribution is important to study operation dynamics. -`osm_bus_lanes` allows to obtain the bus lanes network on OpenStreetMaps for a given area. - -```{r} -aml = sf::st_read("https://github.com/U-Shift/MQAT/raw/refs/heads/main/geo/MUNICIPIOSgeo.gpkg", quiet = TRUE) -lisboa = aml |> dplyr::filter(Concelho == "Lisboa") |> sf::st_bbox() - -bus_lanes = GTFShift::osm_bus_lanes(lisboa) - -mapview::mapview(bus_lanes, layer.name = "Bus lanes") -``` - - - -# Get centerlines for OSM road network - -Performing an aggregated analysis for the spatial distribution of the route frequencies might be easier if the routes are projected over a simplified road network (refer to [vignette("analyse")](./analyse.html#improve-visualization-with-network_overline) for more details). - -`osm_centerlines()` allows to generate this simplification by creating the centerlines for the road network exported from Open Street Maps, using Python [neatnet](https://uscuni.org/neatnet/) package. - -