From 5f9d124d926556aba622116c0bbc4dff2feb1107 Mon Sep 17 00:00:00 2001 From: Diego H Date: Mon, 8 Jan 2024 14:50:42 +0100 Subject: [PATCH] Add progress bars and deprecate amenities (#38) * Add progress bars * Update tests * Deprecate geo amenities * Update wordlist * Update docs with pkgdev --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .github/workflows/wipe-cache.yaml | 2 + CITATION.cff | 49 ++-- DESCRIPTION | 8 +- NAMESPACE | 2 + NEWS.md | 12 + R/bbox_to_poly.R | 3 +- R/data.R | 43 --- R/geo_address_lookup.R | 2 +- R/geo_address_lookup_sf.R | 2 +- R/geo_amenity.R | 164 +----------- R/geo_amenity_sf.R | 176 +----------- R/geo_lite.R | 24 +- R/geo_lite_sf.R | 24 +- R/nominatim_check_access.R | 222 +++++++-------- R/nominatimlite-package.R | 2 +- R/reverse_geo_lite.R | 21 +- R/reverse_geo_lite_sf.R | 21 +- README.md | 10 +- codemeta.json | 22 +- data/osm_amenities.rda | Bin 1127 -> 0 bytes inst/WORDLIST | 16 +- inst/schemaorg.json | 4 +- man/bbox_to_poly.Rd | 9 +- man/figures/README-pizzahut-1.png | Bin 22412 -> 22562 bytes man/figures/README-statue_liberty-1.png | Bin 21436 -> 21441 bytes man/figures/lifecycle-archived.svg | 21 ++ man/figures/lifecycle-defunct.svg | 21 ++ man/figures/lifecycle-deprecated.svg | 21 ++ man/figures/lifecycle-experimental.svg | 21 ++ man/figures/lifecycle-maturing.svg | 21 ++ man/figures/lifecycle-questioning.svg | 21 ++ man/figures/lifecycle-soft-deprecated.svg | 21 ++ man/figures/lifecycle-stable.svg | 29 ++ man/figures/lifecycle-superseded.svg | 21 ++ man/geo_address_lookup.Rd | 4 +- man/geo_address_lookup_sf.Rd | 5 +- man/geo_amenity.Rd | 52 +--- man/geo_amenity_sf.Rd | 68 +---- man/geo_lite.Rd | 8 +- man/geo_lite_sf.Rd | 9 +- man/nominatim_check_access.Rd | 2 +- man/nominatimlite-package.Rd | 2 +- man/osm_amenities.Rd | 144 ---------- man/reverse_geo_lite.Rd | 6 +- man/reverse_geo_lite_sf.Rd | 7 +- man/roxygen/meta.R | 1 - pkgdown/_pkgdown.yml | 8 - tests/testthat/_snaps/geo_amenity.md | 9 + tests/testthat/_snaps/geo_amenity_sf.md | 9 + tests/testthat/test-geo_amenity.R | 191 +------------ tests/testthat/test-geo_amenity_sf.R | 210 +-------------- tests/testthat/test-geo_lite.R | 17 ++ tests/testthat/test-geo_lite_sf.R | 17 ++ tests/testthat/test-reverse_geo_lite.R | 21 +- tests/testthat/test-reverse_geo_lite_sf.R | 21 +- vignettes/nominatimlite.Rmd | 312 +++++++++++----------- 56 files changed, 796 insertions(+), 1362 deletions(-) delete mode 100644 R/data.R delete mode 100644 data/osm_amenities.rda create mode 100644 man/figures/lifecycle-archived.svg create mode 100644 man/figures/lifecycle-defunct.svg create mode 100644 man/figures/lifecycle-deprecated.svg create mode 100644 man/figures/lifecycle-experimental.svg create mode 100644 man/figures/lifecycle-maturing.svg create mode 100644 man/figures/lifecycle-questioning.svg create mode 100644 man/figures/lifecycle-soft-deprecated.svg create mode 100644 man/figures/lifecycle-stable.svg create mode 100644 man/figures/lifecycle-superseded.svg delete mode 100644 man/osm_amenities.Rd create mode 100644 tests/testthat/_snaps/geo_amenity.md create mode 100644 tests/testthat/_snaps/geo_amenity_sf.md diff --git a/.github/workflows/wipe-cache.yaml b/.github/workflows/wipe-cache.yaml index 45fbff09..1a64277a 100644 --- a/.github/workflows/wipe-cache.yaml +++ b/.github/workflows/wipe-cache.yaml @@ -1,6 +1,8 @@ name: Clear all Github actions caches manually on: workflow_dispatch: + schedule: + - cron: '0 16 15 * *' jobs: cache-clear: diff --git a/CITATION.cff b/CITATION.cff index 72223d98..d728000f 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -8,11 +8,11 @@ message: 'To cite package "nominatimlite" in publications use:' type: software license: MIT title: 'nominatimlite: Interface with ''Nominatim'' API Service' -version: 0.2.1 +version: 0.2.1.9000 doi: 10.5281/zenodo.5113195 abstract: Lite interface for getting data from 'OSM' service 'Nominatim' . - Extract coordinates from addresses, find places near a set of coordinates, search - for amenities and return spatial objects on 'sf' format. + Extract coordinates from addresses, find places near a set of coordinates and return + spatial objects on 'sf' format. authors: - family-names: Hernangómez given-names: Diego @@ -26,13 +26,13 @@ preferred-citation: given-names: Diego email: diego.hernangomezherrero@gmail.com orcid: https://orcid.org/0000-0001-8457-4658 - year: '2023' - version: 0.2.1 + year: '2024' + version: 0.2.1.9000 doi: 10.5281/zenodo.5113195 url: https://dieghernan.github.io/nominatimlite/ abstract: Lite interface for getting data from OSM service Nominatim . - Extract coordinates from addresses, find places near a set of coordinates, search - for amenities and return spatial objects on sf format. + Extract coordinates from addresses, find places near a set of coordinates and + return spatial objects on sf format. repository: https://CRAN.R-project.org/package=nominatimlite repository-code: https://github.com/dieghernan/nominatimlite url: https://dieghernan.github.io/nominatimlite/ @@ -65,7 +65,7 @@ references: - name: R Core Team location: name: Vienna, Austria - year: '2023' + year: '2024' institution: name: R Foundation for Statistical Computing version: '>= 3.6.0' @@ -92,7 +92,7 @@ references: given-names: Davis email: davis@posit.co orcid: https://orcid.org/0000-0003-4777-038X - year: '2023' + year: '2024' version: '>= 1.0.0' - type: software title: jsonlite @@ -105,11 +105,26 @@ references: given-names: Jeroen email: jeroen@berkeley.edu orcid: https://orcid.org/0000-0002-4035-0289 - year: '2023' + year: '2024' identifiers: - type: url value: https://arxiv.org/abs/1403.2805 version: '>= 1.7.0' +- type: software + title: lifecycle + abstract: 'lifecycle: Manage the Life Cycle of your Package Functions' + notes: Imports + url: https://lifecycle.r-lib.org/ + repository: https://CRAN.R-project.org/package=lifecycle + authors: + - family-names: Henry + given-names: Lionel + email: lionel@posit.co + - family-names: Wickham + given-names: Hadley + email: hadley@posit.co + orcid: https://orcid.org/0000-0003-4757-117X + year: '2024' - type: software title: sf abstract: 'sf: Simple Features for R' @@ -121,7 +136,7 @@ references: given-names: Edzer email: edzer.pebesma@uni-muenster.de orcid: https://orcid.org/0000-0001-8049-7069 - year: '2023' + year: '2024' version: '>= 0.9.0' - type: software title: utils @@ -131,7 +146,7 @@ references: - name: R Core Team location: name: Vienna, Austria - year: '2023' + year: '2024' institution: name: R Foundation for Statistical Computing - type: software @@ -168,7 +183,7 @@ references: - family-names: Dunnington given-names: Dewey orcid: https://orcid.org/0000-0002-9415-4582 - year: '2023' + year: '2024' version: '>= 3.0.0' - type: software title: knitr @@ -181,7 +196,7 @@ references: given-names: Yihui email: xie@yihui.name orcid: https://orcid.org/0000-0003-0645-5666 - year: '2023' + year: '2024' - type: software title: rmarkdown abstract: 'rmarkdown: Dynamic Documents for R' @@ -224,7 +239,7 @@ references: given-names: Richard email: rich@posit.co orcid: https://orcid.org/0000-0003-3925-190X - year: '2023' + year: '2024' - type: software title: testthat abstract: 'testthat: Unit Testing for R' @@ -235,7 +250,7 @@ references: - family-names: Wickham given-names: Hadley email: hadley@posit.co - year: '2023' + year: '2024' version: '>= 3.0.0' - type: software title: tidygeocoder @@ -260,4 +275,4 @@ references: given-names: Daniel email: possenriede+r@gmail.com orcid: https://orcid.org/0000-0002-6738-9845 - year: '2023' + year: '2024' diff --git a/DESCRIPTION b/DESCRIPTION index 16379758..20e20aa6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: nominatimlite Title: Interface with 'Nominatim' API Service -Version: 0.2.1 +Version: 0.2.1.9000 Authors@R: c( person("Diego", "Hernangómez", , "diego.hernangomezherrero@gmail.com", role = c("aut", "cre", "cph"), comment = c(ORCID = "0000-0001-8457-4658")), @@ -10,8 +10,8 @@ Authors@R: c( ) Description: Lite interface for getting data from 'OSM' service 'Nominatim' . Extract - coordinates from addresses, find places near a set of coordinates, - search for amenities and return spatial objects on 'sf' format. + coordinates from addresses, find places near a set of coordinates and + return spatial objects on 'sf' format. License: MIT + file LICENSE URL: https://dieghernan.github.io/nominatimlite/, https://github.com/dieghernan/nominatimlite @@ -21,6 +21,7 @@ Depends: Imports: dplyr (>= 1.0.0), jsonlite (>= 1.7.0), + lifecycle, sf (>= 0.9.0), utils Suggests: @@ -37,7 +38,6 @@ Config/testthat/parallel: true Copyright: Data © OpenStreetMap contributors, ODbL 1.0. Encoding: UTF-8 -LazyData: true Roxygen: list(markdown = TRUE) RoxygenNote: 7.2.3 X-schema.org-applicationCategory: cartography diff --git a/NAMESPACE b/NAMESPACE index ce795640..6c64dc25 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -11,3 +11,5 @@ export(nominatim_check_access) export(reverse_geo_lite) export(reverse_geo_lite_sf) importFrom(utils,download.file) +importFrom(utils,setTxtProgressBar) +importFrom(utils,txtProgressBar) diff --git a/NEWS.md b/NEWS.md index ada39426..906fa4be 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,15 @@ +# nominatimlite (development version) + +- Add a `progressbar` parameter to `geo_lite()`, `geo_lite_sf()`, + `reverse_geo_lite()` and `reverse_geo_lite_sf()` to display progress in the + console. + +## Deprecated + +- `geo_amenity()` and `geo_amenity_sf()`, see + [Nominatim/issues/1311](https://github.com/osm-search/Nominatim/issues/1311). +- `nominatimlite::osm_amenities` data set deleted. + # nominatimlite 0.2.1 - Remove **osmdata** from Suggests. diff --git a/R/bbox_to_poly.R b/R/bbox_to_poly.R index cf7f1e11..96e50031 100644 --- a/R/bbox_to_poly.R +++ b/R/bbox_to_poly.R @@ -1,4 +1,4 @@ -#' Create a bounding box `sf` object +#' Create a bounding box \CRANpkg{sf} object #' #' @description #' @@ -16,7 +16,6 @@ #' @seealso [sf::st_as_sfc()] #' #' @family spatial -#' @family amenity #' #' @details #' diff --git a/R/data.R b/R/data.R deleted file mode 100644 index 523dd9ad..00000000 --- a/R/data.R +++ /dev/null @@ -1,43 +0,0 @@ -#' OpenStreetMap amenity database -#' -#' @description -#' Database with the list of amenities available on OpenStreetMap. -#' -#' @family datasets -#' @family amenity -#' -#' @encoding UTF-8 -#' -#' @name osm_amenities -#' -#' @docType data -#' -#' @format A `tibble` with with -#' `r prettyNum(nrow(nominatimlite::osm_amenities), big.mark=",")` rows and -#' fields: -#' \describe{ -#' \item{category}{The category of the amenity} -#' \item{amenity}{The name of the amenity} -#' } -#' -#' @details -#' -#' ```{r, echo=FALSE} -#' -#' t <- nominatimlite::osm_amenities -#' -#' knitr::kable(t, col.names = c("**category**", "**amenity**")) -#' -#' -#' ``` -#' -#' @source -#' -#' @note Data extracted on **14 June 2021**. -#' -#' @examples -#' -#' amenities <- nominatimlite::osm_amenities -#' -#' amenities -NULL diff --git a/R/geo_address_lookup.R b/R/geo_address_lookup.R index 82af913f..43dadec9 100644 --- a/R/geo_address_lookup.R +++ b/R/geo_address_lookup.R @@ -21,7 +21,7 @@ #' @family lookup #' @family geocoding #' -#' @return A `tibble` with the results found by the query. +#' @return A \CRANpkg{tibble} with the results found by the query. #' #' @examplesIf nominatim_check_access() #' \donttest{ diff --git a/R/geo_address_lookup_sf.R b/R/geo_address_lookup_sf.R index 642bea71..6af9829c 100644 --- a/R/geo_address_lookup_sf.R +++ b/R/geo_address_lookup_sf.R @@ -6,7 +6,7 @@ #' \CRANpkg{sf} spatial object associated with the query, see #' [geo_address_lookup()] for retrieving the data in \CRANpkg{tibble} format. #' -#' @return A `sf` object with the results. +#' @return A \CRANpkg{sf} object with the results. #' #' @inheritParams geo_lite_sf #' @inheritParams geo_address_lookup diff --git a/R/geo_amenity.R b/R/geo_amenity.R index e5643b8d..48a157bc 100644 --- a/R/geo_amenity.R +++ b/R/geo_amenity.R @@ -1,33 +1,27 @@ #' Geocode amenities #' #' @description -#' This function search amenities as defined by OpenStreetMap on a restricted -#' area defined by a bounding box in the form of -#' `(, , , )`. This -#' function returns the \CRANpkg{tibble} associated with the query, see -#' [geo_amenity_sf()] for retrieving the data as a spatial object -#' (\CRANpkg{sf} format). +#' `r lifecycle::badge("deprecated")` +#' +#' This operation is not supported any more. Use +#' [**osmdata**](https://github.com/ropensci/osmdata) instead. #' #' #' @param bbox A numeric vector of latitude and longitude #' `(, , , )` that #' restrict the search area. See **Details**. #' @param amenity A character of a vector of character with the amenities to be -#' geolocated (i.e. `c("pub", "restaurant")`). See **Details** and -#' [nominatimlite::osm_amenities]. +#' geolocated (i.e. `c("pub", "restaurant")`). #' @param custom_query API-specific parameters to be used. -#' See [nominatimlite::geo_lite()]. #' @param strict Logical `TRUE/FALSE`. Force the results to be included inside #' the `bbox`. Note that Nominatim default behavior may return results located #' outside the provided bounding box. #' #' @inheritParams geo_lite #' -#' @return A `tibble` with the results. +#' @return A \CRANpkg{tibble} with the results. #' #' @seealso [geo_amenity_sf()] -#' @family amenity -#' @family geocoding #' @details #' #' Bounding boxes can be located using different online tools, as @@ -37,22 +31,7 @@ #' . #' #' -#' @examplesIf nominatim_check_access() -#' \donttest{ -#' # Times Square, NY, USA -#' bbox <- c(-73.9894467311, 40.75573629, -73.9830630737, 40.75789245) -#' -#' geo_amenity(bbox = bbox, amenity = "restaurant") -#' -#' # Several amenities -#' geo_amenity(bbox = bbox, amenity = c("restaurant", "pub")) -#' -#' # Increase limit and use with strict -#' geo_amenity( -#' bbox = bbox, amenity = c("restaurant", "pub"), limit = 10, -#' strict = TRUE -#' ) -#' } +#' @keywords internal #' #' @export geo_amenity <- function(bbox, @@ -65,129 +44,12 @@ geo_amenity <- function(bbox, verbose = FALSE, custom_query = list(), strict = FALSE) { - if (limit > 50) { - message(paste( - "Nominatim provides 50 results as a maximum. ", - "Your query may be incomplete" - )) - limit <- min(50, limit) - } - - - # Dedupe for query - amenity <- as.character(amenity) - init_key <- dplyr::tibble(query = amenity) - key <- unique(amenity) - - all_res <- lapply(key, function(x) { - geo_amenity_single( - bbox = bbox, - amenity = x, - lat, - long, - limit, - full_results, - return_addresses, - verbose, - custom_query + if (requireNamespace("lifecycle", quietly = TRUE)) { + lifecycle::deprecate_stop("0.3.0", "geo_amenity()", + details = paste( + "Operation not supported any", + "more by the Nominatim API." + ) ) - }) - - all_res <- dplyr::bind_rows(all_res) - all_res <- dplyr::left_join(init_key, all_res, by = "query") - - if (strict) { - strict <- all_res[lat] >= bbox[2] & - all_res[lat] <= bbox[4] & - all_res[long] >= bbox[1] & - all_res[long] <= bbox[3] - - strict <- as.logical(strict) - - all_res <- all_res[strict, ] - } - - - - return(all_res) -} - - - -#' @noRd -#' @inheritParams geo_amenity -geo_amenity_single <- function(bbox, - amenity, - lat = "lat", - long = "lon", - limit = 1, - full_results = TRUE, - return_addresses = TRUE, - verbose = FALSE, - custom_query = list()) { - # Step 1: Download ---- - bbox_txt <- paste0(bbox, collapse = ",") - - api <- "https://nominatim.openstreetmap.org/search?" - - url <- paste0( - api, "viewbox=", bbox_txt, "&q=[", amenity, - "]&format=json&limit=", limit - ) - - if (full_results) url <- paste0(url, "&addressdetails=1") - if (!"bounded" %in% names(custom_query)) url <- paste0(url, "&bounded=1") - - # Add options - url <- add_custom_query(custom_query, url) - - # Download to temp file - json <- tempfile(fileext = ".json") - res <- api_call(url, json, isFALSE(verbose)) - - # Step 2: Read and parse results ---- - - # Keep a tbl with the query - tbl_query <- dplyr::tibble(query = amenity) - - # If no response... - if (isFALSE(res)) { - message(url, " not reachable.") - out <- empty_tbl(tbl_query, lat, long) - return(invisible(out)) - } - - result <- dplyr::as_tibble(jsonlite::fromJSON(json, flatten = TRUE)) - - # Rename lat and lon - nmes <- names(result) - nmes[nmes == "lat"] <- lat - nmes[nmes == "lon"] <- long - - names(result) <- nmes - - # Empty query - if (nrow(result) == 0) { - message("No results for query ", amenity) - out <- empty_tbl(tbl_query, lat, long) - return(invisible(out)) } - - # Coords as double - result[lat] <- as.double(result[[lat]]) - result[long] <- as.double(result[[long]]) - - # Add query - result_clean <- result - result_clean$query <- amenity - - # Keep names - result_out <- keep_names(result_clean, return_addresses, full_results, - colstokeep = c("query", lat, long) - ) - - # As tibble - result_out <- dplyr::as_tibble(result_out) - - result_out } diff --git a/R/geo_amenity_sf.R b/R/geo_amenity_sf.R index fc26df09..80d2b0f1 100644 --- a/R/geo_amenity_sf.R +++ b/R/geo_amenity_sf.R @@ -1,16 +1,16 @@ #' Geocode amenities in Spatial format #' #' @description -#' This function search amenities as defined by OpenStreetMap on a restricted -#' area defined by a bounding box in the form of -#' `(, , , )`. This -#' function returns the \CRANpkg{sf} spatial object associated with the query, -#' see [geo_amenity()] for retrieving the data in \CRANpkg{tibble} format. +#' `r lifecycle::badge("deprecated")` +#' +#' This operation is not supported any more. Use +#' [**osmdata**](https://github.com/ropensci/osmdata) instead. +#' #' #' @inheritParams geo_lite_sf #' @inheritParams geo_amenity #' -#' @return A `sf` object with the results. +#' @return A \CRANpkg{sf} object with the results. #' #' @details #' @@ -22,37 +22,8 @@ #' #' @inheritSection geo_lite_sf About Geometry Types #' -#' @seealso [geo_amenity()] -#' @family amenity -#' @family geocoding -#' @family spatial -#' -#' @examplesIf nominatim_check_access() -#' \donttest{ -#' # Madrid, Spain -#' -#' library(ggplot2) -#' -#' bbox <- c(-3.888954, 40.311977, -3.517916, 40.643729) -#' -#' # Restaurants and pubs -#' -#' rest_pub <- geo_amenity_sf(bbox, c("restaurant", "pub"), limit = 50) -#' -#' if (any(!sf::st_is_empty(rest_pub))) { -#' ggplot(rest_pub) + -#' geom_sf() -#' } +#' @keywords internal #' -#' # Hospital as polygon -#' -#' hosp <- geo_amenity_sf(bbox, "hospital", points_only = FALSE) -#' -#' if (any(!sf::st_is_empty(hosp))) { -#' ggplot(hosp) + -#' geom_sf() -#' } -#' } #' @export geo_amenity_sf <- function(bbox, amenity, @@ -63,133 +34,12 @@ geo_amenity_sf <- function(bbox, custom_query = list(), points_only = TRUE, strict = FALSE) { - if (limit > 50) { - message(paste( - "Nominatim provides 50 results as a maximum. ", - "Your query may be incomplete" - )) - limit <- min(50, limit) - } - - - # Dedupe for query - amenity <- as.character(amenity) - init_key <- dplyr::tibble(query = amenity) - key <- unique(amenity) - - all_res <- lapply(key, function(x) { - geo_amenity_sf_single( - bbox = bbox, - amenity = x, - limit, - full_results, - return_addresses, - verbose, - custom_query, - points_only + if (requireNamespace("lifecycle", quietly = TRUE)) { + lifecycle::deprecate_stop("0.3.0", "geo_amenity_sf()", + details = paste( + "Operation not supported any", + "more by the Nominatim API." + ) ) - }) - - all_res <- dplyr::bind_rows(all_res) - - all_res <- sf_to_tbl(all_res) - - # Handle dupes in sf - if (!identical(as.character(init_key$query), key)) { - # Join with indexes - template <- sf::st_drop_geometry(all_res)[, "query"] - template$rindex <- seq_len(nrow(template)) - getrows <- dplyr::left_join(init_key, template, by = "query") - - # Select rows - all_res <- all_res[as.integer(getrows$rindex), ] - all_res <- sf_to_tbl(all_res) - } - - if (strict) { - bbox_sf <- bbox_to_poly(bbox) - strict <- sf::st_covered_by(all_res, bbox_sf, sparse = FALSE) - all_res <- all_res[strict, ] - all_res <- sf_to_tbl(all_res) - } - - return(all_res) -} - - - -#' @noRd -#' @inheritParams geo_amenity_sf -geo_amenity_sf_single <- function(bbox, - amenity, - limit = 1, - full_results = TRUE, - return_addresses = TRUE, - verbose = FALSE, - custom_query = list(), - points_only = TRUE) { - # Step 1: Download ---- - bbox_txt <- paste0(bbox, collapse = ",") - api <- "https://nominatim.openstreetmap.org/search?" - - url <- paste0( - api, "viewbox=", bbox_txt, "&q=[", amenity, - "]&format=geojson&limit=", limit - ) - - - if (full_results) url <- paste0(url, "&addressdetails=1") - if (!isTRUE(points_only)) url <- paste0(url, "&polygon_geojson=1") - if (!"bounded" %in% names(custom_query)) url <- paste0(url, "&bounded=1") - - # Add options - url <- add_custom_query(custom_query, url) - - # Download to temp file - json <- tempfile(fileext = ".geojson") - res <- api_call(url, json, quiet = isFALSE(verbose)) - - # Step 2: Read and parse results ---- - - # Keep a tbl with the query - tbl_query <- dplyr::tibble(query = amenity) - - # If no response... - if (isFALSE(res)) { - message(url, " not reachable.") - out <- empty_sf(tbl_query) - return(invisible(out)) - } - - # Read - sfobj <- sf::read_sf(json, stringsAsFactors = FALSE) - - # Empty query - if (length(names(sfobj)) == 1) { - message("No results for query ", amenity) - out <- empty_sf(tbl_query) - return(invisible(out)) } - - - # Prepare output - - # Unnest address - sfobj <- unnest_sf(sfobj) - - - - # Prepare output - sf_clean <- sfobj - sf_clean$query <- amenity - - # Keep names - result_out <- keep_names(sf_clean, return_addresses, full_results, - colstokeep = "query" - ) - - # Attach as tibble - result_out <- sf_to_tbl(result_out) - - result_out } diff --git a/R/geo_lite.R b/R/geo_lite.R index 557520ff..9f1c2329 100644 --- a/R/geo_lite.R +++ b/R/geo_lite.R @@ -18,6 +18,8 @@ #' returned. See also `return_addresses`. #' @param return_addresses return input addresses with results if `TRUE`. #' @param verbose if `TRUE` then detailed logs are output to the console. +#' @param progressbar Logical. If `TRUE` displays a progress bar to indicate +#' the progress of the function. #' @param custom_query A named list with API-specific parameters to be used #' (i.e. `list(countrycodes = "US")`). See **Details**. #' @@ -26,7 +28,7 @@ #' See for additional #' parameters to be passed to `custom_query`. #' -#' @return A `tibble` with the results. +#' @return A \CRANpkg{tibble} with the results. #' #' @examplesIf nominatim_check_access() #' \donttest{ @@ -52,6 +54,7 @@ geo_lite <- function(address, full_results = FALSE, return_addresses = TRUE, verbose = FALSE, + progressbar = TRUE, custom_query = list()) { if (limit > 50) { message(paste( @@ -66,9 +69,23 @@ geo_lite <- function(address, init_key <- dplyr::tibble(query = address) key <- unique(address) - all_res <- lapply(key, function(x) { + # Set progress bar + ntot <- length(key) + # Set progress bar if n > 1 + progressbar <- all(progressbar, ntot > 1) + if (progressbar) { + pb <- txtProgressBar(min = 0, max = ntot, width = 50, style = 3) + } + seql <- seq(1, ntot, 1) + + all_res <- lapply(seql, function(x) { + ad <- key[x] + if (progressbar) { + setTxtProgressBar(pb, x) + cat(paste0(" (", x, "/", ntot, ") ")) + } geo_lite_single( - address = x, + address = ad, lat, long, limit, @@ -78,6 +95,7 @@ geo_lite <- function(address, custom_query ) }) + if (progressbar) close(pb) all_res <- dplyr::bind_rows(all_res) all_res <- dplyr::left_join(init_key, all_res, by = "query") diff --git a/R/geo_lite_sf.R b/R/geo_lite_sf.R index 1cc6ae44..f51911a8 100644 --- a/R/geo_lite_sf.R +++ b/R/geo_lite_sf.R @@ -38,7 +38,7 @@ #' The function is vectorized, allowing for multiple addresses to be geocoded; #' in case of `points_only = FALSE` multiple geometry types may be returned. #' -#' @return A `sf` object with the results. +#' @return A \CRANpkg{sf} object with the results. #' #' @examplesIf nominatim_check_access() #' \donttest{ @@ -82,6 +82,7 @@ geo_lite_sf <- function(address, return_addresses = TRUE, full_results = FALSE, verbose = FALSE, + progressbar = TRUE, custom_query = list(), points_only = TRUE) { if (limit > 50) { @@ -97,10 +98,25 @@ geo_lite_sf <- function(address, init_key <- dplyr::tibble(query = address) key <- unique(address) + # Set progress bar + ntot <- length(key) + # Set progress bar if n > 1 + progressbar <- all(progressbar, ntot > 1) + if (progressbar) { + pb <- txtProgressBar(min = 0, max = ntot, width = 50, style = 3) + } + + seql <- seq(1, ntot, 1) + # Loop - all_res <- lapply(key, function(x) { + all_res <- lapply(seql, function(x) { + ad <- key[x] + if (progressbar) { + setTxtProgressBar(pb, x) + cat(paste0(" (", x, "/", ntot, ") ")) + } geo_lite_sf_single( - address = x, + address = ad, limit, return_addresses, full_results, @@ -110,6 +126,8 @@ geo_lite_sf <- function(address, ) }) + if (progressbar) close(pb) + all_res <- dplyr::bind_rows(all_res) all_res <- sf_to_tbl(all_res) diff --git a/R/nominatim_check_access.R b/R/nominatim_check_access.R index 16395a6b..74d7ab51 100644 --- a/R/nominatim_check_access.R +++ b/R/nominatim_check_access.R @@ -1,111 +1,111 @@ -#' Check access to Nominatim API -#' -#' @family api_management -#' -#' @description -#' Check if R has access to resources at -#' . -#' -#' @return a logical. -#' -#' @seealso -#' -#' -#' @examples -#' \donttest{ -#' nominatim_check_access() -#' } -#' @keywords internal -#' @export -nominatim_check_access <- function() { - url <- "https://nominatim.openstreetmap.org/status.php?format=json" - destfile <- tempfile(fileext = ".json") - - api_res <- api_call(url, destfile, TRUE) - - # nocov start - if (isFALSE(api_res)) { - return(FALSE) - } - # nocov end - result <- dplyr::as_tibble(jsonlite::fromJSON(destfile, flatten = TRUE)) - - # nocov start - if (result$status == 0 || result$message == "OK") { - return(TRUE) - } else { - return(FALSE) - } - # nocov end -} - -skip_if_api_server <- function() { - # nocov start - if (nominatim_check_access()) { - return(invisible(TRUE)) - } - - if (requireNamespace("testthat", quietly = TRUE)) { - testthat::skip("Nominatim API not reachable") - } - return(invisible()) - # nocov end -} - - -#' Helper function for centralize API queries -#' -#' @description -#' A wrapper of [utils::download.file()]. On warning on error it will -#' retry the call. Requests are adjusted to the rate of 1 query per second. -#' -#' See [Nominatim Usage -#' Policy](https://operations.osmfoundation.org/policies/nominatim/). -#' -#' @family api_management -#' -#' @inheritParams utils::download.file -#' @return A logical `TRUE/FALSE` -#' -#' @keywords internal -#' -api_call <- function(url, destfile, quiet) { - # nocov start - dwn_res <- - tryCatch( - download.file(url, destfile = destfile, quiet = quiet, mode = "wb"), - warning = function(e) { - return(FALSE) - }, - error = function(e) { - return(FALSE) - } - ) - # nocov end - # Always sleep to make 1 call per sec - Sys.sleep(1) - - # nocov start - if (isFALSE(dwn_res)) { - if (isFALSE(quiet)) message("Retrying query") - Sys.sleep(1) - - dwn_res <- - tryCatch( - download.file(url, destfile = destfile, quiet = quiet, mode = "wb"), - warning = function(e) { - return(FALSE) - }, - error = function(e) { - return(FALSE) - } - ) - } - - if (isFALSE(dwn_res)) { - return(FALSE) - } else { - return(TRUE) - } - # nocov end -} +#' Check access to Nominatim API +#' +#' @family api_management +#' +#' @description +#' Check if **R** has access to resources at +#' . +#' +#' @return a logical. +#' +#' @seealso +#' +#' +#' @examples +#' \donttest{ +#' nominatim_check_access() +#' } +#' @keywords internal +#' @export +nominatim_check_access <- function() { + url <- "https://nominatim.openstreetmap.org/status.php?format=json" + destfile <- tempfile(fileext = ".json") + + api_res <- api_call(url, destfile, TRUE) + + # nocov start + if (isFALSE(api_res)) { + return(FALSE) + } + # nocov end + result <- dplyr::as_tibble(jsonlite::fromJSON(destfile, flatten = TRUE)) + + # nocov start + if (result$status == 0 || result$message == "OK") { + return(TRUE) + } else { + return(FALSE) + } + # nocov end +} + +skip_if_api_server <- function() { + # nocov start + if (nominatim_check_access()) { + return(invisible(TRUE)) + } + + if (requireNamespace("testthat", quietly = TRUE)) { + testthat::skip("Nominatim API not reachable") + } + return(invisible()) + # nocov end +} + + +#' Helper function for centralize API queries +#' +#' @description +#' A wrapper of [utils::download.file()]. On warning on error it will +#' retry the call. Requests are adjusted to the rate of 1 query per second. +#' +#' See [Nominatim Usage +#' Policy](https://operations.osmfoundation.org/policies/nominatim/). +#' +#' @family api_management +#' +#' @inheritParams utils::download.file +#' @return A logical `TRUE/FALSE` +#' +#' @keywords internal +#' +api_call <- function(url, destfile, quiet) { + # nocov start + dwn_res <- + tryCatch( + download.file(url, destfile = destfile, quiet = quiet, mode = "wb"), + warning = function(e) { + return(FALSE) + }, + error = function(e) { + return(FALSE) + } + ) + # nocov end + # Always sleep to make 1 call per sec + Sys.sleep(1) + + # nocov start + if (isFALSE(dwn_res)) { + if (isFALSE(quiet)) message("Retrying query") + Sys.sleep(1) + + dwn_res <- + tryCatch( + download.file(url, destfile = destfile, quiet = quiet, mode = "wb"), + warning = function(e) { + return(FALSE) + }, + error = function(e) { + return(FALSE) + } + ) + } + + if (isFALSE(dwn_res)) { + return(FALSE) + } else { + return(TRUE) + } + # nocov end +} diff --git a/R/nominatimlite-package.R b/R/nominatimlite-package.R index 91289122..aaba2ada 100644 --- a/R/nominatimlite-package.R +++ b/R/nominatimlite-package.R @@ -8,5 +8,5 @@ NULL # import stuffs -#' @importFrom utils download.file +#' @importFrom utils download.file txtProgressBar setTxtProgressBar NULL diff --git a/R/reverse_geo_lite.R b/R/reverse_geo_lite.R index 444e360c..c1384fdb 100644 --- a/R/reverse_geo_lite.R +++ b/R/reverse_geo_lite.R @@ -47,7 +47,7 @@ #' #' ``` #' -#' @return A `tibble` with the results. +#' @return A \CRANpkg{tibble} with the results. #' #' @examplesIf nominatim_check_access() #' \donttest{ @@ -78,6 +78,7 @@ reverse_geo_lite <- function(lat, full_results = FALSE, return_coords = TRUE, verbose = FALSE, + progressbar = TRUE, custom_query = list()) { # Check inputs if (!is.numeric(lat) || !is.numeric(long)) { @@ -111,8 +112,22 @@ reverse_geo_lite <- function(lat, ) key <- dplyr::distinct(init_key) + # Set progress bar + ntot <- nrow(key) + # Set progress bar if n > 1 + progressbar <- all(progressbar, ntot > 1) + if (progressbar) { + pb <- txtProgressBar(min = 0, max = ntot, width = 50, style = 3) + } + + seql <- seq(1, ntot, 1) - all_res <- lapply(seq_len(nrow(key)), function(x) { + + all_res <- lapply(seql, function(x) { + if (progressbar) { + setTxtProgressBar(pb, x) + cat(paste0(" (", x, "/", ntot, ") ")) + } rw <- key[x, ] res_single <- reverse_geo_lite_single( as.double(rw$lat_cap_int), @@ -128,7 +143,7 @@ reverse_geo_lite <- function(lat, res_single }) - + if (progressbar) close(pb) all_res <- dplyr::bind_rows(all_res) all_res <- dplyr::left_join(init_key[, c(1, 2)], all_res, diff --git a/R/reverse_geo_lite_sf.R b/R/reverse_geo_lite_sf.R index f4365a99..c15e4a27 100644 --- a/R/reverse_geo_lite_sf.R +++ b/R/reverse_geo_lite_sf.R @@ -16,7 +16,7 @@ #' @inheritSection reverse_geo_lite About Zooming #' @inheritSection geo_lite_sf About Geometry Types #' -#' @return A `sf` object with the results. +#' @return A \CRANpkg{sf} object with the results. #' #' @examplesIf nominatim_check_access() #' \donttest{ @@ -67,6 +67,7 @@ reverse_geo_lite_sf <- function(lat, full_results = FALSE, return_coords = TRUE, verbose = FALSE, + progressbar = TRUE, custom_query = list(), points_only = TRUE) { # Check inputs @@ -101,7 +102,22 @@ reverse_geo_lite_sf <- function(lat, ) key <- dplyr::distinct(init_key) - all_res <- lapply(seq_len(nrow(key)), function(x) { + # Set progress bar + ntot <- nrow(key) + # Set progress bar if n > 1 + progressbar <- all(progressbar, ntot > 1) + if (progressbar) { + pb <- txtProgressBar(min = 0, max = ntot, width = 50, style = 3) + } + + seql <- seq(1, ntot, 1) + + + all_res <- lapply(seql, function(x) { + if (progressbar) { + setTxtProgressBar(pb, x) + cat(paste0(" (", x, "/", ntot, ") ")) + } rw <- key[x, ] res_single <- reverse_geo_lite_sf_single( as.double(rw$lat_cap_int), @@ -118,6 +134,7 @@ reverse_geo_lite_sf <- function(lat, res_single }) + if (progressbar) close(pb) all_res <- dplyr::bind_rows(all_res) diff --git a/README.md b/README.md index 15981cc9..19d35c2a 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,7 @@ some_addresses <- tribble( # geocode the addresses lat_longs <- geo_lite(some_addresses$addr, lat = "latitude", long = "longitude") +#> | | | 0% | |================= | 33% (1/3) | |================================= | 67% (2/3) | |==================================================| 100% (3/3) ``` Only latitude and longitude are returned from the geocoder service in @@ -180,6 +181,7 @@ reverse <- reverse_geo_lite( lat = lat_longs$latitude, long = lat_longs$longitude, address = "address_found" ) +#> | | | 0% | |================= | 33% (1/3) | |================================= | 67% (2/3) | |==================================================| 100% (3/3) ``` | address_found | lat | lon | @@ -195,7 +197,7 @@ the parameters available. ## Citation

-Hernangómez D (2023). nominatimlite: Interface with Nominatim API +Hernangómez D (2024). nominatimlite: Interface with Nominatim API Service. doi:10.5281/zenodo.5113195, https://dieghernan.github.io/nominatimlite/. @@ -206,11 +208,11 @@ A BibTeX entry for LaTeX users is @Manual{R-nominatimlite, title = {{nominatimlite}: Interface with {Nominatim} {API} Service}, author = {Diego Hernangómez}, - year = {2023}, - version = {0.2.1}, + year = {2024}, + version = {0.2.1.9000}, doi = {10.5281/zenodo.5113195}, url = {https://dieghernan.github.io/nominatimlite/}, - abstract = {Lite interface for getting data from OSM service Nominatim . Extract coordinates from addresses, find places near a set of coordinates, search for amenities and return spatial objects on sf format.}, + abstract = {Lite interface for getting data from OSM service Nominatim . Extract coordinates from addresses, find places near a set of coordinates and return spatial objects on sf format.}, } ## References diff --git a/codemeta.json b/codemeta.json index b9230e7e..cbcab856 100644 --- a/codemeta.json +++ b/codemeta.json @@ -2,13 +2,13 @@ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "identifier": "nominatimlite", - "description": "Lite interface for getting data from 'OSM' service 'Nominatim' . Extract coordinates from addresses, find places near a set of coordinates, search for amenities and return spatial objects on 'sf' format.", + "description": "Lite interface for getting data from 'OSM' service 'Nominatim' . Extract coordinates from addresses, find places near a set of coordinates and return spatial objects on 'sf' format.", "name": "nominatimlite: Interface with 'Nominatim' API Service", "relatedLink": ["https://dieghernan.github.io/nominatimlite/", "https://CRAN.R-project.org/package=nominatimlite"], "codeRepository": "https://github.com/dieghernan/nominatimlite", "issueTracker": "https://github.com/dieghernan/nominatimlite/issues", "license": "https://spdx.org/licenses/MIT", - "version": "0.2.1", + "version": "0.2.1.9000", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", @@ -154,6 +154,18 @@ "sameAs": "https://CRAN.R-project.org/package=jsonlite" }, "4": { + "@type": "SoftwareApplication", + "identifier": "lifecycle", + "name": "lifecycle", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=lifecycle" + }, + "5": { "@type": "SoftwareApplication", "identifier": "sf", "name": "sf", @@ -166,7 +178,7 @@ }, "sameAs": "https://CRAN.R-project.org/package=sf" }, - "5": { + "6": { "@type": "SoftwareApplication", "identifier": "utils", "name": "utils" @@ -175,11 +187,11 @@ }, "applicationCategory": "cartography", "keywords": ["r", "geocoding", "openstreetmap", "address", "nominatim", "reverse-geocoding", "rstats", "shapefile", "r-package", "spatial", "cran", "api-wrapper", "api", "gis"], - "fileSize": "258.67KB", + "fileSize": "251.765KB", "citation": [ { "@type": "SoftwareSourceCode", - "datePublished": "2023", + "datePublished": "2024", "author": [ { "@type": "Person", diff --git a/data/osm_amenities.rda b/data/osm_amenities.rda deleted file mode 100644 index 34df32421ca4659f328f63b1628053f68fdab882..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1127 zcmV-t1ep6DiwFP!000002JKkQj@vd6*4keG$h+%pg5=OsULZO24T?5FFGY){KyxF8 z6eST$kt%=e_?8Fhvvxa_MaoheG>0JA7JIO)`9uzfGvCZm`sMp~-{kM|EX!uuVm`}e zbG%*5@N$tYvJL)UYugZLxDrlqn`QH--QZbvi~mJGD1Ym%;|dhx4+7b|E<6J#w0dB` z&94TOZMAWa=)*)eZ$w~{0Qt#4{sRZ;Y6gZsP~_{^%5mJMP?*T><+sM!m*08m{Nsqn z5ua(q&Ci}n!Ct)OW-r+P3(emE6Y|sn|GUWTZ-9OB#gCw%;vtM*2w(o>YHsWokjAHy zIRz7)K?OGz7(6EQ$bvzcjteCkPD-uQc_!QwroD-K*dQ4QGaQW^gQ0L zD&c$7yjpmnuw;tJ~)o!0i1D)Cl|ccE^RU(x-5rD%hm`xWQqx#o2LER>4U04 zM(52b{k^}vq!^({$-K}Naau?o7YxNub$M_Aq)iGB7NavmR~ET4JYL#bACk1epz*fW zD*5HKLgeRmVc@672k$j%(_njvFbWr>6GQG(`SI=bS{&~(SGhC zu^sC&aa59`j4>TabCeQiz`?81p!$jGjnRi!(X{Je+6TPc-{1c+8Mp|`^&cnZIPCP1 z;v{FMvGe=M_MUc4I@HKeXAQ8y+ne+Vg+D)^o-ltlo&Rw+|LfAbVd=_qYd^AV=emp2 tZ)Cze9fq`wld+AIfG7Lp**normcK}rYvgI?`EHr+_ZLPuhX7L&001>KIV%7F diff --git a/inst/WORDLIST b/inst/WORDLIST index 71a12e32..9ef50f02 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -1,3 +1,4 @@ +Belanger CMD Cambon CodeFactor @@ -6,20 +7,21 @@ Geocode Geocodes Geocoding Mapbox +Maëlle Nominatim ORCID OSM OpenStreetMap Padgham +Possenriede +Rudis TomTom Transamerica +al api -atm -bbq -biergarten -centre codecov de +et geocode geocoded geocoder @@ -28,13 +30,9 @@ geolocated ie json lon -osm osmdata rlang -stripclub -swingerclub -theatre tibble -townhall +tidygeocoder unnesting vectorized diff --git a/inst/schemaorg.json b/inst/schemaorg.json index 2716cfcb..c637c64e 100644 --- a/inst/schemaorg.json +++ b/inst/schemaorg.json @@ -20,7 +20,7 @@ "familyName": "Hernangómez", "givenName": "Diego" }, - "description": "Lite interface for getting data from 'OSM' service 'Nominatim' . Extract coordinates from addresses, find places near a set of coordinates, search for amenities and return spatial objects on 'sf' format.", + "description": "Lite interface for getting data from 'OSM' service 'Nominatim' . Extract coordinates from addresses, find places near a set of coordinates and return spatial objects on 'sf' format.", "license": "https://spdx.org/licenses/MIT", "name": "nominatimlite: Interface with 'Nominatim' API Service", "programmingLanguage": { @@ -35,7 +35,7 @@ "url": "https://cran.r-project.org" }, "runtimePlatform": "R version 4.3.2 (2023-10-31 ucrt)", - "version": "0.2.1" + "version": "0.2.1.9000" }, { "id": "https://doi.org/10.5281/zenodo.5113195", diff --git a/man/bbox_to_poly.Rd b/man/bbox_to_poly.Rd index a44e85e0..5644db51 100644 --- a/man/bbox_to_poly.Rd +++ b/man/bbox_to_poly.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/bbox_to_poly.R \name{bbox_to_poly} \alias{bbox_to_poly} -\title{Create a bounding box \code{sf} object} +\title{Create a bounding box \CRANpkg{sf} object} \usage{ bbox_to_poly(bbox = NA, xmin = NA, ymin = NA, xmax = NA, ymax = NA, crs = 4326) } @@ -64,14 +64,7 @@ if (any(!sf::st_is_empty(sfobj))) { Get spatial (\code{sf}) objects: \code{\link{geo_address_lookup_sf}()}, -\code{\link{geo_amenity_sf}()}, \code{\link{geo_lite_sf}()}, \code{\link{reverse_geo_lite_sf}()} - -Search amenities: -\code{\link{geo_amenity_sf}()}, -\code{\link{geo_amenity}()}, -\code{\link{osm_amenities}} } -\concept{amenity} \concept{spatial} diff --git a/man/figures/README-pizzahut-1.png b/man/figures/README-pizzahut-1.png index 75c8303a09ca708af349f913a7c466161db1702b..3fbf34d4fd37f3c70f5e3f6e11ba4a0b73e8df47 100644 GIT binary patch literal 22562 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 literal 22412 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 literal 21436 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 KO5st + lifecycle: archived + + + + + + + + + + + + + + + lifecycle + + archived + + diff --git a/man/figures/lifecycle-defunct.svg b/man/figures/lifecycle-defunct.svg new file mode 100644 index 00000000..d5c9559e --- /dev/null +++ b/man/figures/lifecycle-defunct.svg @@ -0,0 +1,21 @@ + + lifecycle: defunct + + + + + + + + + + + + + + + lifecycle + + defunct + + diff --git a/man/figures/lifecycle-deprecated.svg b/man/figures/lifecycle-deprecated.svg new file mode 100644 index 00000000..b61c57c3 --- /dev/null +++ b/man/figures/lifecycle-deprecated.svg @@ -0,0 +1,21 @@ + + lifecycle: deprecated + + + + + + + + + + + + + + + lifecycle + + deprecated + + diff --git a/man/figures/lifecycle-experimental.svg b/man/figures/lifecycle-experimental.svg new file mode 100644 index 00000000..5d88fc2c --- /dev/null +++ b/man/figures/lifecycle-experimental.svg @@ -0,0 +1,21 @@ + + lifecycle: experimental + + + + + + + + + + + + + + + lifecycle + + experimental + + diff --git a/man/figures/lifecycle-maturing.svg b/man/figures/lifecycle-maturing.svg new file mode 100644 index 00000000..897370ec --- /dev/null +++ b/man/figures/lifecycle-maturing.svg @@ -0,0 +1,21 @@ + + lifecycle: maturing + + + + + + + + + + + + + + + lifecycle + + maturing + + diff --git a/man/figures/lifecycle-questioning.svg b/man/figures/lifecycle-questioning.svg new file mode 100644 index 00000000..7c1721d0 --- /dev/null +++ b/man/figures/lifecycle-questioning.svg @@ -0,0 +1,21 @@ + + lifecycle: questioning + + + + + + + + + + + + + + + lifecycle + + questioning + + diff --git a/man/figures/lifecycle-soft-deprecated.svg b/man/figures/lifecycle-soft-deprecated.svg new file mode 100644 index 00000000..9c166ff3 --- /dev/null +++ b/man/figures/lifecycle-soft-deprecated.svg @@ -0,0 +1,21 @@ + + lifecycle: soft-deprecated + + + + + + + + + + + + + + + lifecycle + + soft-deprecated + + diff --git a/man/figures/lifecycle-stable.svg b/man/figures/lifecycle-stable.svg new file mode 100644 index 00000000..9bf21e76 --- /dev/null +++ b/man/figures/lifecycle-stable.svg @@ -0,0 +1,29 @@ + + lifecycle: stable + + + + + + + + + + + + + + + + lifecycle + + + + stable + + + diff --git a/man/figures/lifecycle-superseded.svg b/man/figures/lifecycle-superseded.svg new file mode 100644 index 00000000..db8d757f --- /dev/null +++ b/man/figures/lifecycle-superseded.svg @@ -0,0 +1,21 @@ + + lifecycle: superseded + + + + + + + + + + + + + + + lifecycle + + superseded + + diff --git a/man/geo_address_lookup.Rd b/man/geo_address_lookup.Rd index 4025644e..f5c95974 100644 --- a/man/geo_address_lookup.Rd +++ b/man/geo_address_lookup.Rd @@ -39,7 +39,7 @@ returned. See also \code{return_addresses}.} (i.e. \code{list(countrycodes = "US")}). See \strong{Details}.} } \value{ -A \code{tibble} with the results found by the query. +A \CRANpkg{tibble} with the results found by the query. } \description{ The lookup API allows to query the address and other details of one or @@ -71,8 +71,6 @@ Address Lookup API: Geocoding strings: \code{\link{geo_address_lookup_sf}()}, -\code{\link{geo_amenity_sf}()}, -\code{\link{geo_amenity}()}, \code{\link{geo_lite_sf}()}, \code{\link{geo_lite}()} } diff --git a/man/geo_address_lookup_sf.Rd b/man/geo_address_lookup_sf.Rd index fe8c9dc3..51b14ce5 100644 --- a/man/geo_address_lookup_sf.Rd +++ b/man/geo_address_lookup_sf.Rd @@ -38,7 +38,7 @@ points (\code{TRUE}, which is the default) or potentially other shapes as provided by the Nominatim API (\code{FALSE}). See \strong{About Geometry Types}.} } \value{ -A \code{sf} object with the results. +A \CRANpkg{sf} object with the results. } \description{ The lookup API allows to query the address and other details of one or @@ -111,14 +111,11 @@ Address Lookup API: Geocoding strings: \code{\link{geo_address_lookup}()}, -\code{\link{geo_amenity_sf}()}, -\code{\link{geo_amenity}()}, \code{\link{geo_lite_sf}()}, \code{\link{geo_lite}()} Get spatial (\code{sf}) objects: \code{\link{bbox_to_poly}()}, -\code{\link{geo_amenity_sf}()}, \code{\link{geo_lite_sf}()}, \code{\link{reverse_geo_lite_sf}()} } diff --git a/man/geo_amenity.Rd b/man/geo_amenity.Rd index 2487e822..c0aeef23 100644 --- a/man/geo_amenity.Rd +++ b/man/geo_amenity.Rd @@ -23,8 +23,7 @@ geo_amenity( restrict the search area. See \strong{Details}.} \item{amenity}{A character of a vector of character with the amenities to be -geolocated (i.e. \code{c("pub", "restaurant")}). See \strong{Details} and -\link{osm_amenities}.} +geolocated (i.e. \code{c("pub", "restaurant")}).} \item{lat}{latitude column name in the output data (default \code{"lat"}).} @@ -41,23 +40,20 @@ returned. See also \code{return_addresses}.} \item{verbose}{if \code{TRUE} then detailed logs are output to the console.} -\item{custom_query}{API-specific parameters to be used. -See \code{\link[=geo_lite]{geo_lite()}}.} +\item{custom_query}{API-specific parameters to be used.} \item{strict}{Logical \code{TRUE/FALSE}. Force the results to be included inside the \code{bbox}. Note that Nominatim default behavior may return results located outside the provided bounding box.} } \value{ -A \code{tibble} with the results. +A \CRANpkg{tibble} with the results. } \description{ -This function search amenities as defined by OpenStreetMap on a restricted -area defined by a bounding box in the form of -\verb{(, , , )}. This -function returns the \CRANpkg{tibble} associated with the query, see -\code{\link[=geo_amenity_sf]{geo_amenity_sf()}} for retrieving the data as a spatial object -(\CRANpkg{sf} format). +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} + +This operation is not supported any more. Use +\href{https://github.com/ropensci/osmdata}{\strong{osmdata}} instead. } \details{ Bounding boxes can be located using different online tools, as @@ -66,39 +62,7 @@ Bounding boxes can be located using different online tools, as For a full list of valid amenities see \url{https://wiki.openstreetmap.org/wiki/Key:amenity}. } -\examples{ -\dontshow{if (nominatim_check_access()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} -\donttest{ -# Times Square, NY, USA -bbox <- c(-73.9894467311, 40.75573629, -73.9830630737, 40.75789245) - -geo_amenity(bbox = bbox, amenity = "restaurant") - -# Several amenities -geo_amenity(bbox = bbox, amenity = c("restaurant", "pub")) - -# Increase limit and use with strict -geo_amenity( - bbox = bbox, amenity = c("restaurant", "pub"), limit = 10, - strict = TRUE -) -} -\dontshow{\}) # examplesIf} -} \seealso{ \code{\link[=geo_amenity_sf]{geo_amenity_sf()}} - -Search amenities: -\code{\link{bbox_to_poly}()}, -\code{\link{geo_amenity_sf}()}, -\code{\link{osm_amenities}} - -Geocoding strings: -\code{\link{geo_address_lookup_sf}()}, -\code{\link{geo_address_lookup}()}, -\code{\link{geo_amenity_sf}()}, -\code{\link{geo_lite_sf}()}, -\code{\link{geo_lite}()} } -\concept{amenity} -\concept{geocoding} +\keyword{internal} diff --git a/man/geo_amenity_sf.Rd b/man/geo_amenity_sf.Rd index 45163deb..f492c596 100644 --- a/man/geo_amenity_sf.Rd +++ b/man/geo_amenity_sf.Rd @@ -22,8 +22,7 @@ geo_amenity_sf( restrict the search area. See \strong{Details}.} \item{amenity}{A character of a vector of character with the amenities to be -geolocated (i.e. \code{c("pub", "restaurant")}). See \strong{Details} and -\link{osm_amenities}.} +geolocated (i.e. \code{c("pub", "restaurant")}).} \item{limit}{maximum number of results to return per input address. Note that each query returns a maximum of 50 results.} @@ -48,14 +47,13 @@ the \code{bbox}. Note that Nominatim default behavior may return results located outside the provided bounding box.} } \value{ -A \code{sf} object with the results. +A \CRANpkg{sf} object with the results. } \description{ -This function search amenities as defined by OpenStreetMap on a restricted -area defined by a bounding box in the form of -\verb{(, , , )}. This -function returns the \CRANpkg{sf} spatial object associated with the query, -see \code{\link[=geo_amenity]{geo_amenity()}} for retrieving the data in \CRANpkg{tibble} format. +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} + +This operation is not supported any more. Use +\href{https://github.com/ropensci/osmdata}{\strong{osmdata}} instead. } \details{ Bounding boxes can be located using different online tools, as @@ -84,56 +82,4 @@ The function is vectorized, allowing for multiple addresses to be geocoded; in case of \code{points_only = FALSE} multiple geometry types may be returned. } -\examples{ -\dontshow{if (nominatim_check_access()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} -\donttest{ -# Madrid, Spain - -library(ggplot2) - -bbox <- c(-3.888954, 40.311977, -3.517916, 40.643729) - -# Restaurants and pubs - -rest_pub <- geo_amenity_sf(bbox, c("restaurant", "pub"), limit = 50) - -if (any(!sf::st_is_empty(rest_pub))) { - ggplot(rest_pub) + - geom_sf() -} - -# Hospital as polygon - -hosp <- geo_amenity_sf(bbox, "hospital", points_only = FALSE) - -if (any(!sf::st_is_empty(hosp))) { - ggplot(hosp) + - geom_sf() -} -} -\dontshow{\}) # examplesIf} -} -\seealso{ -\code{\link[=geo_amenity]{geo_amenity()}} - -Search amenities: -\code{\link{bbox_to_poly}()}, -\code{\link{geo_amenity}()}, -\code{\link{osm_amenities}} - -Geocoding strings: -\code{\link{geo_address_lookup_sf}()}, -\code{\link{geo_address_lookup}()}, -\code{\link{geo_amenity}()}, -\code{\link{geo_lite_sf}()}, -\code{\link{geo_lite}()} - -Get spatial (\code{sf}) objects: -\code{\link{bbox_to_poly}()}, -\code{\link{geo_address_lookup_sf}()}, -\code{\link{geo_lite_sf}()}, -\code{\link{reverse_geo_lite_sf}()} -} -\concept{amenity} -\concept{geocoding} -\concept{spatial} +\keyword{internal} diff --git a/man/geo_lite.Rd b/man/geo_lite.Rd index 8b1ae60a..1f76e33e 100644 --- a/man/geo_lite.Rd +++ b/man/geo_lite.Rd @@ -12,6 +12,7 @@ geo_lite( full_results = FALSE, return_addresses = TRUE, verbose = FALSE, + progressbar = TRUE, custom_query = list() ) } @@ -35,11 +36,14 @@ returned. See also \code{return_addresses}.} \item{verbose}{if \code{TRUE} then detailed logs are output to the console.} +\item{progressbar}{Logical. If \code{TRUE} displays a progress bar to indicate +the progress of the function.} + \item{custom_query}{A named list with API-specific parameters to be used (i.e. \code{list(countrycodes = "US")}). See \strong{Details}.} } \value{ -A \code{tibble} with the results. +A \CRANpkg{tibble} with the results. } \description{ Geocodes addresses given as character values. This @@ -73,8 +77,6 @@ geo_lite(c("Madrid", "Barcelona"), Geocoding strings: \code{\link{geo_address_lookup_sf}()}, \code{\link{geo_address_lookup}()}, -\code{\link{geo_amenity_sf}()}, -\code{\link{geo_amenity}()}, \code{\link{geo_lite_sf}()} } \concept{geocoding} diff --git a/man/geo_lite_sf.Rd b/man/geo_lite_sf.Rd index 578ee6d0..72058fb9 100644 --- a/man/geo_lite_sf.Rd +++ b/man/geo_lite_sf.Rd @@ -10,6 +10,7 @@ geo_lite_sf( return_addresses = TRUE, full_results = FALSE, verbose = FALSE, + progressbar = TRUE, custom_query = list(), points_only = TRUE ) @@ -30,6 +31,9 @@ If \code{FALSE} (default) only address columns are returned. See also \item{verbose}{if \code{TRUE} then detailed logs are output to the console.} +\item{progressbar}{Logical. If \code{TRUE} displays a progress bar to indicate +the progress of the function.} + \item{custom_query}{A named list with API-specific parameters to be used (i.e. \code{list(countrycodes = "US")}). See \strong{Details}.} @@ -38,7 +42,7 @@ points (\code{TRUE}, which is the default) or potentially other shapes as provided by the Nominatim API (\code{FALSE}). See \strong{About Geometry Types}.} } \value{ -A \code{sf} object with the results. +A \CRANpkg{sf} object with the results. } \description{ This function allows you to geocode addresses and return the corresponding @@ -109,14 +113,11 @@ if (any(!sf::st_is_empty(Madrid))) { Geocoding strings: \code{\link{geo_address_lookup_sf}()}, \code{\link{geo_address_lookup}()}, -\code{\link{geo_amenity_sf}()}, -\code{\link{geo_amenity}()}, \code{\link{geo_lite}()} Get spatial (\code{sf}) objects: \code{\link{bbox_to_poly}()}, \code{\link{geo_address_lookup_sf}()}, -\code{\link{geo_amenity_sf}()}, \code{\link{reverse_geo_lite_sf}()} } \concept{geocoding} diff --git a/man/nominatim_check_access.Rd b/man/nominatim_check_access.Rd index 9c62510a..65398060 100644 --- a/man/nominatim_check_access.Rd +++ b/man/nominatim_check_access.Rd @@ -10,7 +10,7 @@ nominatim_check_access() a logical. } \description{ -Check if R has access to resources at +Check if \strong{R} has access to resources at \url{https://nominatim.openstreetmap.org}. } \examples{ diff --git a/man/nominatimlite-package.Rd b/man/nominatimlite-package.Rd index 1ba31c09..3a627e0d 100644 --- a/man/nominatimlite-package.Rd +++ b/man/nominatimlite-package.Rd @@ -8,7 +8,7 @@ \description{ \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} -Lite interface for getting data from 'OSM' service 'Nominatim' \url{https://nominatim.org/release-docs/latest/}. Extract coordinates from addresses, find places near a set of coordinates, search for amenities and return spatial objects on 'sf' format. +Lite interface for getting data from 'OSM' service 'Nominatim' \url{https://nominatim.org/release-docs/latest/}. Extract coordinates from addresses, find places near a set of coordinates and return spatial objects on 'sf' format. } \seealso{ Useful links: diff --git a/man/osm_amenities.Rd b/man/osm_amenities.Rd deleted file mode 100644 index bcf78a4c..00000000 --- a/man/osm_amenities.Rd +++ /dev/null @@ -1,144 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/data.R -\docType{data} -\encoding{UTF-8} -\name{osm_amenities} -\alias{osm_amenities} -\title{OpenStreetMap amenity database} -\format{ -A \code{tibble} with with -100 rows and -fields: -\describe{ -\item{category}{The category of the amenity} -\item{amenity}{The name of the amenity} -} -} -\source{ -\url{https://wiki.openstreetmap.org/wiki/Key:amenity} -} -\description{ -Database with the list of amenities available on OpenStreetMap. -} -\details{ -\tabular{ll}{ - \strong{category} \tab \strong{amenity} \cr - Sustenance \tab bar \cr - Sustenance \tab biergarten \cr - Sustenance \tab cafe \cr - Sustenance \tab fast_food \cr - Sustenance \tab food_court \cr - Sustenance \tab ice_cream \cr - Sustenance \tab pub \cr - Sustenance \tab restaurant \cr - Education \tab college \cr - Education \tab driving_school \cr - Education \tab kindergarten \cr - Education \tab language_school \cr - Education \tab library \cr - Education \tab toy_library \cr - Education \tab music_school \cr - Education \tab school \cr - Education \tab university \cr - Transportation \tab bicycle_parking \cr - Transportation \tab bicycle_repair_station \cr - Transportation \tab bicycle_rental \cr - Transportation \tab boat_rental \cr - Transportation \tab boat_sharing \cr - Transportation \tab bus_station \cr - Transportation \tab car_rental \cr - Transportation \tab car_sharing \cr - Transportation \tab car_wash \cr - Transportation \tab vehicle_inspection \cr - Transportation \tab charging_station \cr - Transportation \tab ferry_terminal \cr - Transportation \tab fuel \cr - Transportation \tab grit_bin \cr - Transportation \tab motorcycle_parking \cr - Transportation \tab parking \cr - Transportation \tab parking_entrance \cr - Transportation \tab parking_space \cr - Transportation \tab taxi \cr - Financial \tab atm \cr - Financial \tab bank \cr - Financial \tab bureau_de_change \cr - Healthcare \tab baby_hatch \cr - Healthcare \tab clinic \cr - Healthcare \tab dentist \cr - Healthcare \tab doctors \cr - Healthcare \tab hospital \cr - Healthcare \tab nursing_home \cr - Healthcare \tab pharmacy \cr - Healthcare \tab social_facility \cr - Healthcare \tab veterinary \cr - Entertainment-Arts-Culture \tab arts_centre \cr - Entertainment-Arts-Culture \tab brothel \cr - Entertainment-Arts-Culture \tab casino \cr - Entertainment-Arts-Culture \tab cinema \cr - Entertainment-Arts-Culture \tab community_centre \cr - Entertainment-Arts-Culture \tab conference_centre \cr - Entertainment-Arts-Culture \tab events_venue \cr - Entertainment-Arts-Culture \tab fountain \cr - Entertainment-Arts-Culture \tab gambling \cr - Entertainment-Arts-Culture \tab love_hotel \cr - Entertainment-Arts-Culture \tab nightclub \cr - Entertainment-Arts-Culture \tab planetarium \cr - Entertainment-Arts-Culture \tab public_bookcase \cr - Entertainment-Arts-Culture \tab social_centre \cr - Entertainment-Arts-Culture \tab stripclub \cr - Entertainment-Arts-Culture \tab studio \cr - Entertainment-Arts-Culture \tab swingerclub \cr - Entertainment-Arts-Culture \tab theatre \cr - Public Service \tab courthouse \cr - Public Service \tab embassy \cr - Public Service \tab fire_station \cr - Public Service \tab police \cr - Public Service \tab post_box \cr - Public Service \tab post_depot \cr - Public Service \tab post_office \cr - Public Service \tab prison \cr - Public Service \tab ranger_station \cr - Public Service \tab townhall \cr - Facilities \tab bbq \cr - Facilities \tab bench \cr - Facilities \tab dog_toilet \cr - Facilities \tab drinking_water \cr - Facilities \tab give_box \cr - Facilities \tab shelter \cr - Facilities \tab shower \cr - Facilities \tab telephone \cr - Facilities \tab toilets \cr - Facilities \tab water_point \cr - Facilities \tab watering_place \cr - Waste Management \tab sanitary_dump_station \cr - Waste Management \tab recycling \cr - Waste Management \tab waste_basket \cr - Waste Management \tab waste_disposal \cr - Waste Management \tab waste_transfer_station \cr - Others \tab animal_boarding \cr - Others \tab animal_breeding \cr - Others \tab animal_shelter \cr - Others \tab baking_oven \cr - Others \tab childcare \cr - Others \tab clock \cr - Others \tab crematorium \cr - Others \tab dive_centre \cr -} -} -\note{ -Data extracted on \strong{14 June 2021}. -} -\examples{ - -amenities <- nominatimlite::osm_amenities - -amenities -} -\seealso{ -Search amenities: -\code{\link{bbox_to_poly}()}, -\code{\link{geo_amenity_sf}()}, -\code{\link{geo_amenity}()} -} -\concept{amenity} -\concept{datasets} diff --git a/man/reverse_geo_lite.Rd b/man/reverse_geo_lite.Rd index f152d9ff..2545e841 100644 --- a/man/reverse_geo_lite.Rd +++ b/man/reverse_geo_lite.Rd @@ -11,6 +11,7 @@ reverse_geo_lite( full_results = FALSE, return_coords = TRUE, verbose = FALSE, + progressbar = TRUE, custom_query = list() ) } @@ -31,11 +32,14 @@ returned. See also \code{return_addresses}.} \item{verbose}{if \code{TRUE} then detailed logs are output to the console.} +\item{progressbar}{Logical. If \code{TRUE} displays a progress bar to indicate +the progress of the function.} + \item{custom_query}{API-specific parameters to be used, passed as a named list (ie. \code{list(zoom = 3)}). See \strong{Details}.} } \value{ -A \code{tibble} with the results. +A \CRANpkg{tibble} with the results. } \description{ Generates an address from a latitude and longitude. Latitudes must be diff --git a/man/reverse_geo_lite_sf.Rd b/man/reverse_geo_lite_sf.Rd index 18e3b0cf..c53d1a6d 100644 --- a/man/reverse_geo_lite_sf.Rd +++ b/man/reverse_geo_lite_sf.Rd @@ -11,6 +11,7 @@ reverse_geo_lite_sf( full_results = FALSE, return_coords = TRUE, verbose = FALSE, + progressbar = TRUE, custom_query = list(), points_only = TRUE ) @@ -32,6 +33,9 @@ returned. See also \code{return_addresses}.} \item{verbose}{if \code{TRUE} then detailed logs are output to the console.} +\item{progressbar}{Logical. If \code{TRUE} displays a progress bar to indicate +the progress of the function.} + \item{custom_query}{API-specific parameters to be used, passed as a named list (ie. \code{list(zoom = 3)}). See \strong{Details}.} @@ -40,7 +44,7 @@ points (\code{TRUE}, which is the default) or potentially other shapes as provided by the Nominatim API (\code{FALSE}). See \strong{About Geometry Types}.} } \value{ -A \code{sf} object with the results. +A \CRANpkg{sf} object with the results. } \description{ Generates an address from a latitude and longitude. Latitudes must be @@ -139,7 +143,6 @@ Reverse geocoding coordinates: Get spatial (\code{sf}) objects: \code{\link{bbox_to_poly}()}, \code{\link{geo_address_lookup_sf}()}, -\code{\link{geo_amenity_sf}()}, \code{\link{geo_lite_sf}()} } \concept{reverse} diff --git a/man/roxygen/meta.R b/man/roxygen/meta.R index 3f731d8c..ee4c8a6e 100644 --- a/man/roxygen/meta.R +++ b/man/roxygen/meta.R @@ -1,7 +1,6 @@ list( rd_family_title = list( lookup = "Address Lookup API: ", - amenity = "Search amenities: ", geocoding = "Geocoding strings: ", reverse = "Reverse geocoding coordinates: ", spatial = "Get spatial (\\code{sf}) objects: ", diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index a44c42d4..1c0810aa 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -10,9 +10,6 @@ template: creator: "@dhernangomez" card: summary_large_image -development: - mode: auto - repo: branch: main @@ -43,11 +40,6 @@ reference: contents: - has_concept("spatial") -- title: Datasets - desc: Helper datasets. - contents: - - has_concept("datasets") - - title: About the package contents: - nominatimlite-package diff --git a/tests/testthat/_snaps/geo_amenity.md b/tests/testthat/_snaps/geo_amenity.md new file mode 100644 index 00000000..5264cbf6 --- /dev/null +++ b/tests/testthat/_snaps/geo_amenity.md @@ -0,0 +1,9 @@ +# Deprecated + + Code + geo_amenity() + Condition + Error: + ! `geo_amenity()` was deprecated in nominatimlite 0.3.0 and is now defunct. + i Operation not supported any more by the Nominatim API. + diff --git a/tests/testthat/_snaps/geo_amenity_sf.md b/tests/testthat/_snaps/geo_amenity_sf.md new file mode 100644 index 00000000..5139302d --- /dev/null +++ b/tests/testthat/_snaps/geo_amenity_sf.md @@ -0,0 +1,9 @@ +# Deprecated + + Code + geo_amenity_sf() + Condition + Error: + ! `geo_amenity_sf()` was deprecated in nominatimlite 0.3.0 and is now defunct. + i Operation not supported any more by the Nominatim API. + diff --git a/tests/testthat/test-geo_amenity.R b/tests/testthat/test-geo_amenity.R index 5648b43f..b8964b37 100644 --- a/tests/testthat/test-geo_amenity.R +++ b/tests/testthat/test-geo_amenity.R @@ -1,190 +1,5 @@ -test_that("Returning not reachable", { - expect_message(geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - amenity = "xbzbzbzoa aiaia" - ), "not reachable") +test_that("Deprecated", { + skip_if_not_installed("lifecycle") - skip_on_cran() - skip_if_api_server() - - expect_message(obj <- geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - amenity = "xbzbzbzoa aiaia" - )) - - expect_true(nrow(obj) == 1) - expect_true(obj$query == "xbzbzbzoa aiaia") - expect_s3_class(obj, "tbl") - expect_identical(names(obj), c("query", "lat", "lon")) - expect_true(all( - vapply(obj, class, FUN.VALUE = character(1)) - == c("character", rep("numeric", 2)) - )) - expect_true(is.na(obj$lat)) - expect_true(is.na(obj$lon)) - - expect_message( - obj_renamed <- geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - amenity = "xbzbzbzoa aiaia", - lat = "lata", - long = "longa" - ), - "not reachable" - ) - - expect_identical(names(obj_renamed), c("query", "lata", "longa")) - - names(obj_renamed) <- names(obj) - - expect_identical(obj, obj_renamed) -}) - -test_that("Returning empty query", { - skip_on_cran() - skip_if_api_server() - - - expect_message( - obj <- geo_amenity( - bbox = c(-88.1446, 41.5022, -87.4854, 41.8795), - amenity = "grit_bin" - ), - "No results" - ) - - - expect_true(nrow(obj) == 1) - expect_true(obj$query == "grit_bin") - expect_s3_class(obj, "tbl") - expect_identical(names(obj), c("query", "lat", "lon")) - expect_true(all( - vapply(obj, class, FUN.VALUE = character(1)) - == c("character", rep("numeric", 2)) - )) - expect_true(is.na(obj$lat)) - expect_true(is.na(obj$lon)) - - expect_message( - obj_renamed <- geo_amenity( - bbox = c(-88.1446, 41.5022, -87.4854, 41.8795), - amenity = "grit_bin", - lat = "lata", - long = "longa" - ), - "No results" - ) - - expect_identical(names(obj_renamed), c("query", "lata", "longa")) - - names(obj_renamed) <- names(obj) - - expect_identical(obj, obj_renamed) -}) - - -test_that("Data format", { - skip_on_cran() - skip_if_api_server() - skip_if_offline() - - obj <- geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - c("pub", "restaurant"), - ) - - expect_s3_class(obj, "tbl") - expect_false(inherits(obj, "sf")) -}) - -test_that("Checking query", { - skip_on_cran() - skip_if_api_server() - skip_if_offline() - - expect_message(obj <- geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - c("pub", "restaurant"), - limit = 51 - ), "50 results") - - - expect_identical(names(obj), c("query", "lat", "lon", "address")) - - obj <- geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - long = "ong", lat = "at", - full_results = FALSE, - return_addresses = FALSE - ) - expect_identical(names(obj), c("query", "at", "ong")) - - obj <- geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - long = "ong", lat = "at", - full_results = FALSE, - return_addresses = TRUE - ) - - expect_identical(names(obj), c("query", "at", "ong", "address")) - - obj <- geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - long = "ong", lat = "at", - full_results = TRUE, - return_addresses = FALSE - ) - - expect_identical(names(obj)[1:4], c("query", "at", "ong", "address")) - expect_gt(ncol(obj), 4) - - - expect_gt(nrow(geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - limit = 10, - custom_query = list(countrycode = "es") - )), 4) - expect_equal(nrow(geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - custom_query = list(countrycode = "es") - )), 1) - expect_equal(nrow(geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - custom_query = list(extratags = 1) - )), 1) - - expect_lt(nrow(geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - limit = 1, - strict = TRUE - )), 2) -}) - -test_that("Dedupe", { - skip_on_cran() - skip_if_api_server() - skip_if_offline() - - # Dupes - dup <- geo_amenity( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - rep(c("pub", "restaurant"), 50), - limit = 1 - ) - - expect_equal(nrow(dup), 100) - expect_equal(as.character(dup$query), rep(c("pub", "restaurant"), 50)) - - # Check deduping - dedup <- dplyr::distinct(dup) - - expect_equal(nrow(dedup), 2) - expect_equal(as.character(dedup$query), rep(c("pub", "restaurant"), 1)) + expect_snapshot(geo_amenity(), error = TRUE) }) diff --git a/tests/testthat/test-geo_amenity_sf.R b/tests/testthat/test-geo_amenity_sf.R index bf87617a..02f8cbf6 100644 --- a/tests/testthat/test-geo_amenity_sf.R +++ b/tests/testthat/test-geo_amenity_sf.R @@ -1,209 +1,5 @@ -test_that("Returning not reachable", { - expect_message(geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - amenity = "xbzbzbzoa aiaia" - ), "not reachable") +test_that("Deprecated", { + skip_if_not_installed("lifecycle") - skip_on_cran() - skip_if_api_server() - - expect_message( - obj <- geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - amenity = "xbzbzbzoa aiaia" - ) - ) - - expect_true(nrow(obj) == 1) - expect_true(obj$query == "xbzbzbzoa aiaia") - expect_s3_class(obj, "sf") - expect_s3_class(obj, "tbl") - expect_true(sf::st_is_empty(obj)) - expect_identical(sf::st_crs(obj), sf::st_crs(4326)) -}) - - -test_that("Returning empty query", { - skip_on_cran() - skip_if_api_server() - - - expect_message( - obj <- geo_amenity_sf( - bbox = c(-88.1446, 41.5022, -87.4854, 41.8795), - amenity = "grit_bin" - ), - "No results" - ) - - - expect_true(nrow(obj) == 1) - expect_true(obj$query == "grit_bin") - expect_s3_class(obj, "sf") - expect_s3_class(obj, "tbl") - expect_true(sf::st_is_empty(obj)) - expect_identical(sf::st_crs(obj), sf::st_crs(4326)) -}) - - -test_that("Data format", { - skip_on_cran() - skip_if_api_server() - skip_if_offline() - - obj <- geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - c("pub", "restaurant"), - ) - - expect_s3_class(obj, "sf") - expect_s3_class(obj, "tbl") - expect_equal(nrow(obj), 2) - expect_identical(as.character(obj$query), c("pub", "restaurant")) - - - # Polygon - - expect_message( - hosp <- geo_amenity_sf( - c( - -3.888954, 40.311977, - -3.517916, 40.643729 - ), - c("hospital", "dump", "pub"), - points_only = FALSE - ), "No results for query dump" - ) - - expect_s3_class(hosp, "sf") - expect_s3_class(hosp, "tbl") - expect_equal(nrow(hosp), 3) - expect_identical(as.character(hosp$query), c("hospital", "dump", "pub")) - expect_identical(sf::st_is_empty(hosp), c(FALSE, TRUE, FALSE)) -}) - - -test_that("Checking query", { - skip_on_cran() - skip_if_api_server() - skip_if_offline() - - - expect_message(obj <- geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - c("pub", "restaurant"), - limit = 51 - ), "50 results") - - - expect_identical(names(obj), c("query", "address", "geometry")) - expect_s3_class(obj, "sf") - expect_s3_class(obj, "tbl") - - obj <- geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - full_results = FALSE, - return_addresses = FALSE - ) - expect_identical(names(obj), c("query", "geometry")) - expect_s3_class(obj, "sf") - expect_s3_class(obj, "tbl") - - obj <- geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - full_results = FALSE, - return_addresses = TRUE - ) - - expect_identical(names(obj), c("query", "address", "geometry")) - expect_s3_class(obj, "sf") - expect_s3_class(obj, "tbl") - - obj <- geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - full_results = TRUE, - return_addresses = FALSE - ) - - expect_identical(names(obj)[1:2], c("query", "address")) - expect_gt(ncol(obj), 3) - expect_s3_class(obj, "sf") - expect_s3_class(obj, "tbl") - expect_identical(attributes(obj)$sf_column, "geometry") - - expect_gt(nrow(geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - limit = 10, - custom_query = list(countrycode = "es") - )), 4) - - - expect_equal(nrow(geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - custom_query = list(countrycode = "es") - )), 1) - - expect_equal(nrow(geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - custom_query = list(extratags = 1) - )), 1) - - expect_lt(nrow(geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - "pub", - limit = 1, - strict = TRUE - )), 2) -}) - - -test_that("Dedupe", { - skip_on_cran() - skip_if_api_server() - skip_if_offline() - - # Dupes - dup <- geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - rep(c("pub", "restaurant"), 50), - limit = 1 - ) - - expect_s3_class(dup, "sf") - expect_s3_class(dup, "tbl") - - expect_equal(nrow(dup), 100) - expect_equal(as.character(dup$query), rep(c("pub", "restaurant"), 50)) - - # Check deduping - dedup <- dplyr::distinct(dup) - - expect_equal(nrow(dedup), 2) - expect_equal(as.character(dedup$query), rep(c("pub", "restaurant"), 1)) -}) - - -test_that("Verify names", { - skip_on_cran() - skip_if_api_server() - skip_if_offline() - - # Ok - several <- geo_amenity_sf( - bbox = c(-1.1446, 41.5022, -0.4854, 41.8795), - c("pub", "restaurant"), - limit = 20, - full_results = TRUE - ) - - expect_identical(names(several), unique(names(several))) - - # Do I have dups by any chance? - expect_false(any(grepl("\\.[0-9]$", names(several)))) + expect_snapshot(geo_amenity_sf(), error = TRUE) }) diff --git a/tests/testthat/test-geo_lite.R b/tests/testthat/test-geo_lite.R index de3f7de9..473f360f 100644 --- a/tests/testthat/test-geo_lite.R +++ b/tests/testthat/test-geo_lite.R @@ -116,6 +116,7 @@ test_that("Dedupe", { expect_silent( dup <- geo_lite(rep(c("Pentagon", "Barcelona"), 50), limit = 1, + progressbar = FALSE, verbose = FALSE ) ) @@ -129,3 +130,19 @@ test_that("Dedupe", { expect_equal(nrow(dedup), 2) expect_equal(as.character(dedup$query), rep(c("Pentagon", "Barcelona"), 1)) }) + + +test_that("Progress bar", { + skip_on_cran() + skip_if_api_server() + skip_if_offline() + # No pbar + expect_silent(geo_lite("Madrid")) + expect_silent(geo_lite("Madrid", progressbar = TRUE)) + + # Get a pbar + expect_output(aa <- geo_lite(c("Madrid", "Barcelona")), "1/2") + + # Not + expect_silent(aa <- geo_lite(c("Madrid", "Barcelona"), progressbar = FALSE)) +}) diff --git a/tests/testthat/test-geo_lite_sf.R b/tests/testthat/test-geo_lite_sf.R index 0ee7b23b..872a7e68 100644 --- a/tests/testthat/test-geo_lite_sf.R +++ b/tests/testthat/test-geo_lite_sf.R @@ -155,3 +155,20 @@ test_that("Verify names", { # Do I have dups by any chance? expect_false(any(grepl("\\.[0-9]$", names(several)))) }) + +test_that("Progress bar", { + skip_on_cran() + skip_if_api_server() + skip_if_offline() + # No pbar + expect_silent(geo_lite_sf("Madrid")) + expect_silent(geo_lite_sf("Madrid", progressbar = TRUE)) + + # Get a pbar + expect_output(aa <- geo_lite_sf(c("Madrid", "Barcelona")), "1/2") + + # Not + expect_silent( + aa <- geo_lite_sf(c("Madrid", "Barcelona"), progressbar = FALSE) + ) +}) diff --git a/tests/testthat/test-reverse_geo_lite.R b/tests/testthat/test-reverse_geo_lite.R index ca091a1e..d728d6ae 100644 --- a/tests/testthat/test-reverse_geo_lite.R +++ b/tests/testthat/test-reverse_geo_lite.R @@ -195,7 +195,7 @@ test_that("Dedupe", { lats <- rep(c(40.75728, 55.95335), 50) longs <- rep(c(-73.98586, -3.188375), 50) - expect_silent(dup <- reverse_geo_lite(lats, longs)) + expect_silent(dup <- reverse_geo_lite(lats, longs, progressbar = FALSE)) expect_equal(nrow(dup), 100) @@ -209,3 +209,22 @@ test_that("Dedupe", { expect_equal(nrow(dedup), 2) expect_equal(as.character(dedup$address), nms) }) + +test_that("Progress bar", { + skip_on_cran() + skip_if_api_server() + skip_if_offline() + + lat <- c(40.75728, 55.95335) + long <- c(-73.98586, -3.188375) + + # No pbar + expect_silent(reverse_geo_lite(lat[1], long[1])) + expect_silent(reverse_geo_lite(lat[1], long[1], progressbar = TRUE)) + + # Get a pbar + expect_output(aa <- reverse_geo_lite(lat, long), "1/2") + + # Not + expect_silent(aa <- reverse_geo_lite(lat, long, progressbar = FALSE)) +}) diff --git a/tests/testthat/test-reverse_geo_lite_sf.R b/tests/testthat/test-reverse_geo_lite_sf.R index afee89a1..843bcb54 100644 --- a/tests/testthat/test-reverse_geo_lite_sf.R +++ b/tests/testthat/test-reverse_geo_lite_sf.R @@ -214,7 +214,7 @@ test_that("Dedupe", { lats <- rep(c(40.75728, 55.95335), 50) longs <- rep(c(-73.98586, -3.188375), 50) - expect_silent(dup <- reverse_geo_lite_sf(lats, longs)) + expect_silent(dup <- reverse_geo_lite_sf(lats, longs, progressbar = FALSE)) expect_s3_class(dup, "sf") expect_s3_class(dup, "tbl") @@ -230,3 +230,22 @@ test_that("Dedupe", { expect_equal(nrow(dedup), 2) expect_equal(as.character(dedup$address), nms) }) + +test_that("Progress bar", { + skip_on_cran() + skip_if_api_server() + skip_if_offline() + + lat <- c(40.75728, 55.95335) + long <- c(-73.98586, -3.188375) + + # No pbar + expect_silent(reverse_geo_lite_sf(lat[1], long[1])) + expect_silent(reverse_geo_lite_sf(lat[1], long[1], progressbar = TRUE)) + + # Get a pbar + expect_output(aa <- reverse_geo_lite_sf(lat, long), "1/2") + + # Not + expect_silent(aa <- reverse_geo_lite_sf(lat, long, progressbar = FALSE)) +}) diff --git a/vignettes/nominatimlite.Rmd b/vignettes/nominatimlite.Rmd index 338712ef..9255e4cc 100644 --- a/vignettes/nominatimlite.Rmd +++ b/vignettes/nominatimlite.Rmd @@ -1,155 +1,157 @@ ---- -title: "Get started with nominatimlite" -output: rmarkdown::html_vignette -desc: > - Quick examples showing what `nominatimlite` can do for you. -vignette: > - %\VignetteIndexEntry{Get started with nominatimlite} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} -bibliography: references.bib -link-citations: true ---- - - - - - -The goal of `nominatimlite` is to provide a light interface for geocoding -addresses, based on the [Nominatim -API](https://nominatim.org/release-docs/latest/). **Nominatim** is a tool to -search [OpenStreetMap](https://www.openstreetmap.org/) data by name and address -([geocoding](https://wiki.openstreetmap.org/wiki/Geocoding "Geocoding")) and to -generate synthetic addresses of OSM points (reverse geocoding). - -It also allows to load spatial objects using the `sf` package. - -Full site with examples and vignettes on - - -## Why `nominatimlite`? - -The main goal of `nominatimlite` is to access the Nominatim API avoiding the -dependency on `curl`. In some situations, `curl` may not be available or -accessible, so `nominatimlite` uses base functions to overcome this limitation. - -## Recommended packages - -There are other packages much more complete and mature than `nominatimlite`, -that presents similar features: - -- [`tidygeocoder`](https://jessecambon.github.io/tidygeocoder/) - [@R-tidygeocoder]. Allows to interface with Nominatim, Google, TomTom, - Mapbox, etc. for geocoding and reverse geocoding. -- [`osmdata`](https://docs.ropensci.org/osmdata/) [@R-osmdata]. Great for - downloading spatial data from OpenStreetMap, via the [Overpass - API](https://wiki.openstreetmap.org/wiki/Overpass_API). - -## Usage - -### `sf` objects - -With `nominatimlite` you can extract spatial objects easily: - - -```r -library(nominatimlite) - -# Extract some points - Pizza Hut in California - -CA <- geo_lite_sf("California", points_only = FALSE) - -pizzahut <- geo_lite_sf("Pizza Hut, California", - limit = 50, - custom_query = list(countrycodes = "us") -) - -library(ggplot2) - -ggplot(CA) + - geom_sf() + - geom_sf(data = pizzahut, col = "red") -``` - -![Pizza Hut in California](../man/figures/README-pizzahut-1.png){width="100%"} - -You can also extract polygon and line objects (if available) using the option -`points_only = FALSE`: - - -```r -sol_poly <- geo_lite_sf("Statue of Liberty, NY, USA", points_only = FALSE) - -ggplot(sol_poly) + - geom_sf() -``` - -![The Statue of -Liberty](../man/figures/README-statue_liberty-1.png){width="100%"} - -### Geocoding and reverse geocoding - -*Note: examples adapted from `tidygeocoder` package* - -In this first example we will geocode a few addresses using the `geo_lite()` -function: - - -```r -library(tibble) - -# create a dataframe with addresses -some_addresses <- tribble( - ~name, ~addr, - "White House", "1600 Pennsylvania Ave NW, Washington, DC", - "Transamerica Pyramid", "600 Montgomery St, San Francisco, CA 94111", - "Willis Tower", "233 S Wacker Dr, Chicago, IL 60606" -) - -# geocode the addresses -lat_longs <- geo_lite(some_addresses$addr, lat = "latitude", long = "longitude") -``` - -Only latitude and longitude are returned from the geocoder service in this -example, but `full_results = TRUE` can be used to return all of the data from -the geocoder service. - - - -|query | latitude| longitude|address | -|:------------------------------------------|--------:|----------:|:-----------------------------------------------------------------------------------------------------------------| -|1600 Pennsylvania Ave NW, Washington, DC | 38.89770| -77.03655|White House, 1600, Pennsylvania Avenue Northwest, Ward 2, Washington, District of Columbia, 20500, United States | -|600 Montgomery St, San Francisco, CA 94111 | 37.79520| -122.40279|Transamerica Pyramid, 600, Montgomery Street, Financial District, San Francisco, California, 94111, United States | -|233 S Wacker Dr, Chicago, IL 60606 | 41.87874| -87.63596|Willis Tower, 233, South Wacker Drive, Printer's Row, Loop, Chicago, Cook County, Illinois, 60606, United States | - - - -To perform reverse geocoding (obtaining addresses from geographic coordinates), -we can use the `reverse_geo_lite()` function. The arguments are similar to the -`geo_lite()` function, but now we specify the input data columns with the `lat` -and `long` arguments. The dataset used here is from the geocoder query above. -The single line address is returned in a column named by the `address`. - - -```r -reverse <- reverse_geo_lite( - lat = lat_longs$latitude, long = lat_longs$longitude, - address = "address_found" -) -``` - - - -|address_found | lat| lon| -|:-----------------------------------------------------------------------------------------------------------------|--------:|----------:| -|White House, 1600, Pennsylvania Avenue Northwest, Ward 2, Washington, District of Columbia, 20500, United States | 38.89770| -77.03655| -|Transamerica Pyramid, 600, Montgomery Street, Financial District, San Francisco, California, 94111, United States | 37.79520| -122.40279| -|Willis Tower, 233, South Wacker Drive, Printer's Row, Loop, Chicago, Cook County, Illinois, 60606, United States | 41.87874| -87.63596| - - - -For more advance users, see [Nominatim -docs](https://nominatim.org/release-docs/latest/api/Search/) to check the -parameters available. - -## References +--- +title: "Get started with nominatimlite" +output: rmarkdown::html_vignette +desc: > + Quick examples showing what `nominatimlite` can do for you. +vignette: > + %\VignetteIndexEntry{Get started with nominatimlite} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +bibliography: references.bib +link-citations: true +--- + + + + + +The goal of `nominatimlite` is to provide a light interface for geocoding +addresses, based on the [Nominatim +API](https://nominatim.org/release-docs/latest/). **Nominatim** is a tool to +search [OpenStreetMap](https://www.openstreetmap.org/) data by name and address +([geocoding](https://wiki.openstreetmap.org/wiki/Geocoding "Geocoding")) and to +generate synthetic addresses of OSM points (reverse geocoding). + +It also allows to load spatial objects using the `sf` package. + +Full site with examples and vignettes on + + +## Why `nominatimlite`? + +The main goal of `nominatimlite` is to access the Nominatim API avoiding the +dependency on `curl`. In some situations, `curl` may not be available or +accessible, so `nominatimlite` uses base functions to overcome this limitation. + +## Recommended packages + +There are other packages much more complete and mature than `nominatimlite`, +that presents similar features: + +- [`tidygeocoder`](https://jessecambon.github.io/tidygeocoder/) + [@R-tidygeocoder]. Allows to interface with Nominatim, Google, TomTom, + Mapbox, etc. for geocoding and reverse geocoding. +- [`osmdata`](https://docs.ropensci.org/osmdata/) [@R-osmdata]. Great for + downloading spatial data from OpenStreetMap, via the [Overpass + API](https://wiki.openstreetmap.org/wiki/Overpass_API). + +## Usage + +### `sf` objects + +With `nominatimlite` you can extract spatial objects easily: + + +```r +library(nominatimlite) + +# Extract some points - Pizza Hut in California + +CA <- geo_lite_sf("California", points_only = FALSE) + +pizzahut <- geo_lite_sf("Pizza Hut, California", + limit = 50, + custom_query = list(countrycodes = "us") +) + +library(ggplot2) + +ggplot(CA) + + geom_sf() + + geom_sf(data = pizzahut, col = "red") +``` + +![Pizza Hut in California](../man/figures/README-pizzahut-1.png){width="100%"} + +You can also extract polygon and line objects (if available) using the option +`points_only = FALSE`: + + +```r +sol_poly <- geo_lite_sf("Statue of Liberty, NY, USA", points_only = FALSE) + +ggplot(sol_poly) + + geom_sf() +``` + +![The Statue of +Liberty](../man/figures/README-statue_liberty-1.png){width="100%"} + +### Geocoding and reverse geocoding + +*Note: examples adapted from `tidygeocoder` package* + +In this first example we will geocode a few addresses using the `geo_lite()` +function: + + +```r +library(tibble) + +# create a dataframe with addresses +some_addresses <- tribble( + ~name, ~addr, + "White House", "1600 Pennsylvania Ave NW, Washington, DC", + "Transamerica Pyramid", "600 Montgomery St, San Francisco, CA 94111", + "Willis Tower", "233 S Wacker Dr, Chicago, IL 60606" +) + +# geocode the addresses +lat_longs <- geo_lite(some_addresses$addr, lat = "latitude", long = "longitude") +#> | | | 0% | |================= | 33% (1/3) | |================================= | 67% (2/3) | |==================================================| 100% (3/3) +``` + +Only latitude and longitude are returned from the geocoder service in this +example, but `full_results = TRUE` can be used to return all of the data from +the geocoder service. + + + +|query | latitude| longitude|address | +|:------------------------------------------|--------:|----------:|:-----------------------------------------------------------------------------------------------------------------| +|1600 Pennsylvania Ave NW, Washington, DC | 38.89770| -77.03655|White House, 1600, Pennsylvania Avenue Northwest, Ward 2, Washington, District of Columbia, 20500, United States | +|600 Montgomery St, San Francisco, CA 94111 | 37.79520| -122.40279|Transamerica Pyramid, 600, Montgomery Street, Financial District, San Francisco, California, 94111, United States | +|233 S Wacker Dr, Chicago, IL 60606 | 41.87874| -87.63596|Willis Tower, 233, South Wacker Drive, Printer's Row, Loop, Chicago, Cook County, Illinois, 60606, United States | + + + +To perform reverse geocoding (obtaining addresses from geographic coordinates), +we can use the `reverse_geo_lite()` function. The arguments are similar to the +`geo_lite()` function, but now we specify the input data columns with the `lat` +and `long` arguments. The dataset used here is from the geocoder query above. +The single line address is returned in a column named by the `address`. + + +```r +reverse <- reverse_geo_lite( + lat = lat_longs$latitude, long = lat_longs$longitude, + address = "address_found" +) +#> | | | 0% | |================= | 33% (1/3) | |================================= | 67% (2/3) | |==================================================| 100% (3/3) +``` + + + +|address_found | lat| lon| +|:-----------------------------------------------------------------------------------------------------------------|--------:|----------:| +|White House, 1600, Pennsylvania Avenue Northwest, Ward 2, Washington, District of Columbia, 20500, United States | 38.89770| -77.03655| +|Transamerica Pyramid, 600, Montgomery Street, Financial District, San Francisco, California, 94111, United States | 37.79520| -122.40279| +|Willis Tower, 233, South Wacker Drive, Printer's Row, Loop, Chicago, Cook County, Illinois, 60606, United States | 41.87874| -87.63596| + + + +For more advance users, see [Nominatim +docs](https://nominatim.org/release-docs/latest/api/Search/) to check the +parameters available. + +## References