├── vignettes
├── .gitignore
└── ohsome.Rmd
├── tests
├── testthat
│ ├── setup.R
│ ├── data
│ │ ├── elements-count-buildings-csv.rds
│ │ ├── elements-centroid-shop-convenience-bcircles.rds
│ │ ├── elements-count-shop-convenience-bcircles-csv.rds
│ │ ├── elements-fullHistory-geometry-id-way-625011340.rds
│ │ ├── elements-geometry-amenity-hospitals-Germany-content.rds
│ │ └── elements-count-buildings-groupby-boundary-groupby-tag-csv.rds
│ ├── test-set_boundary.R
│ ├── mock_api
│ │ ├── 200
│ │ │ └── api.ohsome.org
│ │ │ │ └── v1
│ │ │ │ ├── elements
│ │ │ │ └── count-754ee5-POST.csv
│ │ │ │ └── metadata.json
│ │ └── 404
│ │ │ └── api.ohsome.org
│ │ │ └── v1
│ │ │ ├── metadata.R
│ │ │ └── elements
│ │ │ └── amount-754ee5-POST.R
│ ├── test-ohsome_extract_elements.R
│ ├── test-ohsome_users_count.R
│ ├── test-ohsome_aggregate_elements.R
│ ├── test-ohsome_extract_elementsFullHistory.R
│ ├── test-ohsome_extract_contributions.R
│ ├── test-ohsome_contributions_count.R
│ ├── test-ohsome_get_metadata.R
│ ├── test-ohsome_post.R
│ ├── test-ohsome_query.R
│ ├── test-set_endpoint.R
│ ├── test-set_parameters.R
│ ├── test-ohsome_boundary.R
│ ├── test-ohsome_parse.R
│ └── test-validate.R
├── testthat.R
└── spelling.R
├── data
├── ohsome_api_url.rda
└── ohsome_endpoints.rda
├── man
├── figures
│ ├── README-density-1.png
│ ├── README-buildings-1.png
│ ├── README-building_levels-1.png
│ └── README-contribution_extraction-1.png
├── ohsome_endpoints.Rd
├── ohsome_temporalExtent.Rd
├── ohsome_api_url.Rd
├── ohsome_metadata.Rd
├── ohsome_get_metadata.Rd
├── ohsome_post.Rd
├── ohsome_parse.Rd
├── set_boundary.Rd
├── ohsome_contributions_count.Rd
├── set_endpoint.Rd
├── ohsome_boundary.Rd
├── set_parameters.Rd
├── ohsome_query.Rd
├── ohsome_users_count.Rd
├── ohsome_extract_elements.Rd
├── ohsome_extract_elementsFullHistory.Rd
├── ohsome_extract_contributions.Rd
└── ohsome_aggregate_elements.Rd
├── .gitignore
├── data-raw
├── ohsome_api_url.R
└── ohsome_endpoints.R
├── .Rbuildignore
├── inst
├── WORDLIST
└── CITATION
├── R
├── zzz.R
├── ohsome_users_count.R
├── set_boundary.R
├── data.R
├── ohsome_contributions_count.R
├── ohsome_get_metadata.R
├── ohsome_extract_elementsFullHistory.R
├── utils.R
├── ohsome_post.R
├── ohsome_extract_elements.R
├── ohsome_extract_contributions.R
├── set_endpoint.R
├── ohsome_query.R
├── ohsome_aggregate_elements.R
├── set_parameters.R
├── ohsome_parse.R
├── validate.R
└── ohsome_boundary.R
├── cran-comments.md
├── NAMESPACE
├── DESCRIPTION
├── NEWS.md
├── LICENSE.md
└── CITATION.cff
/vignettes/.gitignore:
--------------------------------------------------------------------------------
1 | *.html
2 | *.R
3 |
--------------------------------------------------------------------------------
/tests/testthat/setup.R:
--------------------------------------------------------------------------------
1 | library(httptest)
2 |
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(ohsome)
3 |
4 | test_check("ohsome")
5 |
--------------------------------------------------------------------------------
/data/ohsome_api_url.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/data/ohsome_api_url.rda
--------------------------------------------------------------------------------
/data/ohsome_endpoints.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/data/ohsome_endpoints.rda
--------------------------------------------------------------------------------
/man/figures/README-density-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/man/figures/README-density-1.png
--------------------------------------------------------------------------------
/man/figures/README-buildings-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/man/figures/README-buildings-1.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 | .Rdata
4 | .httr-oauth
5 | .DS_Store
6 | *.Rproj
7 | inst/doc
8 | /doc/
9 | /Meta/
10 |
--------------------------------------------------------------------------------
/man/figures/README-building_levels-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/man/figures/README-building_levels-1.png
--------------------------------------------------------------------------------
/man/figures/README-contribution_extraction-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/man/figures/README-contribution_extraction-1.png
--------------------------------------------------------------------------------
/tests/testthat/data/elements-count-buildings-csv.rds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/tests/testthat/data/elements-count-buildings-csv.rds
--------------------------------------------------------------------------------
/tests/testthat/data/elements-centroid-shop-convenience-bcircles.rds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/tests/testthat/data/elements-centroid-shop-convenience-bcircles.rds
--------------------------------------------------------------------------------
/tests/spelling.R:
--------------------------------------------------------------------------------
1 | if(requireNamespace('spelling', quietly = TRUE))
2 | spelling::spell_check_test(vignettes = TRUE, error = FALSE,
3 | skip_on_cran = TRUE)
4 |
--------------------------------------------------------------------------------
/tests/testthat/data/elements-count-shop-convenience-bcircles-csv.rds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/tests/testthat/data/elements-count-shop-convenience-bcircles-csv.rds
--------------------------------------------------------------------------------
/tests/testthat/data/elements-fullHistory-geometry-id-way-625011340.rds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/tests/testthat/data/elements-fullHistory-geometry-id-way-625011340.rds
--------------------------------------------------------------------------------
/data-raw/ohsome_api_url.R:
--------------------------------------------------------------------------------
1 | require(usethis)
2 |
3 | ohsome_api_url <- list(
4 | base = "https://api.ohsome.org",
5 | version = "v1"
6 | )
7 |
8 | usethis::use_data(ohsome_api_url, overwrite = TRUE)
9 |
--------------------------------------------------------------------------------
/tests/testthat/data/elements-geometry-amenity-hospitals-Germany-content.rds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/tests/testthat/data/elements-geometry-amenity-hospitals-Germany-content.rds
--------------------------------------------------------------------------------
/tests/testthat/data/elements-count-buildings-groupby-boundary-groupby-tag-csv.rds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GIScience/ohsome-r/HEAD/tests/testthat/data/elements-count-buildings-groupby-boundary-groupby-tag-csv.rds
--------------------------------------------------------------------------------
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^ohsome\.Rproj$
2 | ^\.Rproj\.user$
3 | ^README\.Rmd$
4 | ^data-raw$
5 | ^LICENSE\.md$
6 | ^CITATION\.cff$
7 | ^ohsome-r\.Rproj$
8 | ^doc$
9 | ^Meta$
10 | ^cran-comments\.md$
11 | ^CRAN-SUBMISSION$
12 |
--------------------------------------------------------------------------------
/tests/testthat/test-set_boundary.R:
--------------------------------------------------------------------------------
1 | test_that("removes bcircles parameter when setting new bboxes parameter", {
2 |
3 | q1 <- ohsome_elements_count("8,49,1000")
4 | q2 <- set_boundary(q1, "8,49,9,50")
5 | expect_null(q2$body$bcircles)
6 | })
7 |
--------------------------------------------------------------------------------
/tests/testthat/mock_api/200/api.ohsome.org/v1/elements/count-754ee5-POST.csv:
--------------------------------------------------------------------------------
1 | # Copyright URL: https://ohsome.org/copyrights
2 | # Copyright Text: © OpenStreetMap contributors
3 | # API Version: 1.6.0
4 | timestamp;value
5 | "2021-08-29T20:00:00Z";"24.0"
6 |
--------------------------------------------------------------------------------
/man/ohsome_endpoints.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{ohsome_endpoints}
5 | \alias{ohsome_endpoints}
6 | \title{ohsome API endpoints}
7 | \format{
8 | A list of ohsome API endpoints.
9 | }
10 | \description{
11 | Available ohsome API endpoints with their parameters
12 | }
13 |
--------------------------------------------------------------------------------
/man/ohsome_temporalExtent.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{ohsome_temporalExtent}
5 | \alias{ohsome_temporalExtent}
6 | \title{ohsome API temporal extent}
7 | \format{
8 | A vector of POSIXct
9 | }
10 | \description{
11 | Temporal extent of the OSM data in the underlying OSHDB
12 | }
13 |
--------------------------------------------------------------------------------
/man/ohsome_api_url.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{ohsome_api_url}
5 | \alias{ohsome_api_url}
6 | \title{ohsome API URL}
7 | \format{
8 | A list:
9 | \itemize{
10 | \item \code{base}: character; base URL
11 | \item \code{version}: character; path to current major API version
12 | }
13 | }
14 | \description{
15 | The base URL of the ohsome API with path to current major
16 | version.
17 | }
18 |
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_extract_elements.R:
--------------------------------------------------------------------------------
1 | test_that("creates ohsome_query object with the correct endpoint", {
2 | q <- ohsome_elements_geometry()
3 | expect_equal(httr::parse_url(q$url)$path, "v1/elements/geometry")
4 | })
5 |
6 | test_that("returns object of class ohsome_query", {
7 | expect_s3_class(ohsome_extract_elements(), "ohsome_query")
8 | })
9 |
10 | test_that("correctly sets clipGeometry parameter", {
11 | q <- ohsome_elements_geometry(clipGeometry = FALSE)
12 | expect_equal(q$body$clipGeometry, "FALSE")
13 | })
14 |
--------------------------------------------------------------------------------
/inst/WORDLIST:
--------------------------------------------------------------------------------
1 | API's
2 | API’s
3 | CRS
4 | FeatureCollection
5 | FeatureCollections
6 | Franconia
7 | GeoJSON
8 | JSON
9 | MultiPolygons
10 | Neukölln
11 | Nominatim
12 | OSHDB
13 | OSM
14 | OpenStreetMap
15 | POSIXct
16 | URIs
17 | WGS
18 | bboxes
19 | bcircles
20 | bpolys
21 | centroids
22 | changeset
23 | choropleth
24 | coercible
25 | contributionTypes
26 | dplyr
27 | elementsFullHistory
28 | geodata
29 | mapview
30 | nominatimlite
31 | rgeoboundaries
32 | rnaturalearth
33 | sfc
34 | tidyr
35 | timeframe
36 | timespan
37 | timestring
38 | ’s
39 | ️
40 |
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_users_count.R:
--------------------------------------------------------------------------------
1 | test_that("creates ohsome_query object with the correct endpoint", {
2 | q <- ohsome_users_count()
3 | expect_equal(httr::parse_url(q$url)$path, "v1/users/count")
4 | })
5 |
6 | test_that("returns object of class ohsome_query", {
7 | expect_s3_class(ohsome_users_count(), "ohsome_query")
8 | })
9 |
10 | test_that("correctly sets density endpoint on return_value arg", {
11 | q <- ohsome_users_count(return_value = "density")
12 | expect_equal(httr::parse_url(q$url)$path, "v1/users/count/density")
13 | })
14 |
15 |
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_aggregate_elements.R:
--------------------------------------------------------------------------------
1 | q <- ohsome_elements_count("0,0,1000")
2 |
3 | test_that("creates ohsome_query object with the correct endpoint", {
4 | expect_equal(httr::parse_url(q$url)$path, "v1/elements/count")
5 | })
6 |
7 | test_that("returns object of class ohsome_query", {
8 | expect_s3_class(q, "ohsome_query")
9 | })
10 |
11 | test_that("correctly sets ratio endpoint on return_value arg", {
12 | q <- ohsome_elements_length(return_value = "ratio")
13 | expect_equal(httr::parse_url(q$url)$path, "v1/elements/length/ratio")
14 | })
15 |
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_extract_elementsFullHistory.R:
--------------------------------------------------------------------------------
1 | test_that("creates ohsome_query object with the correct endpoint", {
2 | q <- ohsome_elementsFullHistory_geometry(time = "2010,2020")
3 | expect_equal(httr::parse_url(q$url)$path, "v1/elementsFullHistory/geometry")
4 | })
5 |
6 | test_that("returns object of class ohsome_query", {
7 | expect_s3_class(ohsome_extract_elementsFullHistory(time = "2010,2020"), "ohsome_query")
8 | })
9 |
10 | test_that("correctly sets clipGeometry parameter", {
11 | q <- ohsome_elementsFullHistory_geometry(time = "2010,2020", clipGeometry = FALSE)
12 | expect_equal(q$body$clipGeometry, "FALSE")
13 | })
14 |
--------------------------------------------------------------------------------
/tests/testthat/mock_api/200/api.ohsome.org/v1/metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "attribution": {
3 | "url": "https://ohsome.org/copyrights",
4 | "text": "© OpenStreetMap contributors"
5 | },
6 | "apiVersion": "1.8.0-RC1",
7 | "timeout": 600.0,
8 | "extractRegion": {
9 | "spatialExtent": {
10 | "type": "Polygon",
11 | "coordinates": [
12 | [
13 | [
14 | -180.0,
15 | -90.0
16 | ],
17 | [
18 | 180.0,
19 | -90.0
20 | ],
21 | [
22 | 180.0,
23 | 90.0
24 | ],
25 | [
26 | -180.0,
27 | 90.0
28 | ],
29 | [
30 | -180.0,
31 | -90.0
32 | ]
33 | ]
34 | ]
35 | },
36 | "temporalExtent": {
37 | "fromTimestamp": "2007-10-08T00:00:00Z",
38 | "toTimestamp": "2021-06-06T20:00Z"
39 | },
40 | "replicationSequenceNumber": 76549
41 | }
42 | }
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_extract_contributions.R:
--------------------------------------------------------------------------------
1 | test_that("creates ohsome_query object with the correct endpoint", {
2 | q <- ohsome_contributions_geometry()
3 | expect_equal(httr::parse_url(q$url)$path, "v1/contributions/geometry")
4 | })
5 |
6 | test_that("correctly modifies endpoint when latest = TRUE", {
7 | q <- ohsome_contributions_geometry(latest = TRUE)
8 | expect_equal(httr::parse_url(q$url)$path, "v1/contributions/latest/geometry")
9 | })
10 |
11 | test_that("returns object of class ohsome_query", {
12 | expect_s3_class(ohsome_extract_contributions(), "ohsome_query")
13 | })
14 |
15 | test_that("correctly sets clipGeometry parameter", {
16 | q <- ohsome_contributions_geometry(clipGeometry = FALSE)
17 | expect_equal(q$body$clipGeometry, "FALSE")
18 | })
19 |
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_contributions_count.R:
--------------------------------------------------------------------------------
1 | test_that("creates ohsome_query object with the correct endpoint", {
2 | q <- ohsome_contributions_count()
3 | expect_equal(httr::parse_url(q$url)$path, "v1/contributions/count")
4 | })
5 |
6 | test_that("returns object of class ohsome_query", {
7 | expect_s3_class(ohsome_contributions_count(), "ohsome_query")
8 | })
9 |
10 | test_that("correctly sets density endpoint on return_value arg", {
11 | q <- ohsome_contributions_count(return_value = "density")
12 | expect_equal(httr::parse_url(q$url)$path, "v1/contributions/count/density")
13 | })
14 |
15 | test_that("correctly modifies endpoint when latest = TRUE", {
16 | q <- ohsome_contributions_count(latest = TRUE)
17 | expect_equal(httr::parse_url(q$url)$path, "v1/contributions/latest/count")
18 | })
--------------------------------------------------------------------------------
/R/zzz.R:
--------------------------------------------------------------------------------
1 | # Upon attaching package, request ohsome API metadata and assign to ohsome_metadata
2 | .onLoad <- function(libname, pkgname) {
3 | tryCatch({
4 | ohsome_metadata <- ohsome_get_metadata(quiet = TRUE)
5 | assign(
6 | "ohsome_metadata",
7 | ohsome_metadata,
8 | envir = parent.env(environment())
9 | )
10 | assign(
11 | "ohsome_temporalExtent",
12 | ohsome_metadata$extractRegion$temporalExtent,
13 | envir = parent.env(environment())
14 | )
15 | },
16 | error = function(e) return(TRUE)
17 | )
18 | }
19 |
20 | .onAttach <- function(libname, pkgname) {
21 | if(exists("ohsome_metadata", where = parent.env(environment()))) {
22 | packageStartupMessage(create_metadata_message(ohsome_metadata))
23 | } else {
24 | packageStartupMessage(
25 | "Could not retrieve metadata from ohsome API.",
26 | "\nPlease check your internet connection and try to run ",
27 | "ohsome_get_metadata()"
28 | )
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/data-raw/ohsome_endpoints.R:
--------------------------------------------------------------------------------
1 | library(httr)
2 | library(rapiclient)
3 | library(data.table)
4 |
5 | extract_endpoint <- function(endpoint, paths) {
6 |
7 | params <- rbindlist(paths[[endpoint]]$post$parameters, fill = TRUE)
8 | deprecated <- grepl("deprecated", params$description)
9 |
10 | invisible(list(
11 | summary = paths[[endpoint]]$post$summary,
12 | produces = paths[[endpoint]]$post$produces,
13 | parameters = as.data.frame(
14 | params[!deprecated, c("name", "description", "required")]
15 | )
16 | ))
17 | }
18 |
19 | extract_spec <- function(spec) {
20 | api <- "https://api.ohsome.org/stable/docs" |>
21 | modify_url(query = spec) |>
22 | get_api()
23 |
24 | paths <- api$paths
25 | endpoints <- names(paths)
26 |
27 | out <- lapply(endpoints, extract_endpoint, paths = paths)
28 | names(out) <- sub("^/", "", endpoints)
29 | invisible(out)
30 | }
31 |
32 | specs <- c("group=Data%20Aggregation", "group=Data%20Extraction")
33 | ohsome_endpoints <- unlist(lapply(specs, extract_spec), recursive = FALSE)
34 |
35 | usethis::use_data(ohsome_endpoints, overwrite = TRUE)
36 |
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_get_metadata.R:
--------------------------------------------------------------------------------
1 | with_mock_api({
2 |
3 | # mock response: tests/testthat/mock_api/200/api.ohsome.org/v1/metadata.json
4 | .mockPaths("./mock_api/200")
5 |
6 | test_that(
7 | "returns metadata", {
8 | meta <- ohsome_get_metadata(quiet = T)
9 | expect_equal(meta$apiVersion, "1.8.0-RC1")
10 | expect_type(meta, "list")
11 | expect_s3_class(meta, "ohsome_metadata")
12 | })
13 |
14 | test_that(
15 | "converts spatial extent", {
16 | meta <- ohsome_get_metadata(quiet = T)
17 | expect_s3_class(meta$extractRegion$spatialExtent, "sfc_POLYGON")
18 | expect_equal(
19 | sf::st_bbox(meta$extractRegion$spatialExtent),
20 | sf::st_bbox(
21 | obj = c(xmin = -180, xmax = 180, ymax = 90, ymin = -90),
22 | crs = 4326
23 | )
24 | )
25 | })
26 |
27 | test_that(
28 | "message if quiet = F", {
29 | expect_message(ohsome_get_metadata(quiet = F))
30 | })
31 | })
32 |
33 |
34 | with_mock_api({
35 |
36 | # mock response: tests/testthat/mock_api/404/api.ohsome.org/v1/metadata.R
37 | .mockPaths("./mock_api/404")
38 |
39 | test_that(
40 | "throws error on API request fail", {
41 | expect_error(ohsome_get_metadata(quiet = T))
42 | })
43 | })
44 |
45 |
--------------------------------------------------------------------------------
/man/ohsome_metadata.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{ohsome_metadata}
5 | \alias{ohsome_metadata}
6 | \title{ohsome API metadata}
7 | \format{
8 | An \code{ohsome_metadata} object. This is a named list with the
9 | attributes \code{date}, \code{status_code} (of the GET request) and the following list
10 | elements:
11 | \itemize{
12 | \item \code{attribution}: character; \code{url} and \code{text} of OSM data copyrights and
13 | attribution
14 | \item \code{apiVersion}: numeric_version; Version of the ohsome API
15 | \item \code{timeout}: numeric; limit of the processing time in seconds
16 | \item \code{extractRegion}:
17 | \itemize{
18 | \item \code{spatialExtent}: sfc_POLYGON; spatial boundary of the OSM data in the
19 | underlying OSHDB
20 | \item \code{temporalExtent}: vector of POSIXct; timeframe of the OSM data in the
21 | underlying OSHDB data
22 | \item \code{replicationSequenceNumber}: numeric; precise state of the OSM data
23 | contained in the underlying OSHDB, expressed as the id of the last
24 | applied (hourly) diff file from \href{https://planet.openstreetmap.org}{Planet OSM}
25 | }
26 | }
27 | }
28 | \description{
29 | Metadata of the ohsome API that is requested on loading the
30 | package
31 | }
32 |
--------------------------------------------------------------------------------
/cran-comments.md:
--------------------------------------------------------------------------------
1 | ## Test environments
2 | - R-hub windows-x86_64-devel (r-devel)
3 | - R-hub ubuntu-gcc-release (r-release)
4 | - R-hub fedora-clang-devel (r-devel)
5 |
6 | ## R CMD check results
7 | ❯ On windows-x86_64-devel (r-devel)
8 | checking for non-standard things in the check directory ... NOTE
9 | Found the following files/directories:
10 | ''NULL''
11 |
12 | This seems to be an Rhub issue and can likely be ignored. See [R-hub issue #560](https://github.com/r-hub/rhub/issues/560)
13 |
14 | ❯ On windows-x86_64-devel (r-devel)
15 | checking for detritus in the temp directory ... NOTE
16 | Found the following files/directories:
17 | 'lastMiKTeXException'
18 |
19 | This seems to be an Rhub issue and can likely be ignored. See [R-hub issue #503](https://github.com/r-hub/rhub/issues/503)
20 |
21 |
22 | ❯ On fedora-clang-devel (r-devel), ubuntu-gcc-release (r-release)
23 | checking HTML version of manual ... NOTE
24 | Skipping checking HTML validation: no command 'tidy' found
25 |
26 | This seems to indicate that HTML validity checks were skipped due to missing
27 | 'tidy' in R-hub's environment. However, the package manual has passed
28 | HTML validity checks in the Windows environment. Thus, the note can
29 | probably be ignored.
30 |
31 | 0 errors ✔ | 0 warnings ✔ | 3 notes ✖
32 |
--------------------------------------------------------------------------------
/R/ohsome_users_count.R:
--------------------------------------------------------------------------------
1 | #' Count OSM users
2 | #'
3 | #' Create an `ohsome_query` object for OSM users count
4 | #'
5 | #' `ohsome_users_count()` creates an `ohsome_query` object for OSM users
6 | #' aggregation. Boundary objects are passed via [set_boundary()] into
7 | #' [ohsome_boundary()].
8 | #'
9 | #' @inherit ohsome_query params return
10 | #' @inheritParams ohsome_contributions_count
11 | #' @param return_value character; the value to be returned by the ohsome API:
12 | #' * `"absolute"` returns the absolute number of users. This is the
13 | #' default.
14 | #' * `"density"` returns the number of users per square kilometer.
15 | #' @seealso [ohsome API Endpoints -- Users Aggregation](https://docs.ohsome.org/ohsome-api/stable/endpoints.html#users-aggregation)
16 | #' @export
17 | #' @examples
18 | #' # Yearly count of users contributing to man-made objects around "Null Island"
19 | #' ohsome_users_count("0,0,10", filter = "man_made=*", time = "2012/2022/P1Y")
20 | #'
21 | ohsome_users_count <- function(
22 | boundary = NULL,
23 | return_value = c("absolute", "density"),
24 | grouping = NULL,
25 | time = NULL,
26 | ...
27 | ) {
28 | return_value <- match.arg(return_value)
29 | if(return_value == "absolute") return_value <- NULL
30 |
31 | q <- ohsome_query(c("users", "count", return_value), boundary, grouping,...)
32 | set_time(q, time)
33 | }
34 |
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_post.R:
--------------------------------------------------------------------------------
1 | with_mock_api({
2 |
3 | .mockPaths("./mock_api/200")
4 |
5 | # mock response: tests/testthat/mock_api/200/api.ohsome.org/v1/elements/count-754ee5-POST.csv
6 | test_that(
7 | "returns ohsome API response if parse = FALSE", {
8 |
9 | q <- ohsome_query(
10 | c("elements", "count"),
11 | filter = "shop=convenience",
12 | bcircles = "13.45,52.5,1000"
13 | )
14 |
15 | expect_s3_class(ohsome_post(q, parse = FALSE, validate = FALSE), "response")
16 | })
17 |
18 | test_that(
19 | "returns data.frame if parse = TRUE", {
20 |
21 | q <- ohsome_query(
22 | c("elements", "count"),
23 | filter = "shop=convenience",
24 | bcircles = "13.45,52.5,1000"
25 | )
26 |
27 | expect_s3_class(ohsome_post(q, parse = TRUE, validate = FALSE), "data.frame")
28 | })
29 | })
30 |
31 |
32 | with_mock_api({
33 |
34 | # mock response: tests/testthat/mock_api/404/api.ohsome.org/elements/amount-754ee5-POST.R
35 | .mockPaths("./mock_api/404")
36 |
37 | test_that(
38 | "throws error on API request fail", {
39 |
40 | q <- ohsome_query(
41 | c("elements", "amount"),
42 | filter = "shop=convenience",
43 | bcircles = "13.45,52.5,1000"
44 | )
45 |
46 | expect_error(ohsome_post(q, validate = FALSE))
47 | })
48 | })
49 |
50 | test_that("throws error on invalid queries by default (strict=TRUE)", {
51 | q <- ohsome_query("foo")
52 | expect_error(suppressWarnings(ohsome_post(q)))
53 | })
54 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | S3method(ohsome_boundary,bbox)
4 | S3method(ohsome_boundary,character)
5 | S3method(ohsome_boundary,list)
6 | S3method(ohsome_boundary,matrix)
7 | S3method(ohsome_boundary,ohsome_boundary)
8 | S3method(ohsome_boundary,sf)
9 | S3method(ohsome_boundary,sfc)
10 | S3method(ohsome_boundary,sfg)
11 | export(ohsome_aggregate_elements)
12 | export(ohsome_boundary)
13 | export(ohsome_contributions_bbox)
14 | export(ohsome_contributions_centroid)
15 | export(ohsome_contributions_count)
16 | export(ohsome_contributions_geometry)
17 | export(ohsome_df)
18 | export(ohsome_elementsFullHistory_bbox)
19 | export(ohsome_elementsFullHistory_centroid)
20 | export(ohsome_elementsFullHistory_geometry)
21 | export(ohsome_elements_area)
22 | export(ohsome_elements_bbox)
23 | export(ohsome_elements_centroid)
24 | export(ohsome_elements_count)
25 | export(ohsome_elements_geometry)
26 | export(ohsome_elements_length)
27 | export(ohsome_elements_perimeter)
28 | export(ohsome_extract_contributions)
29 | export(ohsome_extract_elements)
30 | export(ohsome_extract_elementsFullHistory)
31 | export(ohsome_get_metadata)
32 | export(ohsome_parse)
33 | export(ohsome_post)
34 | export(ohsome_query)
35 | export(ohsome_sf)
36 | export(ohsome_users_count)
37 | export(set_boundary)
38 | export(set_endpoint)
39 | export(set_filter)
40 | export(set_groupByKey)
41 | export(set_groupByKeys)
42 | export(set_groupByValues)
43 | export(set_grouping)
44 | export(set_parameters)
45 | export(set_properties)
46 | export(set_time)
47 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: ohsome
2 | Title: An 'ohsome API' Client
3 | Version: 0.2.2.9000
4 | Authors@R: c(
5 | person("Heidelberg Institute for Geoinformation Technology (HeiGIT) gGmbH", role = "cph"),
6 | person("Oliver", "Fritz", , "oliver.fritz@heigit.org", role = c("aut", "cre"),
7 | comment = c(ORCID = "0000-0001-6324-7295"))
8 | )
9 | Description: A client that grants access to the power of the 'ohsome API'
10 | from R. It lets you analyze the rich data source of the
11 | 'OpenStreetMap (OSM)' history. You can retrieve the geometry of 'OSM'
12 | data at specific points in time, and you can get aggregated statistics
13 | on the evolution of 'OSM' elements and specify your own temporal,
14 | spatial and/or thematic filters.
15 | License: LGPL (>= 3)
16 | URL:
17 | https://github.com/GIScience/ohsome-r,https://docs.ohsome.org/ohsome-api/stable/
18 | BugReports: https://github.com/GIScience/ohsome-r/issues
19 | Depends:
20 | R (>= 2.10)
21 | Imports:
22 | geojsonsf,
23 | httr,
24 | jsonlite,
25 | readr,
26 | sf,
27 | utils
28 | Suggests:
29 | dplyr,
30 | ggplot2,
31 | httptest,
32 | janitor,
33 | knitr,
34 | mapview,
35 | nominatimlite,
36 | osmdata,
37 | rmarkdown,
38 | spelling,
39 | testthat (>= 3.0.0),
40 | tmaptools,
41 | tidyr
42 | VignetteBuilder:
43 | knitr
44 | Config/testthat/edition: 3
45 | Encoding: UTF-8
46 | Language: en-US
47 | LazyData: true
48 | Roxygen: list(markdown = TRUE)
49 | RoxygenNote: 7.2.3
50 |
--------------------------------------------------------------------------------
/inst/CITATION:
--------------------------------------------------------------------------------
1 | bibentry(
2 | bibtype = "Misc",
3 | title = "OSHDB - OpenStreetMap History Data Analysis (0.7.2)",
4 | author = c(
5 | person(given = "Martin", family = "Raifer"),
6 | person(given = "Rafael", family = "Troilo"),
7 | person(given = "Franz-Benjamin", family = "Mocnik"),
8 | person(given = "Moritz", family = "Schott")
9 | ),
10 | month = "Sep",
11 | year = "2021",
12 | publisher = "Zenodo",
13 | version = "0.7.2",
14 | doi = "10.5281/zenodo.5512545",
15 | header = "When using the OSHDB indirectly through ohsome for a publication, please cite it as:"
16 | )
17 |
18 | bibentry(
19 | bibtype = "Article",
20 | title = "OSHDB: a framework for spatio-temporal analysis of OpenStreetMap history data",
21 | author = c(
22 | person(given = "Martin", family = "Raifer"),
23 | person(given = "Rafael", family = "Troilo"),
24 | person(given = "Fabian", family = "Kowatsch"),
25 | person(given = "Michael", family = "Auer"),
26 | person(given = "Lukas", family = "Loos"),
27 | person(given = "Sabrina", family = "Marx"),
28 | person(given = "Katharina", family = "Przybill"),
29 | person(given = "Sascha", family = "Fendrich"),
30 | person(given = "Franz-Benjamin", family = "Mocnik"),
31 | person(given = "Alexander", family = "Zipf")
32 | ),
33 | journal = "Open Geospatial Data, Software and Standards",
34 | year = "2019",
35 | month = "Apr",
36 | day = "08",
37 | volume = 4,
38 | number = 1,
39 | pages = 3,
40 | doi = "10.1186/s40965-019-0061-3",
41 | header = "For scientific papers or similar publications around the analysis of OSM history data, please consider to additionally cite the technical paper describing the OSHDB:"
42 | )
43 |
--------------------------------------------------------------------------------
/R/set_boundary.R:
--------------------------------------------------------------------------------
1 | #' Set boundary
2 | #'
3 | #' Set or modify the spatial filter of an existing `ohsome_query` object
4 | #'
5 | #' [set_boundary()] adds a spatial filter to an `ohsome_query` object or
6 | #' replaces an existing one. The spatial filter of a query to the ohsome API can
7 | #' be defined as one or more polygons, bounding boxes or bounding circles.
8 | #'
9 | #' @inheritParams ohsome_boundary
10 | #' @inheritParams ohsome_post
11 | #' @inherit ohsome_query return
12 | #' @seealso [ohsome API documentation](https://docs.ohsome.org/ohsome-api/v1/)
13 | #' @export
14 | #' @examples
15 | #' # Query without boundary definition
16 | #' q <- ohsome_query(
17 | #' "elements/count/groupBy/boundary",
18 | #' filter = "building=*",
19 | #' time = "2022-01-01"
20 | #' )
21 | #'
22 | #' # Use franconia from the mapview package as bounding polygons
23 | #' \donttest{
24 | #' set_boundary(q, mapview::franconia, digits = 4)
25 | #' }
26 | #'
27 | #' # Use the bounding box of franconia
28 | #' \donttest{
29 | #' set_boundary(q, sf::st_bbox(mapview::franconia))
30 | #' }
31 | #'
32 | #' \dontrun{
33 | #' # Get bounding box of the city of Kigali from OSM
34 | #' set_boundary(q, osmdata::getbb("Kigali"))
35 | #' }
36 | #'
37 | #' # Definition of two named bounding circles
38 | #' set_boundary(q, c("Circle 1:8.6528,49.3683,1000", "Circle 2:8.7294,49.4376,1000"))
39 | #'
40 | set_boundary <- function(query, boundary = NULL, ...) {
41 |
42 | endpoint <- gsub("^.*?/", "", httr::parse_url(query$url)$path)
43 | body <- query$body
44 |
45 | btypes <- c("bpolys", "bboxes", "bcircles")
46 |
47 | boundary <- ohsome_boundary(boundary %||% Reduce(`%||%`, body[btypes]), ...)
48 |
49 | body[[boundary$type]] <- boundary$boundary
50 | body[btypes[btypes != boundary$type]] <- NULL
51 |
52 | return(do.call(ohsome_query, c(endpoint, body)))
53 | }
54 |
--------------------------------------------------------------------------------
/man/ohsome_get_metadata.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_get_metadata.R
3 | \name{ohsome_get_metadata}
4 | \alias{ohsome_get_metadata}
5 | \title{GET metadata from ohsome API}
6 | \usage{
7 | ohsome_get_metadata(quiet = FALSE)
8 | }
9 | \arguments{
10 | \item{quiet}{logical; suppresses message on data attribution, API version and
11 | temporal extent.}
12 | }
13 | \value{
14 | An \code{ohsome_metadata} object. This is a named list with the
15 | attributes \code{date}, \code{status_code} (of the GET request) and the following list
16 | elements:
17 | \itemize{
18 | \item \code{attribution}: character; \code{url} and \code{text} of OSM data copyrights and
19 | attribution
20 | \item \code{apiVersion}: character; Version of the ohsome API
21 | \item \code{timeout}: numeric; limit of the processing time in seconds
22 | \item \code{extractRegion}:
23 | \itemize{
24 | \item \code{spatialExtent}: sfc_POLYGON; spatial boundary of the OSM data in the
25 | underlying OSHDB
26 | \item \code{temporalExtent}: vector of ISO 8601 character; start and end of the temporal extent of OSM data in the
27 | underlying OSHDB
28 | \item \code{replicationSequenceNumber}: numeric; precise state of the OSM data
29 | contained in the underlying OSHDB, expressed as the id of the last
30 | applied (hourly) diff file from \href{https://planet.openstreetmap.org}{Planet OSM}
31 | }
32 | }
33 | }
34 | \description{
35 | Returns parsed metadata from ohsome API
36 | }
37 | \details{
38 | \code{ohsome_get_metadata()} sends a GET request to the metadata endpoint of
39 | ohsome API and parses the response. The parsed metadata is silently returned.
40 | }
41 | \examples{
42 | \dontrun{
43 | ohsome_get_metadata()
44 | }
45 | }
46 | \seealso{
47 | \href{https://docs.ohsome.org/ohsome-api/v1/endpoints.html#metadata}{ohsome API Endpoints -- Metadata}
48 | }
49 |
--------------------------------------------------------------------------------
/R/data.R:
--------------------------------------------------------------------------------
1 | #' @docType data
2 | #' @name ohsome_api_url
3 | #' @title ohsome API URL
4 | #' @description The base URL of the ohsome API with path to current major
5 | #' version.
6 | #' @format A list:
7 | #' * `base`: character; base URL
8 | #' * `version`: character; path to current major API version
9 | NULL
10 |
11 | #' @docType data
12 | #' @name ohsome_endpoints
13 | #' @title ohsome API endpoints
14 | #' @description Available ohsome API endpoints with their parameters
15 | #' @format A list of ohsome API endpoints.
16 | NULL
17 |
18 | #' @docType data
19 | #' @name ohsome_metadata
20 | #' @title ohsome API metadata
21 | #' @description Metadata of the ohsome API that is requested on loading the
22 | #' package
23 | #' @format An `ohsome_metadata` object. This is a named list with the
24 | #' attributes `date`, `status_code` (of the GET request) and the following list
25 | #' elements:
26 | #' * `attribution`: character; `url` and `text` of OSM data copyrights and
27 | #' attribution
28 | #' * `apiVersion`: numeric_version; Version of the ohsome API
29 | #' * `timeout`: numeric; limit of the processing time in seconds
30 | #' * `extractRegion`:
31 | #' * `spatialExtent`: sfc_POLYGON; spatial boundary of the OSM data in the
32 | #' underlying OSHDB
33 | #' * `temporalExtent`: vector of POSIXct; timeframe of the OSM data in the
34 | #' underlying OSHDB data
35 | #' * `replicationSequenceNumber`: numeric; precise state of the OSM data
36 | #' contained in the underlying OSHDB, expressed as the id of the last
37 | #' applied (hourly) diff file from [Planet OSM](https://planet.openstreetmap.org)
38 | NULL
39 |
40 | #' @docType data
41 | #' @name ohsome_temporalExtent
42 | #' @title ohsome API temporal extent
43 | #' @description Temporal extent of the OSM data in the underlying OSHDB
44 | #' @format A vector of POSIXct
45 | NULL
46 |
--------------------------------------------------------------------------------
/tests/testthat/mock_api/404/api.ohsome.org/v1/metadata.R:
--------------------------------------------------------------------------------
1 | structure(list(url = "https://api.ohsome.org/404/metadata", status_code = 404L,
2 | headers = structure(list(date = "Wed, 16 Jun 2021 07:38:04 GMT",
3 | server = "Apache/2.4.29 (Ubuntu)", `content-length` = "277",
4 | `content-type` = "text/html; charset=iso-8859-1"), class = c("insensitive",
5 | "list")), all_headers = list(list(status = 301L, version = "HTTP/1.1",
6 | headers = structure(list(date = "Wed, 16 Jun 2021 07:38:04 GMT",
7 | server = "Apache/2.4.29 (Ubuntu)", location = "https://api.ohsome.org/404/metadata",
8 | `content-length` = "323", `content-type` = "text/html; charset=iso-8859-1"), class = c("insensitive",
9 | "list"))), list(status = 404L, version = "HTTP/1.1",
10 | headers = structure(list(date = "Wed, 16 Jun 2021 07:38:04 GMT",
11 | server = "Apache/2.4.29 (Ubuntu)", `content-length` = "277",
12 | `content-type` = "text/html; charset=iso-8859-1"), class = c("insensitive",
13 | "list")))), cookies = structure(list(domain = logical(0),
14 | flag = logical(0), path = logical(0), secure = logical(0),
15 | expiration = structure(numeric(0), class = c("POSIXct",
16 | "POSIXt")), name = logical(0), value = logical(0)), row.names = integer(0), class = "data.frame"),
17 | content = charToRaw("\n
\n404 Not Found\n\nNot Found
\nThe requested URL was not found on this server.
\n
\nApache/2.4.29 (Ubuntu) Server at api.ohsome.org Port 443\n\n"),
18 | date = structure(1623829084, class = c("POSIXct", "POSIXt"
19 | ), tzone = "GMT"), times = c(redirect = 0.105752, namelookup = 0.008729,
20 | connect = 0.128672, pretransfer = 0.158497, starttransfer = 0.220432,
21 | total = 0.220477)), class = "response")
22 |
--------------------------------------------------------------------------------
/R/ohsome_contributions_count.R:
--------------------------------------------------------------------------------
1 | #' Count OSM contributions
2 | #'
3 | #' Creates an `ohsome_query` object for OSM contributions count
4 | #'
5 | #' `ohsome_contributions_count()` creates an `ohsome_query` object for
6 | #' OSM element aggregation. Boundary objects are passed via [set_boundary()]
7 | #' into [ohsome_boundary()].
8 | #'
9 | #' @inherit ohsome_query params return
10 | #' @param latest logical; if `TRUE`, request only the latest contributions
11 | #' provided to each OSM element.
12 | #' @param return_value character; the value to be returned by the ohsome API:
13 | #' * `"absolute"` returns the absolute number of contributions. This is the
14 | #' default.
15 | #' * `"density"` returns the number of contributions per square kilometer.
16 | #' @param time character; `time` parameter of the query (see
17 | #' [Supported time formats](https://docs.ohsome.org/ohsome-api/v1/time.html)).
18 | #' @inherit ohsome_query return
19 | #' @seealso [ohsome API Endpoints - Contributions Aggregation](https://docs.ohsome.org/ohsome-api/v1/endpoints.html#contributions-aggregation)
20 | #' @export
21 | #' @examples
22 | #' # Monthly counts of contributions to man-made objects around "Null Island"
23 | #' ohsome_contributions_count("0,0,10", filter = "man_made=*", time = "2010/2020/P1Y")
24 | #'
25 | #' # Monthly counts of latest contributions to man-made objects around "Null Island"
26 | #' ohsome_contributions_count(
27 | #' "0,0,10",
28 | #' latest = TRUE,
29 | #' filter = "man_made=*",
30 | #' time = "2010/2020/P1Y"
31 | #' )
32 | #'
33 | ohsome_contributions_count <- function(
34 | boundary = NULL,
35 | latest = FALSE,
36 | return_value = c("absolute", "density"),
37 | time = NULL,
38 | ...
39 | ) {
40 | return_value <- match.arg(return_value)
41 | if(latest) latest <- "latest" else latest <- NULL
42 | if(return_value == "absolute") return_value <- NULL
43 |
44 | q <- ohsome_query(c("contributions", latest, "count", return_value), boundary,...)
45 | set_time(q, time)
46 | }
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_query.R:
--------------------------------------------------------------------------------
1 | test_that("requests geojson content with groupBy/boundary queries", {
2 |
3 | q1 <- ohsome_query(c("elements", "count", "groupBy", "boundary"))
4 | q2 <- ohsome_query("elements/length/density/groupBy/boundary")
5 | q3 <- ohsome_query("elements/count", grouping = "boundary")
6 | expect_equal(q1$body$format, "geojson")
7 | expect_equal(q2$body$format, "geojson")
8 | expect_equal(q3$body$format, "geojson")
9 | })
10 |
11 | test_that("requests csv content with aggregation not grouped by boundary", {
12 | q1 <- ohsome_query(c("elements", "area", "ratio"))
13 | q2 <- ohsome_query("elements/count/groupBy/tag")
14 | expect_equal(q1$body$format, "csv")
15 | expect_equal(q2$body$format, "csv")
16 | })
17 |
18 | test_that("accepts custom format parameter", {
19 | q <- ohsome_query(c("elements", "count"), format = "foo")
20 | expect_equal(q$body$format, "foo")
21 | })
22 |
23 | test_that("does not set format parameter with elements extraction queries", {
24 | q1 <- ohsome_query(c("elements", "bbox"))
25 | q2 <- ohsome_query("elements/centroid")
26 | expect_null(q1$body$format)
27 | expect_null(q2$body$format)
28 | })
29 |
30 | test_that("does not overwrite explicit format with groupBy/boundary", {
31 | q <- ohsome_query("elements/count", grouping = "boundary", format = "csv")
32 | expect_equal(q$body$format, "csv")
33 | })
34 |
35 | test_that("returns object of class ohsome_query", {
36 | expect_s3_class(ohsome_query("elements/count"), "ohsome_query")
37 | })
38 |
39 | test_that("issues warning if boundary and other bounding geom params are set", {
40 | expect_warning(
41 | ohsome_query("elements/count", boundary = "0,0,1,1", bboxes = "1,1,2,2")
42 | )
43 | expect_warning(
44 | ohsome_query("elements/count", boundary = "0,0,1,1", bcircles = "0,0,1000")
45 | )
46 | expect_warning(
47 | ohsome_query("elements/count", boundary = "0,0,1,1", bpolys = "foo")
48 | )
49 | })
50 |
51 | test_that("correctly sets bboxes param based on boundary argument", {
52 | bbox <- "0,0,1,1"
53 | q <- ohsome_query("elements/count", boundary = bbox)
54 | expect_equal(q$body$bboxes, bbox)
55 | })
56 |
57 |
--------------------------------------------------------------------------------
/tests/testthat/test-set_endpoint.R:
--------------------------------------------------------------------------------
1 | test_that("replaces endpoint in ohsome_query by default (append = FALSE)", {
2 |
3 | q1 <- ohsome_query("elements/count")
4 | q2 <- set_endpoint(q1, "elements/length")
5 | expect_equal(httr::parse_url(q2$url)$path, "v1/elements/length")
6 | })
7 |
8 | test_that("appends endpoint if append = TRUE", {
9 |
10 | q1 <- ohsome_query("elements/count")
11 | q2 <- set_endpoint(q1, c("groupBy", "boundary"), append = TRUE)
12 | expect_equal(httr::parse_url(q2$url)$path, "v1/elements/count/groupBy/boundary")
13 | })
14 |
15 | test_that("resets response format correctly according to reset_format argument",{
16 | q1 <- ohsome_query("elements/count")
17 | q2 <- set_endpoint(q1, c("groupBy", "boundary"), append = TRUE, reset_format = FALSE)
18 | q3 <- set_endpoint(q1, c("groupBy", "boundary"), append = TRUE)
19 | q4 <- set_endpoint(q1, c("elements/geometry"))
20 | expect_equal(q2$body$format, "csv")
21 | expect_equal(q3$body$format, "geojson")
22 | expect_null(q4$body$format)
23 | })
24 |
25 | test_that("returns unmodified endpoint if grouping arg is missing", {
26 | q1 <- ohsome_query("elements/count/groupBy/boundary/groupBy/tag")
27 | q2 <- set_grouping(q1)
28 | expect_equal(httr::parse_url(q1$url)$path, httr::parse_url(q2$url)$path)
29 |
30 | q1 <- ohsome_query("elements/count")
31 | q2 <- set_grouping(q1)
32 | expect_equal(httr::parse_url(q1$url)$path, httr::parse_url(q2$url)$path)
33 | })
34 |
35 | test_that("correctly modifies grouping", {
36 | q1 <- ohsome_query("elements/count/groupBy/boundary")
37 | q2 <- set_grouping(q1, "tag")
38 | expect_equal(httr::parse_url(q2$url)$path, "v1/elements/count/groupBy/tag")
39 |
40 | q1 <- ohsome_query("elements/count")
41 | q2 <- set_grouping(q1, "tag")
42 | expect_equal(httr::parse_url(q2$url)$path, "v1/elements/count/groupBy/tag")
43 |
44 | q1 <- ohsome_query("elements/count")
45 | q2 <- set_grouping(q1, c("Boundary", "Tag"))
46 | expect_equal(httr::parse_url(q2$url)$path, "v1/elements/count/groupBy/boundary/groupBy/tag")
47 | })
48 |
49 | test_that("removes grouping if grouping = NULL", {
50 | q1 <- ohsome_query("elements/count/groupBy/boundary")
51 | q2 <- set_grouping(q1, grouping = NULL)
52 | expect_equal(httr::parse_url(q2$url)$path, "v1/elements/count")
53 | })
--------------------------------------------------------------------------------
/tests/testthat/test-set_parameters.R:
--------------------------------------------------------------------------------
1 | test_that("sets and modifies parameters of ohsome_query", {
2 |
3 | q <- ohsome_query("elements/count") %>%
4 | set_parameters(foo = "bar", foo2 = "bar") %>%
5 | set_parameters(foo = "baz")
6 |
7 | expect_equal(q$body$foo, "baz")
8 | expect_equal(q$body$foo2, "bar")
9 | })
10 |
11 | test_that("returns unmodified query if no args defined", {
12 | q1 <- ohsome_query("elements/count", filter = "foo")
13 | q2 <- set_parameters(q1)
14 | expect_equal(q1, q2)
15 | })
16 |
17 | test_that("returns unmodified query if filter arg is missing", {
18 | q1 <- ohsome_query("elements/count", filter = "foo")
19 | q2 <- set_filter(q1)
20 | expect_equal(q1$body$filter, q2$body$filter)
21 | })
22 |
23 | test_that("removes filter with arg filter = NULL", {
24 | q1 <- ohsome_query("elements/count", filter = "foo")
25 | q2 <- set_filter(q1, filter = NULL)
26 | expect_null(q2$body$filter)
27 | })
28 |
29 | # set properties
30 | test_that("removes properties from query body by default", {
31 | q <- ohsome_query("elements/centroid", properties = "tags")
32 | expect_null(set_properties(q)$body$properties)
33 | })
34 |
35 | test_that("correctly sets properties", {
36 | q <- ohsome_query("elements/centroid")
37 |
38 | expect_equal(
39 | set_properties(q, "tags")$body$properties,
40 | "tags"
41 | )
42 | expect_equal(
43 | set_properties(q, "metadata, tags")$body$properties,
44 | "metadata,tags"
45 | )
46 | expect_equal(
47 | set_properties(q, c("tags", "metadata"))$body$properties,
48 | "tags,metadata"
49 | )
50 | })
51 |
52 | test_that("throws error on properties argument 'foo'", {
53 |
54 | q <- ohsome_query("elements/centroid")
55 |
56 | expect_error(set_properties(q, "foo"))
57 | })
58 |
59 | test_that("removes 'contributionTypes' from element extraction query", {
60 |
61 | q <- ohsome_query("elements/elements/bbox")
62 |
63 | expect_equal(
64 | set_properties(q, c("tags", "contributionTypes"))$body$properties,
65 | "tags"
66 | )
67 | })
68 |
69 | test_that("accepts 'contributionTypes' in contribution extraction", {
70 |
71 | q <- ohsome_query("elements/contributions/bbox")
72 |
73 | expect_equal(
74 | set_properties(q, c("tags", "contributionTypes"))$body$properties,
75 | "tags,contributionTypes"
76 | )
77 | })
78 |
--------------------------------------------------------------------------------
/man/ohsome_post.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_post.R
3 | \name{ohsome_post}
4 | \alias{ohsome_post}
5 | \title{Send POST request to ohsome API}
6 | \usage{
7 | ohsome_post(
8 | query,
9 | parse = TRUE,
10 | validate = TRUE,
11 | strict = validate,
12 | additional_identifiers = NULL,
13 | ...
14 | )
15 | }
16 | \arguments{
17 | \item{query}{An \code{ohsome_query} object constructed with \code{\link[=ohsome_query]{ohsome_query()}} or
18 | any of its wrapper functions}
19 |
20 | \item{parse}{logical; if \code{TRUE}, parse the ohsome API response with
21 | \code{\link[=ohsome_parse]{ohsome_parse()}}}
22 |
23 | \item{validate}{logical; if \code{TRUE}, issues warning for invalid endpoint or
24 | invalid/missing query parameters.}
25 |
26 | \item{strict}{logical; If \code{TRUE}, throws error on invalid query. Overrules
27 | validate argument \code{TRUE}.}
28 |
29 | \item{additional_identifiers}{vector coercible to character; optional user
30 | agent identifiers in addition to \code{"ohsome-r/{version}"}.}
31 |
32 | \item{...}{Additional arguments passed to \code{\link[=ohsome_parse]{ohsome_parse()}}:
33 | \itemize{
34 | \item \code{returnclass}: class of the returned object
35 | \item \code{omit_empty}: logical; omit features with empty geometries (only if
36 | \code{returnclass = "sf"})
37 | }}
38 | }
39 | \value{
40 | An \code{ohsome_response} object if \code{parse = FALSE}, else an \code{sf} object,
41 | a \code{data.frame}, a \code{list} or a \code{character}
42 | }
43 | \description{
44 | Sends an \code{ohsome_query} object as a POST request to the ohsome API and
45 | returns the response.
46 | }
47 | \examples{
48 | \dontrun{
49 | # Get bounding box of the city of Berlin
50 | bbberlin <- osmdata::getbb("Berlin")
51 |
52 | # Query for cinema geometries within bounding box
53 | q <- ohsome_elements_geometry(bbberlin, filter = "amenity=cinema")
54 |
55 | # Send query to ohsome API and return sf by default
56 | ohsome_post(q)
57 |
58 | # Send query to ohsome API and return data.frame
59 | ohsome_post(q, returnclass = "data.frame")
60 |
61 | # Send query and return unparsed response
62 | ohsome_post(q, parse = FALSE)
63 | }
64 |
65 | }
66 | \seealso{
67 | \href{https://docs.ohsome.org/ohsome-api/v1/}{ohsome API documentation}
68 | }
69 |
--------------------------------------------------------------------------------
/R/ohsome_get_metadata.R:
--------------------------------------------------------------------------------
1 | #' GET metadata from ohsome API
2 | #'
3 | #' Returns parsed metadata from ohsome API
4 | #'
5 | #' `ohsome_get_metadata()` sends a GET request to the metadata endpoint of
6 | #' ohsome API and parses the response. The parsed metadata is silently returned.
7 | #'
8 | #' @param quiet logical; suppresses message on data attribution, API version and
9 | #' temporal extent.
10 | #' @return An `ohsome_metadata` object. This is a named list with the
11 | #' attributes `date`, `status_code` (of the GET request) and the following list
12 | #' elements:
13 | #' * `attribution`: character; `url` and `text` of OSM data copyrights and
14 | #' attribution
15 | #' * `apiVersion`: character; Version of the ohsome API
16 | #' * `timeout`: numeric; limit of the processing time in seconds
17 | #' * `extractRegion`:
18 | #' * `spatialExtent`: sfc_POLYGON; spatial boundary of the OSM data in the
19 | #' underlying OSHDB
20 | #' * `temporalExtent`: vector of ISO 8601 character; start and end of the temporal extent of OSM data in the
21 | #' underlying OSHDB
22 | #' * `replicationSequenceNumber`: numeric; precise state of the OSM data
23 | #' contained in the underlying OSHDB, expressed as the id of the last
24 | #' applied (hourly) diff file from [Planet OSM](https://planet.openstreetmap.org)
25 | #' @seealso [ohsome API Endpoints -- Metadata](https://docs.ohsome.org/ohsome-api/v1/endpoints.html#metadata)
26 | #' @export
27 | #' @examples
28 | #' \dontrun{
29 | #' ohsome_get_metadata()
30 | #' }
31 |
32 | ohsome_get_metadata <- function(quiet = FALSE) {
33 |
34 | response <- httr::GET(
35 | url = build_endpoint_url("metadata"),
36 | httr::user_agent(paste("ohsome-r", utils::packageVersion("ohsome"), sep = "/"))
37 | )
38 |
39 | httr::stop_for_status(response)
40 |
41 | parsed <- ohsome_parse(response, returnclass = "list")
42 | spatialExtent <- parsed$extractRegion$spatialExtent
43 | parsed$extractRegion$spatialExtent <- convert_spatialExtent(spatialExtent)
44 |
45 | ohsome_metadata <- structure(
46 | .Data = parsed,
47 | status_code = httr::status_code(response),
48 | date = httr::headers(response)$date,
49 | class = "ohsome_metadata"
50 | )
51 |
52 | if(!quiet) message(create_metadata_message(ohsome_metadata))
53 | invisible(ohsome_metadata)
54 | }
55 |
--------------------------------------------------------------------------------
/man/ohsome_parse.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_parse.R
3 | \name{ohsome_parse}
4 | \alias{ohsome_parse}
5 | \alias{ohsome_sf}
6 | \alias{ohsome_df}
7 | \title{Parse content from an ohsome API response}
8 | \usage{
9 | ohsome_parse(
10 | response,
11 | returnclass = c("default", "sf", "data.frame", "list", "character"),
12 | omit_empty = TRUE
13 | )
14 |
15 | ohsome_sf(response, omit_empty = TRUE)
16 |
17 | ohsome_df(response, omit_empty = TRUE)
18 | }
19 | \arguments{
20 | \item{response}{An \code{ohsome_response} object}
21 |
22 | \item{returnclass}{character; one of the following:
23 | \itemize{
24 | \item \code{"default"} returns \code{sf} if the \code{ohsome_response} contains GeoJSON, or
25 | else a \code{data.frame}.
26 | \item \code{"sf"} returns \code{sf} if the \code{ohsome_response} contains GeoJSON, else
27 | issues a warning and returns a \code{data.frame}.
28 | \item \code{"data.frame"} returns a \code{data.frame}.
29 | \item \code{"list"} returns a \code{list}.
30 | \item \code{"character"} returns the ohsome API response body as text (JSON or
31 | semicolon-separated values)
32 | }}
33 |
34 | \item{omit_empty}{logical; omit features with empty geometries (only if
35 | \code{returnclass = "sf"})}
36 | }
37 | \value{
38 | An \code{sf} object, a \code{data.frame}, a \code{list} or a \code{character}
39 | }
40 | \description{
41 | Extracts and parses the content from an ohsome API response
42 | }
43 | \details{
44 | \code{ohsome_parse()} parses an \code{ohsome_response} object into an object of the
45 | specified class. By default, this is an \code{sf} object if the ohsome API
46 | response contains GeoJSON data or a \code{data.frame} if it does not.
47 | \code{ohsome_sf()} and \code{ohsome_df()} wrapper functions for specific return
48 | classes.
49 | }
50 | \examples{
51 | \dontrun{
52 | # Create and send a query to ohsome API
53 | r <- ohsome_query("elements/centroid", filter = "amenity=*") |>
54 | set_boundary(osmdata::getbb("Heidelberg")) |>
55 | set_time("2021") |>
56 | set_properties("metadata") |>
57 | ohsome_post(parse = FALSE)
58 |
59 | # Parse response to object of default class (here: sf)
60 | ohsome_parse(r)
61 |
62 | # Parse response to data.frame
63 | ohsome_df(r)
64 |
65 | # Parse response to sf
66 | ohsome_sf(r)
67 | }
68 |
69 | }
70 | \concept{Extract and parse the content from an ohsome API response}
71 |
--------------------------------------------------------------------------------
/R/ohsome_extract_elementsFullHistory.R:
--------------------------------------------------------------------------------
1 | #' Extract OSM elements' full history
2 | #'
3 | #' Creates an `ohsome_query` object for the extraction of OSM elements' full
4 | #' history
5 | #'
6 | #' `ohsome_extract_elementsFullHistory()` creates an `ohsome_query` object for OSM
7 | #' element full history extraction. `ohsome_elementsFullHistory_bbox()`,
8 | #' `ohsome_elementsFullHistory_centroid()` and
9 | #' `ohsome_elementsFullHistory_geometry()` are wrapper functions for specific
10 | #' elementsFullHistory extraction endpoints. Boundary objects are passed via
11 | #' [set_boundary()] into [ohsome_boundary()].
12 | #'
13 | #' @inherit ohsome_query params return
14 | #' @inheritParams ohsome_contributions_count
15 | #' @inheritParams ohsome_extract_elements
16 | #' @family Extract elements full History
17 | #' @seealso [ohsome API Endpoints -- Elements Full History Extraction](https://docs.ohsome.org/ohsome-api/v1/endpoints.html#elements-full-history-extraction)
18 | #' @export
19 | #' @examples
20 | #'
21 | #' # Extract full history of building geometries around Heidelberg main station:
22 | #' ohsome_elementsFullHistory_geometry(
23 | #' boundary = "8.67542,49.40347,1000",
24 | #' time = "2012,2022",
25 | #' filter = "building=* and geometry:polygon",
26 | #' clipGeometry = FALSE
27 | #' )
28 |
29 | ohsome_extract_elementsFullHistory <- function(
30 | boundary = NULL,
31 | geometryType = c("centroid", "bbox", "geometry"),
32 | time = NULL,
33 | properties = NULL,
34 | clipGeometry = TRUE,
35 | ...
36 | ) {
37 | geometryType <- match.arg(geometryType)
38 | q <- ohsome_query(c("elementsFullHistory", geometryType), boundary, ...)
39 | q <- set_properties(q, properties)
40 | q <- set_parameters(q, clipGeometry = as.character(clipGeometry))
41 | q <- set_time(q, time)
42 | return(q)
43 | }
44 |
45 | #' @export
46 | #' @rdname ohsome_extract_elementsFullHistory
47 | ohsome_elementsFullHistory_bbox <- function(boundary = NULL, ...) {
48 | ohsome_extract_elementsFullHistory(boundary, geometryType = "bbox", ...)
49 | }
50 |
51 | #' @export
52 | #' @rdname ohsome_extract_elementsFullHistory
53 | ohsome_elementsFullHistory_centroid <- function(boundary = NULL, ...) {
54 | ohsome_extract_elementsFullHistory(boundary, geometryType = "centroid", ...)
55 | }
56 |
57 | #' @export
58 | #' @rdname ohsome_extract_elementsFullHistory
59 | ohsome_elementsFullHistory_geometry <- function(boundary = NULL, ...) {
60 | ohsome_extract_elementsFullHistory(boundary, geometryType = "geometry", ...)
61 | }
--------------------------------------------------------------------------------
/R/utils.R:
--------------------------------------------------------------------------------
1 | #' Build URL to an ohsome API endpoint
2 | #'
3 | #' @param endpoint character (atomic or vector)
4 | #' @return character
5 | #' @keywords Internal
6 | #' @noRd
7 | build_endpoint_url <- function(endpoint) {
8 | trimws(
9 | httr::modify_url(
10 | ohsome::ohsome_api_url$base,
11 | path = c(ohsome::ohsome_api_url$version, endpoint)
12 | ),
13 | whitespace = "/"
14 | )
15 | }
16 |
17 |
18 | #' Convert spatialExtent of ohsome metadata
19 | #'
20 | #' @param spatialExtent The `$extractRegion$spatialExtent` element of the
21 | #' parsed content of a response from the metadata endpoint of ohsome API
22 | #' @return An `sfc_POLYGON` object
23 | #' @keywords Internal
24 | #' @noRd
25 | convert_spatialExtent <- function(spatialExtent) {
26 |
27 | if(spatialExtent$type != "Polygon") return(spatialExtent)
28 |
29 | coords <- list(matrix(spatialExtent$coordinates, ncol = 2))
30 | sf::st_sfc(sf::st_polygon(coords), crs = 4326)
31 | }
32 |
33 |
34 | #' Create metadata message
35 | #'
36 | #' Creates a message text from an `ohsome_metadata` object.
37 | #'
38 | #' @param meta An [ohsome_metadata] object
39 | #' @return character
40 | #' @keywords Internal
41 | #' @noRd
42 | create_metadata_message <- function(meta) {
43 | sprintf(
44 | "Data: %s %s\nohsome API version: %s\nTemporal extent: %s to %s",
45 | meta$attribution$text,
46 | meta$attribution$url,
47 | meta$apiVersion,
48 | meta$extractRegion$temporalExtent[1],
49 | meta$extractRegion$temporalExtent[2]
50 | )
51 | }
52 |
53 |
54 | #' Extract endpoint
55 | #'
56 | #' Extracts the API endpoint path from the URL in an `ohsome_query` object
57 | #' @inheritParams ohsome_post
58 | #' @return character
59 | #' @keywords Internal
60 | #' @noRd
61 | extract_endpoint <- function(query) {
62 | gsub("^.*?/", "", httr::parse_url(query$url)$path)
63 | }
64 |
65 |
66 | #' Type convert without message
67 | #'
68 | #' Converts types of data.frame columns with [readr::type_convert()] while
69 | #' suppressing messages
70 | #'
71 | #' @param df data.frame
72 | #' @return data.frame
73 | #' @keywords Internal
74 | #' @noRd
75 | convert_quietly <- function(df) suppressMessages(readr::type_convert(df))
76 |
77 |
78 | #' Null coalesce operator
79 | #'
80 | #' Operator that returns the left-hand side operand if it is not `NULL`, else
81 | #' returns the right-hand side operand
82 | #'
83 | #' @name null-coalesce
84 | #' @param a left-side argument
85 | #' @param b right-side argument
86 | #' @keywords Internal
87 | #' @noRd
88 | `%||%` <- function(a, b) if (is.null(a)) b else a
89 |
--------------------------------------------------------------------------------
/tests/testthat/mock_api/404/api.ohsome.org/v1/elements/amount-754ee5-POST.R:
--------------------------------------------------------------------------------
1 | structure(list(url = "https://api.ohsome.org/v1/elements/amount",
2 | status_code = 404L, headers = structure(list(date = "Tue, 22 Jun 2021 15:13:36 GMT",
3 | server = "Apache/2.4.29 (Ubuntu)", `access-control-allow-origin` = "*",
4 | `access-control-allow-methods` = "POST, GET", `access-control-max-age` = "3600",
5 | `access-control-allow-credentials` = "true", `access-control-allow-headers` = "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization",
6 | `content-disposition` = "attachment;filename=ohsome.csv",
7 | `content-type` = "application/json;charset=UTF-8", `content-encoding` = "gzip",
8 | vary = "Accept-Encoding", `cache-control` = "max-age=0, no-store",
9 | `transfer-encoding` = "chunked"), class = c("insensitive",
10 | "list")), all_headers = list(list(status = 404L, version = "HTTP/1.1",
11 | headers = structure(list(date = "Tue, 22 Jun 2021 15:13:36 GMT",
12 | server = "Apache/2.4.29 (Ubuntu)", `access-control-allow-origin` = "*",
13 | `access-control-allow-methods` = "POST, GET", `access-control-max-age` = "3600",
14 | `access-control-allow-credentials` = "true", `access-control-allow-headers` = "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization",
15 | `content-disposition` = "attachment;filename=ohsome.csv",
16 | `content-type` = "application/json;charset=UTF-8",
17 | `content-encoding` = "gzip", vary = "Accept-Encoding",
18 | `cache-control` = "max-age=0, no-store", `transfer-encoding` = "chunked"), class = c("insensitive",
19 | "list")))), cookies = structure(list(domain = logical(0),
20 | flag = logical(0), path = logical(0), secure = logical(0),
21 | expiration = structure(numeric(0), class = c("POSIXct",
22 | "POSIXt")), name = logical(0), value = logical(0)), row.names = integer(0), class = "data.frame"),
23 | content = charToRaw("{\n \"timestamp\" : \"2021-06-22T15:13:36.122+0000\",\n \"status\" : 404,\n \"error\" : \"Not Found\",\n \"message\" : \"No message available\",\n \"path\" : \"/elements/amount\"\n}"),
24 | date = structure(1624374816, class = c("POSIXct", "POSIXt"
25 | ), tzone = "GMT"), times = c(redirect = 0, namelookup = 0.015879,
26 | connect = 0.113829, pretransfer = 0.155543, starttransfer = 0,
27 | total = 0.248149)), class = "response")
28 |
--------------------------------------------------------------------------------
/R/ohsome_post.R:
--------------------------------------------------------------------------------
1 | #' Send POST request to ohsome API
2 | #'
3 | #' Sends an `ohsome_query` object as a POST request to the ohsome API and
4 | #' returns the response.
5 | #'
6 | #' @param query An `ohsome_query` object constructed with [ohsome_query()] or
7 | #' any of its wrapper functions
8 | #' @param parse logical; if `TRUE`, parse the ohsome API response with
9 | #' [ohsome_parse()]
10 | #' @param validate logical; if `TRUE`, issues warning for invalid endpoint or
11 | #' invalid/missing query parameters.
12 | #' @param strict logical; If `TRUE`, throws error on invalid query. Overrules
13 | #' validate argument `TRUE`.
14 | #' @param additional_identifiers vector coercible to character; optional user
15 | #' agent identifiers in addition to `"ohsome-r/{version}"`.
16 | #' @param ... Additional arguments passed to [ohsome_parse()]:
17 | #' * `returnclass`: class of the returned object
18 | #' * `omit_empty`: logical; omit features with empty geometries (only if
19 | #' `returnclass = "sf"`)
20 | #' @return An `ohsome_response` object if `parse = FALSE`, else an `sf` object,
21 | #' a `data.frame`, a `list` or a `character`
22 | #' @seealso [ohsome API documentation](https://docs.ohsome.org/ohsome-api/v1/)
23 | #' @export
24 | #' @examples
25 | #' \dontrun{
26 | #' # Get bounding box of the city of Berlin
27 | #' bbberlin <- osmdata::getbb("Berlin")
28 | #'
29 | #' # Query for cinema geometries within bounding box
30 | #' q <- ohsome_elements_geometry(bbberlin, filter = "amenity=cinema")
31 | #'
32 | #' # Send query to ohsome API and return sf by default
33 | #' ohsome_post(q)
34 | #'
35 | #' # Send query to ohsome API and return data.frame
36 | #' ohsome_post(q, returnclass = "data.frame")
37 | #'
38 | #' # Send query and return unparsed response
39 | #' ohsome_post(q, parse = FALSE)
40 | #' }
41 | #'
42 | ohsome_post <- function(
43 | query,
44 | parse = TRUE,
45 | validate = TRUE,
46 | strict = validate,
47 | additional_identifiers = NULL,
48 | ...
49 | ) {
50 | if(validate || strict) valid <- validate_query(query)
51 | stopifnot("Query invalid. See warnings for details." = !strict || valid)
52 |
53 | if(is.null(additional_identifiers)) additional_identifiers <- ""
54 | user_agent <- trimws(sprintf(
55 | "%s %s/%s",
56 | paste(as.character(additional_identifiers), collapse = " "),
57 | "ohsome-r", utils::packageVersion("ohsome")
58 | ))
59 |
60 | response <- httr::POST(
61 | url = query$url,
62 | body = query$body,
63 | encode = query$encode,
64 | httr::user_agent(user_agent)
65 | )
66 |
67 | attr(response, "request_body") <- query$body
68 | attr(response, "class") <- c("ohsome_response", "response")
69 |
70 | httr::stop_for_status(response)
71 |
72 | if(parse) { return(ohsome_parse(response, ...)) } else { return(response) }
73 | }
74 |
--------------------------------------------------------------------------------
/R/ohsome_extract_elements.R:
--------------------------------------------------------------------------------
1 | #' Extract OSM elements
2 | #'
3 | #' Create an `ohsome_query` object for OSM element extraction
4 | #'
5 | #' `ohsome_extract_elements()` creates an `ohsome_query` object for OSM element
6 | #' extraction. `ohsome_elements_bbox()`, `ohsome_elements_centroid()` and
7 | #' `ohsome_elements_geometry()` are wrapper functions for specific elements
8 | #' extraction endpoints. Boundary objects are passed via [set_boundary()] into
9 | #' [ohsome_boundary()].
10 | #'
11 | #' @inherit ohsome_query params return
12 | #' @inheritParams ohsome_aggregate_elements
13 | #' @param geometryType character; type of geometry to be extracted:
14 | #' * `"centroid"`,
15 | #' * `"bboxes"` (bounding boxes), or
16 | #' * `"geometry"`
17 | #'
18 | #' Caveat: Node elements are omitted from results in queries for bounding
19 | #' boxes.
20 | #' @param properties character; properties to be extracted with the features:
21 | #' * `"tags"`, and/or
22 | #' * `"metadata"` (i.e. `@changesetId`, `@lastEdit`, `@osmType`, and
23 | #' `@version`)
24 | #'
25 | #' Multiple values can be provided as comma-separated character or as
26 | #' character vector. This defaults to `NULL` (provides `@osmId`).
27 | #' @param clipGeometry logical; specifies whether the returned geometries should
28 | #' be clipped to the query’s spatial boundary
29 | #' @family Extract elements
30 | #' @seealso [ohsome API Endpoints -- Elements Extraction](https://docs.ohsome.org/ohsome-api/stable/endpoints.html#elements-extraction)
31 | #' @export
32 | #' @examples
33 | #' # Extract geometries, metadata and tags of man-made objects around "Null Island":
34 | #' ohsome_elements_geometry(
35 | #' "0,0,10",
36 | #' filter = "man_made=*",
37 | #' time = "2022-01-01",
38 | #' properties = c("metadata", "tags")
39 | #' )
40 | #'
41 | ohsome_extract_elements <- function(
42 | boundary = NULL,
43 | geometryType = c("centroid", "bbox", "geometry"),
44 | time = NULL,
45 | properties = NULL,
46 | clipGeometry = TRUE,
47 | ...
48 | ) {
49 | geometryType <- match.arg(geometryType)
50 | q <- ohsome_query(c("elements", geometryType), boundary, ...)
51 | q <- set_properties(q, properties)
52 | q <- set_parameters(q, clipGeometry = as.character(clipGeometry))
53 | q <- set_time(q, time)
54 | return(q)
55 | }
56 |
57 | #' @export
58 | #' @rdname ohsome_extract_elements
59 | ohsome_elements_bbox <- function(boundary = NULL, ...) {
60 | ohsome_extract_elements(boundary, geometryType = "bbox", ...)
61 | }
62 |
63 | #' @export
64 | #' @rdname ohsome_extract_elements
65 | ohsome_elements_centroid <- function(boundary = NULL, ...) {
66 | ohsome_extract_elements(boundary, geometryType = "centroid", ...)
67 | }
68 |
69 | #' @export
70 | #' @rdname ohsome_extract_elements
71 | ohsome_elements_geometry <- function(boundary = NULL, ...) {
72 | ohsome_extract_elements(boundary, geometryType = "geometry", ...)
73 | }
74 |
--------------------------------------------------------------------------------
/R/ohsome_extract_contributions.R:
--------------------------------------------------------------------------------
1 | #' Extract OSM contributions
2 | #'
3 | #' Creates an `ohsome_query` object for OSM contribution extraction
4 | #'
5 | #' `ohsome_extract_contributions()` creates an `ohsome_query` object for OSM
6 | #' contribution extraction. `ohsome_contributions_bbox()`,
7 | #' `ohsome_contributions_centroid()` and `ohsome_contributions_geometry()`
8 | #' are wrapper functions for specific contributions extraction endpoints.
9 | #' Boundary objects are passed via [set_boundary()] into [ohsome_boundary()].
10 | #'
11 | #' @inherit ohsome_query params return
12 | #' @inheritParams ohsome_contributions_count
13 | #' @inheritParams ohsome_extract_elements
14 | #' @param properties character; properties to be extracted with the
15 | #' contributions:
16 | #' * `"tags"`, and/or
17 | #' * `"metadata"` (i.e. `@changesetId`, `@lastEdit`, `@osmType`,
18 | #' `@version`), and/or
19 | #' * `"contributionTypes"` (i.e. `@creation`, `@tagChange`, `@deletion`, and
20 | #' `@geometryChange`)
21 | #'
22 | #' Multiple values can be provided as comma-separated character or as
23 | #' character vector. This defaults to `NULL` (provides
24 | #' `@contributionChangesetId`, `@osmId` and `@timestamp`).
25 | #' @family Extract contributions
26 | #' @seealso [ohsome API Endpoints -- Contributions Extraction](https://docs.ohsome.org/ohsome-api/stable/endpoints.html#contributions-extraction)
27 | #' @export
28 | #' @examples
29 | #' # Extract contributions to man-made objects around "Null Island" with metadata:
30 | #' ohsome_contributions_geometry(
31 | #' "0,0,10",
32 | #' filter = "man_made=*",
33 | #' time = c("2021-01-01", "2022-01-01"),
34 | #' properties = "metadata"
35 | #' )
36 | #'
37 | ohsome_extract_contributions <- function(
38 | boundary = NULL,
39 | geometryType = c("centroid", "bbox", "geometry"),
40 | latest = FALSE,
41 | time = NULL,
42 | properties = NULL,
43 | clipGeometry = TRUE,
44 | ...
45 | ) {
46 | geometryType <- match.arg(geometryType)
47 | if(latest) latest <- "latest" else latest <- NULL
48 | q <- ohsome_query(c("contributions", latest, geometryType), boundary, ...)
49 | q <- set_properties(q, properties)
50 | q <- set_parameters(q, clipGeometry = as.character(clipGeometry))
51 | q <- set_time(q, time)
52 | return(q)
53 | }
54 |
55 | #' @export
56 | #' @rdname ohsome_extract_contributions
57 | ohsome_contributions_bbox <- function(boundary = NULL, ...) {
58 | ohsome_extract_contributions(boundary, geometryType = "bbox", ...)
59 | }
60 |
61 | #' @export
62 | #' @rdname ohsome_extract_contributions
63 | ohsome_contributions_centroid <- function(boundary = NULL, ...) {
64 | ohsome_extract_contributions(boundary, geometryType = "centroid", ...)
65 | }
66 |
67 | #' @export
68 | #' @rdname ohsome_extract_contributions
69 | ohsome_contributions_geometry <- function(boundary = NULL, ...) {
70 | ohsome_extract_contributions(boundary, geometryType = "geometry", ...)
71 | }
72 |
--------------------------------------------------------------------------------
/R/set_endpoint.R:
--------------------------------------------------------------------------------
1 | #' Set endpoint
2 | #'
3 | #' Modifies the endpoint of an existing `ohsome_query` object
4 | #'
5 | #' `set_endpoint()` takes an `ohsome_query` object and modifies the ohsome API
6 | #' endpoint. `set_grouping()` takes an `ohsome_query` object and modifies the
7 | #' endpoint path for grouped aggregations.
8 | #'
9 | #' @inherit ohsome_query params return
10 | #' @inheritParams ohsome_post
11 | #' @param append logical; If `TRUE`, the provided endpoint string is appended to
12 | #' the existing endpoint definition instead of replacing it. This is
13 | #' particularly useful if you wish to add `density`/`ratio` and/or a grouping
14 | #' to an existing aggregation query.
15 | #' @param reset_format logical; if `TRUE`, the format parameter of the query is
16 | #' updated depending on the new endpoint.
17 | #' @param ... Additional arguments passed to `set_endpoint()`
18 | #' @family Set endpoint
19 | #' @seealso [ohsome API Endpoints](https://docs.ohsome.org/ohsome-api/v1/endpoints.html)
20 | #' @export
21 | #' @examples
22 | #' # Query for count of elements
23 | #' q <- ohsome_elements_count(
24 | #' boundary = "HD:8.5992,49.3567,8.7499,49.4371|HN:9.1638,49.113,9.2672,49.1766",
25 | #' time = "2022-01-01",
26 | #' filter = "highway=*"
27 | #' )
28 | #'
29 | #' # Modify query to aggregate length of elements instead of count
30 | #' set_endpoint(q, "elements/length")
31 | #'
32 | #' # Modify query to extract geometries instead of aggregating elements
33 | #' set_endpoint(q, "elements/geometry")
34 | #'
35 | #' # Append the endpoint path in order to group aggregation by boundary
36 | #' set_endpoint(q, "groupBy/boundary", append = TRUE)
37 | #'
38 | #' # Modify query to group aggregation by boundary
39 | #' set_grouping(q, grouping = "boundary")
40 | #'
41 | #' # Modify query to group by boundary, but keep format csv instead of geojson
42 | #' set_grouping(q, grouping = "boundary", reset_format = FALSE)
43 | #'
44 | #' # Append the endpoint path to query for element densities per boundary
45 | #' set_endpoint(q, c("density", "groupBy", "boundary"), append = TRUE)
46 | #'
47 | #' # Modify query to group aggregation by OSM element type
48 | #' set_grouping(q, grouping = "type")
49 | #'
50 | set_endpoint <- function(query, endpoint, append = FALSE, reset_format = TRUE) {
51 |
52 | if(append) {
53 | old <- gsub("^.*?/", "", httr::parse_url(query$url)$path)
54 | endpoint <- paste(old, paste(endpoint, collapse = "/"), sep = "/")
55 | }
56 |
57 | body <- query$body
58 | if(reset_format) body$format <- NULL
59 |
60 | return(do.call(ohsome_query, c(endpoint, body)))
61 | }
62 |
63 | #' @export
64 | #' @rdname set_endpoint
65 | set_grouping <- function(query, grouping, ...) {
66 |
67 | if(missing(grouping)) return(query)
68 |
69 | old <- gsub("^.*?/", "", httr::parse_url(query$url)$path)
70 | split <- unlist(strsplit(old, "/groupBy/"))
71 | if(!is.null(grouping)) {
72 | grouping <- paste("groupBy", tolower(grouping), sep = "/", collapse = "/")
73 | }
74 | endpoint <- paste(split[1], grouping, sep = "/")
75 |
76 | set_endpoint(query, endpoint, ...)
77 | }
78 |
--------------------------------------------------------------------------------
/NEWS.md:
--------------------------------------------------------------------------------
1 | # ohsome (development version)
2 |
3 | # ohsome 0.2.2
4 |
5 | * On attach, the package now issues an informative startup message instead of a
6 | warning if it could not retrieve metadata information from the ohsome API.
7 | * Vignette code chunks do not evaluate on CRAN to avoid errors when internet
8 | resources are temporally unavailable
9 | * Fixed tests to use suggested packages conditionally
10 |
11 | # ohsome 0.2.1
12 |
13 | * Package CITATION file calls `bibentry()` instead of old-style `citEntry()`.
14 | * Fixed incomplete file URIs in docs.
15 | * Fixed missing `strict = FALSE` in query example in `README`.
16 |
17 |
18 | # ohsome 0.2.0
19 |
20 | * Added a `NEWS.md` file to track changes to the package.
21 | * Added `strict`argument to `ohsome_post`. When set to TRUE (default), an error
22 | is thrown on invalid queries and the request is **not** sent to the API. Queries
23 | with undefined filter or time parameters are considered as invalid in strict
24 | mode.
25 | * Changed behavior of `set_properties()`: Removes properties parameter from
26 | query body by default, accepts *tags* and/or *metadata* and/or
27 | *contributionTypes* as properties argument (multiple values provided as
28 | comma-separated character or character vector).
29 | * Changed behavior of `set_time()`, `set_filter()`, `set_groupByKeys()`,
30 | `set_groupByKey()` and `set_groupByValues`: Return unmodified query object if
31 | parameter argument is missing (e.g. `set_filter(query)`), but remove parameter
32 | from body if explicitly set to NULL (e.g. `set_filter(query, filter = NULL)`)
33 | * Added `grouping` argument to `ohsome_query()` and `set_grouping()`function.
34 | Based on `grouping`, the endpoint URL is appended so that aggregations are
35 | grouped accordingly.
36 | * Added `return_value` argument to `ohsome_aggregate_elements()`. Based on
37 | `return_value`, the endpoint URL is appended so that either absolute aggregate
38 | values, densities or ratios are requested from the ohsome API.
39 | * Added `ohsome_query()` wrapper functions `ohsome_extract_elements()`,
40 | `ohsome_elements_bbox`, `ohsome_elements_centroid` and `ohsome_elements_geometry`
41 | for elements extraction endpoints of ohsome API
42 | * Added `ohsome_query()` wrapper functions `ohsome_extract_elementsFullHistory()`,
43 | `ohsome_elementsFullHistory_bbox()`, `ohsome_elementsFullHistory_centroid()` and
44 | `ohsome_elementsFullHistory_geometry()` for elementsFullHistory extraction
45 | endpoints of ohsome API
46 | * Added `ohsome_query()` wrapper functions `ohsome_extract_contributions()`,
47 | `ohsome_contributions_bbox()`, `ohsome_contributios_centroid()` and
48 | `ohsome_contributions_geometry()` for contributions extraction endpoints of ohsome
49 | API
50 | * Added `ohsome_query()` wrapper functions `ohsome_contributions_count()` for
51 | contributions aggregation endpoints of ohsome API
52 | * Added `ohsome_query()` wrapper function `ohsome_users_count()` for user
53 | aggregation endpoints of ohsome API
54 | * `ohsome_medata` and `ohsome_temporalExtent` are assigned on loading (not on
55 | attaching) the package
56 | * `ohsome_metadata$extractRegion$temporalExtent` and `ohsome_temporalExtent` are
57 | no longer converted to POSIXct, but provided as ISO 8601 strings
58 | * Added endpoint-specific check for missing required parameters to query
59 | validation
60 | * Added validation of JSON response content
61 | * Updated `README` to reflect new features, added hints on boundary polygon
62 | acquisition through third-party packages
63 | * Added `CITATION` file with reference to OSHDB/ohsome API and technical paper
64 |
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_boundary.R:
--------------------------------------------------------------------------------
1 | franconia <- suppressMessages(sf::st_set_crs(mapview::franconia, 4326))
2 | breweries <- suppressMessages(sf::st_set_crs(mapview::breweries, 4326))
3 |
4 | test_that("correctly detects boundary type for character objects", {
5 |
6 | bboxes1 <- paste(
7 | "8.5992,49.3567,8.7499,49.4371",
8 | "9.1638,49.113,9.2672,49.1766",
9 | sep = "|"
10 | )
11 | bboxes2 <- paste(
12 | "Heidelberg:8.5992,49.3567,8.7499,49.4371",
13 | "Heilbronn:9.1638,49.113,9.2672,49.1766",
14 | sep = "|"
15 | )
16 | bcircles1 <- paste(
17 | "8.6528,49.3683,1000",
18 | "8.7294,49.4376,1000",
19 | sep = "|"
20 | )
21 | bcircles2 <- paste(
22 | "Circle 1:8.6528,49.3683,1000",
23 | "Circle 2:8.7294,49.4376,1000",
24 | sep = "|"
25 | )
26 | bpolys1 <- paste(
27 | "8.65821,49.41129,8.65821,49.41825,8.70053,49.41825,8.70053,49.41129,8.65821,49.41129",
28 | "8.67817,49.42147,8.67817,49.4342,8.70053,49.4342,8.70053,49.42147,8.67817,49.42147",
29 | sep = "|"
30 | )
31 | bpolys2 = paste(
32 | "Region 1:8.65821,49.41129,8.65821,49.41825,8.70053,49.41825,8.70053,49.41129,8.65821,49.41129",
33 | "Region 2:8.67817,49.42147,8.67817,49.4342,8.70053,49.4342,8.70053,49.42147,8.67817,49.42147",
34 | sep = "|"
35 | )
36 | bpolys3 = '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"id":"Region 1"},"geometry":{"type":"Polygon","coordinates":[[[8.65821,49.41129],[8.65821,49.41825],[8.70053,49.41825],[8.70053,49.41129],[8.65821,49.41129]]]}},{"type":"Feature","properties":{"id":"Region 2"},"geometry":{"type":"Polygon","coordinates":[[[8.67817,49.42147],[8.67817,49.4342],[8.70053,49.4342],[8.70053,49.42147],[8.67817,49.42147]]]}}]}'
37 |
38 | expect_equal(ohsome_boundary(bboxes1)$type, "bboxes")
39 | expect_equal(ohsome_boundary(bboxes2)$type, "bboxes")
40 | expect_equal(ohsome_boundary(bcircles1)$type, "bcircles")
41 | expect_equal(ohsome_boundary(bcircles2)$type, "bcircles")
42 | expect_equal(ohsome_boundary(bpolys1)$type, "bpolys")
43 | expect_equal(ohsome_boundary(bpolys2)$type, "bpolys")
44 | expect_equal(ohsome_boundary(bpolys3)$type, "bpolys")
45 | })
46 |
47 | test_that("returns ohsome_boundary object", {
48 |
49 | bpolys <- paste(
50 | "8.65821,49.41129,8.65821,49.41825,8.70053,49.41825,8.70053,49.41129,8.65821,49.41129",
51 | "8.67817,49.42147,8.67817,49.4342,8.70053,49.4342,8.70053,49.42147,8.67817,49.42147",
52 | sep = "|"
53 | )
54 | expect_s3_class(ohsome_boundary(bpolys), "ohsome_boundary")
55 | })
56 |
57 | test_that("returns ohsome_boundary object with type = bpolys for sf boundaries", {
58 | expect_equal(ohsome_boundary(franconia)$type, "bpolys")
59 | })
60 |
61 | test_that("returns ohsome_boundary object with type = bboxes for bbox boundaries", {
62 | expect_equal(ohsome_boundary(sf::st_bbox(franconia))$type, "bboxes")
63 | })
64 |
65 | test_that("throws error on sf with point geometries only", {
66 | expect_error(ohsome_boundary(breweries))
67 | })
68 |
69 | test_that("issues warning for sf boundaries that contain polygon and other geoms", {
70 |
71 | skip_if_not_installed("dplyr")
72 |
73 | mixed <- dplyr::bind_rows(franconia, breweries)
74 | expect_warning(ohsome_boundary(mixed))
75 | })
76 |
77 | test_that("creates ohsome_boundary object from list of bboxes of various classes", {
78 |
79 | skip_if_not_installed("osmdata")
80 |
81 | bboxes1 <- c(
82 | "8.5992,49.3567,8.7499,49.4371",
83 | "9.1638,49.113,9.2672,49.1766"
84 | )
85 | # output of dput(osmdata::getbb("Berlin"))
86 | bboxes2 <- structure(
87 | c(13.088345, 52.3382448, 13.7611609, 52.6755087),
88 | dim = c(2L, 2L),
89 | dimnames = list(c("x", "y"), c("min", "max"))
90 | )
91 | bboxes3 <- sf::st_bbox(breweries)
92 |
93 | b <- ohsome_boundary(list(bboxes1, bboxes2, bboxes3))
94 | expect_s3_class(b, "ohsome_boundary")
95 | })
96 |
--------------------------------------------------------------------------------
/man/set_boundary.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/set_boundary.R
3 | \name{set_boundary}
4 | \alias{set_boundary}
5 | \title{Set boundary}
6 | \usage{
7 | set_boundary(query, boundary = NULL, ...)
8 | }
9 | \arguments{
10 | \item{query}{An \code{ohsome_query} object constructed with \code{\link[=ohsome_query]{ohsome_query()}} or
11 | any of its wrapper functions}
12 |
13 | \item{boundary}{Bounding geometries specified by WGS84 coordinates in the
14 | order \verb{lon,lat}. The geometries of \code{sf} are transformed to WGS84 if the CRS
15 | of the object is known. The following classes are supported:
16 | \itemize{
17 | \item \code{sf} with (MULTI)POLYGON geometries
18 | \item \code{sfc} with (MULTI)POLYGON geometries
19 | \item \code{sfg} with (MULTI)POLYGON geometries and WGS 84 coordinates
20 | \item \code{bbox} created with \code{\link[sf:st_bbox]{sf::st_bbox()}} or \code{\link[tmaptools:bb]{tmaptools::bb()}}
21 | \item \code{matrix} created with \code{\link[sp:bbox]{sp::bbox()}} or \code{\link[osmdata:getbb]{osmdata::getbb()}}
22 | \item \code{character} providing textual definitions of bounding polygons, boxes or
23 | circles as allowed by the ohsome API (see
24 | \href{https://docs.ohsome.org/ohsome-api/stable/boundaries.html}{ohsome API - Boundaries}
25 | ):
26 | \itemize{
27 | \item bboxes: WGS84 coordinates in the following format:
28 | \code{"id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|..."} OR
29 | \code{"lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|..."}
30 | \item bcircles: WGS84 coordinates + radius in meter in the following
31 | format: \code{"id1:lon,lat,r|id2:lon,lat,r|..."} OR
32 | \code{"lon,lat,r|lon,lat,r|..."}
33 | \item bpolys: WGS84 coordinates given as a list of coordinate pairs (as for
34 | bboxes) or GeoJSON FeatureCollection. The first point has to be the same
35 | as the last point and MultiPolygons are only supported in GeoJSON.
36 | }
37 | \item \code{list} of \code{bbox}, \code{matrix} or \code{character}. Bounding geometry types of all
38 | list elements must be the same. Does not work with GeoJSON
39 | FeatureCollections.
40 | }}
41 |
42 | \item{...}{Additional arguments other than \code{digits} are ignored.}
43 | }
44 | \value{
45 | An \code{ohsome_query} object. The object can be sent to the ohsome API
46 | with \code{\link[=ohsome_post]{ohsome_post()}}. It consists of the following elements:
47 | \itemize{
48 | \item \code{url}: The URL of the endpoint.
49 | \item \code{encode}: The way the information is encoded and then posted to the
50 | ohsome API. Set as \code{"form"}.
51 | \item \code{body}: The parameters of the query such as \code{format}, \code{filter} or
52 | \code{bpolys}.
53 | }
54 | }
55 | \description{
56 | Set or modify the spatial filter of an existing \code{ohsome_query} object
57 | }
58 | \details{
59 | \code{\link[=set_boundary]{set_boundary()}} adds a spatial filter to an \code{ohsome_query} object or
60 | replaces an existing one. The spatial filter of a query to the ohsome API can
61 | be defined as one or more polygons, bounding boxes or bounding circles.
62 | }
63 | \examples{
64 | # Query without boundary definition
65 | q <- ohsome_query(
66 | "elements/count/groupBy/boundary",
67 | filter = "building=*",
68 | time = "2022-01-01"
69 | )
70 |
71 | # Use franconia from the mapview package as bounding polygons
72 | \donttest{
73 | set_boundary(q, mapview::franconia, digits = 4)
74 | }
75 |
76 | # Use the bounding box of franconia
77 | \donttest{
78 | set_boundary(q, sf::st_bbox(mapview::franconia))
79 | }
80 |
81 | \dontrun{
82 | # Get bounding box of the city of Kigali from OSM
83 | set_boundary(q, osmdata::getbb("Kigali"))
84 | }
85 |
86 | # Definition of two named bounding circles
87 | set_boundary(q, c("Circle 1:8.6528,49.3683,1000", "Circle 2:8.7294,49.4376,1000"))
88 |
89 | }
90 | \seealso{
91 | \href{https://docs.ohsome.org/ohsome-api/v1/}{ohsome API documentation}
92 | }
93 |
--------------------------------------------------------------------------------
/R/ohsome_query.R:
--------------------------------------------------------------------------------
1 | #' Create an `ohsome_query` object
2 | #'
3 | #' Creates an `ohsome_query` object specifying the ohsome API endpoint and
4 | #' the request parameters.
5 | #'
6 | #' @inheritParams ohsome_boundary
7 | #' @inheritParams ohsome_post
8 | #' @param endpoint The path to the
9 | #' [ohsome API endpoint](https://docs.ohsome.org/ohsome-api/v1/endpoints.html).
10 | #' Either a single string (e.g. `"elements/count"`) or a vector of character
11 | #' in the right order (e.g. `c("elements", "count")`).
12 | #' @param grouping character; group type(s) for grouped aggregations (only
13 | #' available for queries to aggregation endpoints). The following group types
14 | #' are available:
15 | #' * `"boundary"` groups the result by the given boundaries that are defined
16 | #' through any of the `boundary` query parameters.
17 | #' * `"key"` groups the result by the given keys that are defined through the
18 | #' `groupByKeys` query parameter.
19 | #' * `"tag"` groups the result by the given tags that are defined through the
20 | #' `groupByKey` and `groupByValues` query parameters.
21 | #' * `"type"` groups the result by OSM element type.
22 | #' * `c("boundary", "tag")` groups the result by the given boundaries and
23 | #' tags.
24 | #'
25 | #' Not all of these group types are accepted by all of the aggregation
26 | #' endpoints. Check
27 | #' [Grouping](https://docs.ohsome.org/ohsome-api/v1/group-by.html)
28 | #' for available group types.
29 | #' @param ... Parameters of the request to the ohsome API endpoint.
30 | #' @return An `ohsome_query` object. The object can be sent to the ohsome API
31 | #' with [ohsome_post()]. It consists of the following elements:
32 | #' * `url`: The URL of the endpoint.
33 | #' * `encode`: The way the information is encoded and then posted to the
34 | #' ohsome API. Set as `"form"`.
35 | #' * `body`: The parameters of the query such as `format`, `filter` or
36 | #' `bpolys`.
37 | #' @seealso [ohsome API documentation](https://docs.ohsome.org/ohsome-api/v1/)
38 | #' @export
39 | #' @examples
40 | #' # Extract building geometries with manually set bboxes parameter
41 | #' ohsome_query(
42 | #' "elements/geometry",
43 | #' bboxes = "8.6,49.36,8.75,49.44",
44 | #' time = "2022-01-01",
45 | #' filter = "building=*"
46 | #' )
47 | #'
48 | #' # Extract building geometries using a boundary object:
49 | #' ohsome_query(
50 | #' "elements/geometry",
51 | #' boundary = "8.6,49.36,8.75,49.44",
52 | #' time = "2022-01-01",
53 | #' filter = "building=*"
54 | #' )
55 | #'
56 | ohsome_query <- function(
57 | endpoint,
58 | boundary = NULL,
59 | grouping = NULL,
60 | ...,
61 | validate = FALSE) {
62 |
63 | body <- lapply(list(...), paste, collapse=",")
64 | explicit_format <- !is.null(body[["format"]])
65 |
66 | if(
67 | !explicit_format &&
68 | !any(grepl("(centroid|bbox|geometry)", endpoint))
69 | ) {
70 | if(any(grepl("boundary", endpoint))) {
71 | body[["format"]] = "geojson"
72 | } else {
73 | body[["format"]] = "csv"
74 | }
75 | }
76 |
77 | query <- structure(
78 | list(
79 | url = build_endpoint_url(endpoint),
80 | encode = "form",
81 | body = body
82 | ),
83 | class = "ohsome_query"
84 | )
85 |
86 | if(!is.null(grouping)) {
87 | query <- set_grouping(query, grouping, reset_format = !explicit_format)
88 | }
89 |
90 | if(!is.null(boundary)) {
91 | btypes <- c("bpolys", "bboxes", "bcircles")
92 | check <- btypes %in% names(query$body)
93 | if(any(check)) warning(
94 | paste(
95 | "Boundary overwrites",
96 | paste(btypes[check], collapse = ", "),
97 | "parameter(s)."),
98 | call. = FALSE
99 | )
100 |
101 | query <- set_boundary(query, boundary)
102 |
103 | }
104 |
105 | if(validate) validate_query(query)
106 |
107 | return(query)
108 | }
109 |
--------------------------------------------------------------------------------
/man/ohsome_contributions_count.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_contributions_count.R
3 | \name{ohsome_contributions_count}
4 | \alias{ohsome_contributions_count}
5 | \title{Count OSM contributions}
6 | \usage{
7 | ohsome_contributions_count(
8 | boundary = NULL,
9 | latest = FALSE,
10 | return_value = c("absolute", "density"),
11 | time = NULL,
12 | ...
13 | )
14 | }
15 | \arguments{
16 | \item{boundary}{Bounding geometries specified by WGS84 coordinates in the
17 | order \verb{lon,lat}. The geometries of \code{sf} are transformed to WGS84 if the CRS
18 | of the object is known. The following classes are supported:
19 | \itemize{
20 | \item \code{sf} with (MULTI)POLYGON geometries
21 | \item \code{sfc} with (MULTI)POLYGON geometries
22 | \item \code{sfg} with (MULTI)POLYGON geometries and WGS 84 coordinates
23 | \item \code{bbox} created with \code{\link[sf:st_bbox]{sf::st_bbox()}} or \code{\link[tmaptools:bb]{tmaptools::bb()}}
24 | \item \code{matrix} created with \code{\link[sp:bbox]{sp::bbox()}} or \code{\link[osmdata:getbb]{osmdata::getbb()}}
25 | \item \code{character} providing textual definitions of bounding polygons, boxes or
26 | circles as allowed by the ohsome API (see
27 | \href{https://docs.ohsome.org/ohsome-api/stable/boundaries.html}{ohsome API - Boundaries}
28 | ):
29 | \itemize{
30 | \item bboxes: WGS84 coordinates in the following format:
31 | \code{"id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|..."} OR
32 | \code{"lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|..."}
33 | \item bcircles: WGS84 coordinates + radius in meter in the following
34 | format: \code{"id1:lon,lat,r|id2:lon,lat,r|..."} OR
35 | \code{"lon,lat,r|lon,lat,r|..."}
36 | \item bpolys: WGS84 coordinates given as a list of coordinate pairs (as for
37 | bboxes) or GeoJSON FeatureCollection. The first point has to be the same
38 | as the last point and MultiPolygons are only supported in GeoJSON.
39 | }
40 | \item \code{list} of \code{bbox}, \code{matrix} or \code{character}. Bounding geometry types of all
41 | list elements must be the same. Does not work with GeoJSON
42 | FeatureCollections.
43 | }}
44 |
45 | \item{latest}{logical; if \code{TRUE}, request only the latest contributions
46 | provided to each OSM element.}
47 |
48 | \item{return_value}{character; the value to be returned by the ohsome API:
49 | \itemize{
50 | \item \code{"absolute"} returns the absolute number of contributions. This is the
51 | default.
52 | \item \code{"density"} returns the number of contributions per square kilometer.
53 | }}
54 |
55 | \item{time}{character; \code{time} parameter of the query (see
56 | \href{https://docs.ohsome.org/ohsome-api/v1/time.html}{Supported time formats}).}
57 |
58 | \item{...}{Parameters of the request to the ohsome API endpoint.}
59 | }
60 | \value{
61 | An \code{ohsome_query} object. The object can be sent to the ohsome API
62 | with \code{\link[=ohsome_post]{ohsome_post()}}. It consists of the following elements:
63 | \itemize{
64 | \item \code{url}: The URL of the endpoint.
65 | \item \code{encode}: The way the information is encoded and then posted to the
66 | ohsome API. Set as \code{"form"}.
67 | \item \code{body}: The parameters of the query such as \code{format}, \code{filter} or
68 | \code{bpolys}.
69 | }
70 | }
71 | \description{
72 | Creates an \code{ohsome_query} object for OSM contributions count
73 | }
74 | \details{
75 | \code{ohsome_contributions_count()} creates an \code{ohsome_query} object for
76 | OSM element aggregation. Boundary objects are passed via \code{\link[=set_boundary]{set_boundary()}}
77 | into \code{\link[=ohsome_boundary]{ohsome_boundary()}}.
78 | }
79 | \examples{
80 | # Monthly counts of contributions to man-made objects around "Null Island"
81 | ohsome_contributions_count("0,0,10", filter = "man_made=*", time = "2010/2020/P1Y")
82 |
83 | # Monthly counts of latest contributions to man-made objects around "Null Island"
84 | ohsome_contributions_count(
85 | "0,0,10",
86 | latest = TRUE,
87 | filter = "man_made=*",
88 | time = "2010/2020/P1Y"
89 | )
90 |
91 | }
92 | \seealso{
93 | \href{https://docs.ohsome.org/ohsome-api/v1/endpoints.html#contributions-aggregation}{ohsome API Endpoints - Contributions Aggregation}
94 | }
95 |
--------------------------------------------------------------------------------
/tests/testthat/test-ohsome_parse.R:
--------------------------------------------------------------------------------
1 | # original query:
2 | # q <- ohsome_query(
3 | # c("elements", "count"),
4 | # filter = "shop=convenience",
5 | # bcircles = "13.45,52.5,1000",
6 | # format = "csv"
7 | # )
8 | # r <- ohsome_post(q, parse = FALSE, validate = FALSE)
9 |
10 | r <- readRDS("data/elements-count-shop-convenience-bcircles-csv.rds")
11 |
12 | test_that(
13 | 'returns data.frame by default when content CSV', {
14 | expect_s3_class(ohsome_parse(r), "data.frame")
15 | })
16 |
17 | test_that(
18 | 'converts timestamp to POSIXct in data.frame', {
19 | p <- ohsome_parse(r)
20 | expect_s3_class(p$timestamp, "POSIXct")
21 | })
22 |
23 | test_that(
24 | 'issues warning and returns data.frame if returnclass = "sf" and content not GeoJSON', {
25 | expect_warning(ohsome_parse(r, returnclass = "sf"))
26 | expect_s3_class(suppressWarnings(ohsome_parse(r, returnclass = "sf")), "data.frame")
27 | })
28 |
29 | test_that(
30 | 'returns list if returnclass = "list"', {
31 | expect_type(ohsome_parse(r, returnclass = "list"), "list")
32 | })
33 |
34 | test_that(
35 | 'returns character if returnclass = "character"', {
36 | expect_type(ohsome_parse(r, returnclass = "character"), "character")
37 | })
38 |
39 |
40 |
41 | # original query:
42 | # q <- ohsome_query(
43 | # c("elements", "centroid"),
44 | # filter = "shop=convenience",
45 | # bcircles = "13.45,52.5,1000"
46 | # )
47 | # r <- ohsome_post(q, parse = FALSE, validate = FALSE)
48 |
49 | r <- readRDS("data/elements-centroid-shop-convenience-bcircles.rds")
50 |
51 | test_that(
52 | 'returns sf by default when content GeoJSON', {
53 | expect_s3_class(ohsome_parse(r, returnclass = "sf"), "sf")
54 | })
55 |
56 | test_that(
57 | 'converts @snapshotTimestamp to POSIXct in sf objects', {
58 | p <- ohsome_parse(r)
59 | expect_s3_class(p$`@snapshotTimestamp`, "POSIXct")
60 | })
61 |
62 | test_that(
63 | 'returns data.frame when returnclass = "data.frame" and content GeoOJSON', {
64 | expect_s3_class(ohsome_parse(r, returnclass = "data.frame"), "data.frame")
65 | })
66 |
67 | test_that(
68 | 'returns list if returnclass = "list" and content GeoJSON', {
69 | expect_type(ohsome_parse(r, returnclass = "list"), "list")
70 | })
71 |
72 | test_that(
73 | 'does not issue warning if no geometries are omitted when omit_empty = TRUE', {
74 | expect_silent(ohsome_parse(r, returnclass = "sf", omit_empty = TRUE))
75 | })
76 |
77 | # original query:
78 | # q <- franconia |>
79 | # mutate(id = NUTS_ID) |>
80 | # ohsome_elements_count(filter = "building=*", time = "2015/2020", format = "csv") |>
81 | # set_endpoint("groupBy/boundary/groupBy/tag", reset_format = FALSE, append = TRUE) |>
82 | # set_groupByKey("building:levels")
83 | # r <- ohsome_post(q, parse = FALSE, validate = FALSE)
84 |
85 | r <- readRDS("data/elements-count-buildings-groupby-boundary-groupby-tag-csv.rds")
86 |
87 | test_that(
88 | 'succesfully parses csv response of groupBy/boundary/groupBy/tag query', {
89 | expect_s3_class(ohsome_parse(r), "data.frame")
90 | })
91 |
92 | # original query:
93 | # q <- ohsome_query(
94 | # "elementsFullHistory/geometry",
95 | # bboxes = "-180,-90,180,90",
96 | # filter = "id:way/625011340",
97 | # time = "2008-01-01,2020-01-01"
98 | # )
99 | # r <- ohsome_post(q, parse = FALSE, validate = FALSE)
100 |
101 | r <- readRDS("data/elements-fullHistory-geometry-id-way-625011340.rds")
102 |
103 | test_that(
104 | "parses GeoJSON FeatureCollection with faulty feature (way without nodes)", {
105 | expect_s3_class(
106 | suppressWarnings(ohsome_parse(r, returnclass = "sf")),
107 | "sf"
108 | )
109 | })
110 |
111 | test_that(
112 | "issues warning when omitting empty geometry features", {
113 | expect_warning(ohsome_parse(r, returnclass = "sf"))
114 | })
115 |
116 | # original query:
117 | # boundary <- "6.75,51.4,500000"
118 | # q <- ohsome_elements_count(boundary, filter = 'building=*', time = '2022-01')
119 | # r <- ohsome_post(q, parse = F)
120 |
121 | r <- readRDS("data/elements-count-buildings-csv.rds")
122 |
123 | test_that(
124 | "correctly converts scientific notation value", {
125 | p <- ohsome_parse(r)
126 | expect_equal(p$value[1], 67003817L)
127 | }
128 | )
129 |
--------------------------------------------------------------------------------
/man/set_endpoint.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/set_endpoint.R
3 | \name{set_endpoint}
4 | \alias{set_endpoint}
5 | \alias{set_grouping}
6 | \title{Set endpoint}
7 | \usage{
8 | set_endpoint(query, endpoint, append = FALSE, reset_format = TRUE)
9 |
10 | set_grouping(query, grouping, ...)
11 | }
12 | \arguments{
13 | \item{query}{An \code{ohsome_query} object constructed with \code{\link[=ohsome_query]{ohsome_query()}} or
14 | any of its wrapper functions}
15 |
16 | \item{endpoint}{The path to the
17 | \href{https://docs.ohsome.org/ohsome-api/v1/endpoints.html}{ohsome API endpoint}.
18 | Either a single string (e.g. \code{"elements/count"}) or a vector of character
19 | in the right order (e.g. \code{c("elements", "count")}).}
20 |
21 | \item{append}{logical; If \code{TRUE}, the provided endpoint string is appended to
22 | the existing endpoint definition instead of replacing it. This is
23 | particularly useful if you wish to add \code{density}/\code{ratio} and/or a grouping
24 | to an existing aggregation query.}
25 |
26 | \item{reset_format}{logical; if \code{TRUE}, the format parameter of the query is
27 | updated depending on the new endpoint.}
28 |
29 | \item{grouping}{character; group type(s) for grouped aggregations (only
30 | available for queries to aggregation endpoints). The following group types
31 | are available:
32 | \itemize{
33 | \item \code{"boundary"} groups the result by the given boundaries that are defined
34 | through any of the \code{boundary} query parameters.
35 | \item \code{"key"} groups the result by the given keys that are defined through the
36 | \code{groupByKeys} query parameter.
37 | \item \code{"tag"} groups the result by the given tags that are defined through the
38 | \code{groupByKey} and \code{groupByValues} query parameters.
39 | \item \code{"type"} groups the result by OSM element type.
40 | \item \code{c("boundary", "tag")} groups the result by the given boundaries and
41 | tags.
42 | }
43 |
44 | Not all of these group types are accepted by all of the aggregation
45 | endpoints. Check
46 | \href{https://docs.ohsome.org/ohsome-api/v1/group-by.html}{Grouping}
47 | for available group types.}
48 |
49 | \item{...}{Additional arguments passed to \code{set_endpoint()}}
50 | }
51 | \value{
52 | An \code{ohsome_query} object. The object can be sent to the ohsome API
53 | with \code{\link[=ohsome_post]{ohsome_post()}}. It consists of the following elements:
54 | \itemize{
55 | \item \code{url}: The URL of the endpoint.
56 | \item \code{encode}: The way the information is encoded and then posted to the
57 | ohsome API. Set as \code{"form"}.
58 | \item \code{body}: The parameters of the query such as \code{format}, \code{filter} or
59 | \code{bpolys}.
60 | }
61 | }
62 | \description{
63 | Modifies the endpoint of an existing \code{ohsome_query} object
64 | }
65 | \details{
66 | \code{set_endpoint()} takes an \code{ohsome_query} object and modifies the ohsome API
67 | endpoint. \code{set_grouping()} takes an \code{ohsome_query} object and modifies the
68 | endpoint path for grouped aggregations.
69 | }
70 | \examples{
71 | # Query for count of elements
72 | q <- ohsome_elements_count(
73 | boundary = "HD:8.5992,49.3567,8.7499,49.4371|HN:9.1638,49.113,9.2672,49.1766",
74 | time = "2022-01-01",
75 | filter = "highway=*"
76 | )
77 |
78 | # Modify query to aggregate length of elements instead of count
79 | set_endpoint(q, "elements/length")
80 |
81 | # Modify query to extract geometries instead of aggregating elements
82 | set_endpoint(q, "elements/geometry")
83 |
84 | # Append the endpoint path in order to group aggregation by boundary
85 | set_endpoint(q, "groupBy/boundary", append = TRUE)
86 |
87 | # Modify query to group aggregation by boundary
88 | set_grouping(q, grouping = "boundary")
89 |
90 | # Modify query to group by boundary, but keep format csv instead of geojson
91 | set_grouping(q, grouping = "boundary", reset_format = FALSE)
92 |
93 | # Append the endpoint path to query for element densities per boundary
94 | set_endpoint(q, c("density", "groupBy", "boundary"), append = TRUE)
95 |
96 | # Modify query to group aggregation by OSM element type
97 | set_grouping(q, grouping = "type")
98 |
99 | }
100 | \seealso{
101 | \href{https://docs.ohsome.org/ohsome-api/v1/endpoints.html}{ohsome API Endpoints}
102 | }
103 | \concept{Set endpoint}
104 |
--------------------------------------------------------------------------------
/man/ohsome_boundary.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_boundary.R
3 | \name{ohsome_boundary}
4 | \alias{ohsome_boundary}
5 | \alias{ohsome_boundary.ohsome_boundary}
6 | \alias{ohsome_boundary.character}
7 | \alias{ohsome_boundary.sf}
8 | \alias{ohsome_boundary.sfc}
9 | \alias{ohsome_boundary.sfg}
10 | \alias{ohsome_boundary.bbox}
11 | \alias{ohsome_boundary.matrix}
12 | \alias{ohsome_boundary.list}
13 | \title{Create an \code{ohsome_boundary} object}
14 | \usage{
15 | ohsome_boundary(boundary, ...)
16 |
17 | \method{ohsome_boundary}{ohsome_boundary}(boundary, ...)
18 |
19 | \method{ohsome_boundary}{character}(boundary, ...)
20 |
21 | \method{ohsome_boundary}{sf}(boundary, digits = 6, ...)
22 |
23 | \method{ohsome_boundary}{sfc}(boundary, ...)
24 |
25 | \method{ohsome_boundary}{sfg}(boundary, ...)
26 |
27 | \method{ohsome_boundary}{bbox}(boundary, ...)
28 |
29 | \method{ohsome_boundary}{matrix}(boundary, ...)
30 |
31 | \method{ohsome_boundary}{list}(boundary, ...)
32 | }
33 | \arguments{
34 | \item{boundary}{Bounding geometries specified by WGS84 coordinates in the
35 | order \verb{lon,lat}. The geometries of \code{sf} are transformed to WGS84 if the CRS
36 | of the object is known. The following classes are supported:
37 | \itemize{
38 | \item \code{sf} with (MULTI)POLYGON geometries
39 | \item \code{sfc} with (MULTI)POLYGON geometries
40 | \item \code{sfg} with (MULTI)POLYGON geometries and WGS 84 coordinates
41 | \item \code{bbox} created with \code{\link[sf:st_bbox]{sf::st_bbox()}} or \code{\link[tmaptools:bb]{tmaptools::bb()}}
42 | \item \code{matrix} created with \code{\link[sp:bbox]{sp::bbox()}} or \code{\link[osmdata:getbb]{osmdata::getbb()}}
43 | \item \code{character} providing textual definitions of bounding polygons, boxes or
44 | circles as allowed by the ohsome API (see
45 | \href{https://docs.ohsome.org/ohsome-api/stable/boundaries.html}{ohsome API - Boundaries}
46 | ):
47 | \itemize{
48 | \item bboxes: WGS84 coordinates in the following format:
49 | \code{"id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|..."} OR
50 | \code{"lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|..."}
51 | \item bcircles: WGS84 coordinates + radius in meter in the following
52 | format: \code{"id1:lon,lat,r|id2:lon,lat,r|..."} OR
53 | \code{"lon,lat,r|lon,lat,r|..."}
54 | \item bpolys: WGS84 coordinates given as a list of coordinate pairs (as for
55 | bboxes) or GeoJSON FeatureCollection. The first point has to be the same
56 | as the last point and MultiPolygons are only supported in GeoJSON.
57 | }
58 | \item \code{list} of \code{bbox}, \code{matrix} or \code{character}. Bounding geometry types of all
59 | list elements must be the same. Does not work with GeoJSON
60 | FeatureCollections.
61 | }}
62 |
63 | \item{...}{Additional arguments other than \code{digits} are ignored.}
64 |
65 | \item{digits}{integer; number of decimal places of coordinates in the
66 | resulting GeoJSON when converting \code{sf} to GeoJSON (defaults to 6).}
67 | }
68 | \value{
69 | An \code{ohsome_boundary} object which contains the following elements:
70 | \itemize{
71 | \item \code{boundary}: the boundary in textual format
72 | \item \code{type} of the boundary (\code{bpolys}, \code{bcircles}, or \code{bboxes}).
73 | }
74 | }
75 | \description{
76 | Creates an \code{ohsome_boundary} object from various classes of input geometries.
77 | The \code{ohsome_boundary} object is used to set the \code{bpolys}, \code{bboxes} or
78 | \code{bcircles} parameter of an \code{ohsome_query} object.
79 | }
80 | \examples{
81 | # Defintion of a bounding circle (lon,lat,radius in meters)
82 | ohsome_boundary("8.6528,49.3683,1000")
83 |
84 | # Definition of two named bounding circles
85 | ohsome_boundary("Circle 1:8.6528,49.3683,1000|Circle 2:8.7294,49.4376,1000")
86 |
87 | # Definition of two named bounding circles with a character vector
88 | ohsome_boundary(c("Circle 1:8.6528,49.3683,1000", "Circle 2:8.7294,49.4376,1000"))
89 |
90 | # Use franconia from the mapview package as bounding polygons
91 | \donttest{
92 | ohsome_boundary(mapview::franconia, digits = 4)
93 | }
94 |
95 | # Use the bounding box of franconia
96 | \donttest{
97 | ohsome_boundary(sf::st_bbox(mapview::franconia))
98 | }
99 |
100 | # Get bounding box of the city of Berlin from OSM
101 | \dontrun{
102 | ohsome_boundary(osmdata::getbb("Berlin"))
103 | }
104 |
105 | # Use a list of two bounding boxes
106 | \dontrun{
107 | ohsome_boundary(list(osmdata::getbb("Berlin"), sf::st_bbox(mapview::franconia)))
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/man/set_parameters.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/set_parameters.R
3 | \name{set_parameters}
4 | \alias{set_parameters}
5 | \alias{set_time}
6 | \alias{set_filter}
7 | \alias{set_groupByKeys}
8 | \alias{set_groupByKey}
9 | \alias{set_groupByValues}
10 | \alias{set_properties}
11 | \title{Set parameters}
12 | \usage{
13 | set_parameters(query, ...)
14 |
15 | set_time(query, time = query$body$time)
16 |
17 | set_filter(query, filter = query$body$filter, filter2 = query$body$filter2)
18 |
19 | set_groupByKeys(query, groupByKeys = query$body$groupByKeys)
20 |
21 | set_groupByKey(query, groupByKey = query$body$groupByKey)
22 |
23 | set_groupByValues(query, groupByValues = query$body$groupByValues)
24 |
25 | set_properties(query, properties = NULL)
26 | }
27 | \arguments{
28 | \item{query}{An \code{ohsome_query} object constructed with \code{\link[=ohsome_query]{ohsome_query()}} or
29 | any of its wrapper functions}
30 |
31 | \item{...}{Parameters of the request to the ohsome API endpoint.}
32 |
33 | \item{time}{character; \code{time} parameter of the query (see
34 | \href{https://docs.ohsome.org/ohsome-api/v1/time.html}{Supported time formats}).}
35 |
36 | \item{filter}{character; \code{filter} parameter of the query (see
37 | \href{https://docs.ohsome.org/ohsome-api/v1/filter.html}{Filter})}
38 |
39 | \item{filter2}{character; \code{filter2} parameter of a ratio query}
40 |
41 | \item{groupByKeys}{character; \code{groupByKeys} parameter of a \code{groupBy/key} query}
42 |
43 | \item{groupByKey}{character; \code{groupByKey} parameter of a \code{groupBy/tag} query}
44 |
45 | \item{groupByValues}{character; \code{groupByValues} parameter of a \code{groupBy/tag}
46 | query}
47 |
48 | \item{properties}{character; properties to be extracted with extraction
49 | queries:
50 | \itemize{
51 | \item \code{"tags"}, and/or
52 | \item \code{"metadata"} (i.e. \verb{@changesetId}, \verb{@lastEdit}, \verb{@osmType},
53 | \verb{@version}), and/or
54 | \item \code{"contributionTypes"} (i.e. \verb{@creation}, \verb{@tagChange}, \verb{@deletion}, and
55 | \verb{@geometryChange}; only for contributions extraction)
56 | }
57 |
58 | Multiple values can be provided as comma-separated character or as
59 | character vector. This defaults to \code{NULL} (removes \code{properties} parameter
60 | from the query body).}
61 | }
62 | \value{
63 | An \code{ohsome_query} object. The object can be sent to the ohsome API
64 | with \code{\link[=ohsome_post]{ohsome_post()}}. It consists of the following elements:
65 | \itemize{
66 | \item \code{url}: The URL of the endpoint.
67 | \item \code{encode}: The way the information is encoded and then posted to the
68 | ohsome API. Set as \code{"form"}.
69 | \item \code{body}: The parameters of the query such as \code{format}, \code{filter} or
70 | \code{bpolys}.
71 | }
72 | }
73 | \description{
74 | Sets or modifies parameters of an existing \code{ohsome_query} object
75 | }
76 | \details{
77 | \code{set_parameters()} takes an \code{ohsome_query} object and an arbitrary number of
78 | named parameters as an input. It sets or modifies these parameters in the
79 | \code{ohsome_query} and returns the modified object. \code{set_time()}, \code{set_filter()},
80 | \code{set_groupByKeys()}, \code{set_groupByKey()}, \code{set_groupByValues()} and
81 | \code{set_properties()} are wrapper functions to set specific parameters. By
82 | default, an unmodified \code{ohsome_query} object is returned. In order to remove
83 | a parameter from the query object, you can set the respective argument
84 | explicitly to \code{NULL} (e.g. \code{set_filter(query, filter = NULL)}).
85 | }
86 | \examples{
87 | # Query ratio grouped by boundary
88 | q1 <- ohsome_query(
89 | endpoint = "elements/count/ratio/groupBy/boundary",
90 | boundary = "HD:8.5992,49.3567,8.7499,49.4371|HN:9.1638,49.113,9.2672,49.1766"
91 | )
92 |
93 | # Add time, filter and format parameters
94 | q1 |>
95 | set_time("2021/2022/P3M") |>
96 | set_filter("building=*", filter2 = "building=* and building:levels=3") |>
97 | set_parameters(format = "csv")
98 |
99 | # Query elements area grouped by tag
100 | q2 <- ohsome_query(
101 | endpoint = "elements/area/groupBy/tag",
102 | boundary = "HD:8.5992,49.3567,8.7499,49.4371"
103 | )
104 |
105 | # Add time, filter and groupByKey parameters
106 | q2 |>
107 | set_time("2021/2022/P3M") |>
108 | set_filter("building=*") |>
109 | set_groupByKey("building:levels")
110 |
111 | }
112 | \seealso{
113 | \url{https://docs.ohsome.org/ohsome-api/v1/}
114 | }
115 | \concept{Set parameters}
116 |
--------------------------------------------------------------------------------
/man/ohsome_query.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_query.R
3 | \name{ohsome_query}
4 | \alias{ohsome_query}
5 | \title{Create an \code{ohsome_query} object}
6 | \usage{
7 | ohsome_query(endpoint, boundary = NULL, grouping = NULL, ..., validate = FALSE)
8 | }
9 | \arguments{
10 | \item{endpoint}{The path to the
11 | \href{https://docs.ohsome.org/ohsome-api/v1/endpoints.html}{ohsome API endpoint}.
12 | Either a single string (e.g. \code{"elements/count"}) or a vector of character
13 | in the right order (e.g. \code{c("elements", "count")}).}
14 |
15 | \item{boundary}{Bounding geometries specified by WGS84 coordinates in the
16 | order \verb{lon,lat}. The geometries of \code{sf} are transformed to WGS84 if the CRS
17 | of the object is known. The following classes are supported:
18 | \itemize{
19 | \item \code{sf} with (MULTI)POLYGON geometries
20 | \item \code{sfc} with (MULTI)POLYGON geometries
21 | \item \code{sfg} with (MULTI)POLYGON geometries and WGS 84 coordinates
22 | \item \code{bbox} created with \code{\link[sf:st_bbox]{sf::st_bbox()}} or \code{\link[tmaptools:bb]{tmaptools::bb()}}
23 | \item \code{matrix} created with \code{\link[sp:bbox]{sp::bbox()}} or \code{\link[osmdata:getbb]{osmdata::getbb()}}
24 | \item \code{character} providing textual definitions of bounding polygons, boxes or
25 | circles as allowed by the ohsome API (see
26 | \href{https://docs.ohsome.org/ohsome-api/stable/boundaries.html}{ohsome API - Boundaries}
27 | ):
28 | \itemize{
29 | \item bboxes: WGS84 coordinates in the following format:
30 | \code{"id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|..."} OR
31 | \code{"lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|..."}
32 | \item bcircles: WGS84 coordinates + radius in meter in the following
33 | format: \code{"id1:lon,lat,r|id2:lon,lat,r|..."} OR
34 | \code{"lon,lat,r|lon,lat,r|..."}
35 | \item bpolys: WGS84 coordinates given as a list of coordinate pairs (as for
36 | bboxes) or GeoJSON FeatureCollection. The first point has to be the same
37 | as the last point and MultiPolygons are only supported in GeoJSON.
38 | }
39 | \item \code{list} of \code{bbox}, \code{matrix} or \code{character}. Bounding geometry types of all
40 | list elements must be the same. Does not work with GeoJSON
41 | FeatureCollections.
42 | }}
43 |
44 | \item{grouping}{character; group type(s) for grouped aggregations (only
45 | available for queries to aggregation endpoints). The following group types
46 | are available:
47 | \itemize{
48 | \item \code{"boundary"} groups the result by the given boundaries that are defined
49 | through any of the \code{boundary} query parameters.
50 | \item \code{"key"} groups the result by the given keys that are defined through the
51 | \code{groupByKeys} query parameter.
52 | \item \code{"tag"} groups the result by the given tags that are defined through the
53 | \code{groupByKey} and \code{groupByValues} query parameters.
54 | \item \code{"type"} groups the result by OSM element type.
55 | \item \code{c("boundary", "tag")} groups the result by the given boundaries and
56 | tags.
57 | }
58 |
59 | Not all of these group types are accepted by all of the aggregation
60 | endpoints. Check
61 | \href{https://docs.ohsome.org/ohsome-api/v1/group-by.html}{Grouping}
62 | for available group types.}
63 |
64 | \item{...}{Parameters of the request to the ohsome API endpoint.}
65 |
66 | \item{validate}{logical; if \code{TRUE}, issues warning for invalid endpoint or
67 | invalid/missing query parameters.}
68 | }
69 | \value{
70 | An \code{ohsome_query} object. The object can be sent to the ohsome API
71 | with \code{\link[=ohsome_post]{ohsome_post()}}. It consists of the following elements:
72 | \itemize{
73 | \item \code{url}: The URL of the endpoint.
74 | \item \code{encode}: The way the information is encoded and then posted to the
75 | ohsome API. Set as \code{"form"}.
76 | \item \code{body}: The parameters of the query such as \code{format}, \code{filter} or
77 | \code{bpolys}.
78 | }
79 | }
80 | \description{
81 | Creates an \code{ohsome_query} object specifying the ohsome API endpoint and
82 | the request parameters.
83 | }
84 | \examples{
85 | # Extract building geometries with manually set bboxes parameter
86 | ohsome_query(
87 | "elements/geometry",
88 | bboxes = "8.6,49.36,8.75,49.44",
89 | time = "2022-01-01",
90 | filter = "building=*"
91 | )
92 |
93 | # Extract building geometries using a boundary object:
94 | ohsome_query(
95 | "elements/geometry",
96 | boundary = "8.6,49.36,8.75,49.44",
97 | time = "2022-01-01",
98 | filter = "building=*"
99 | )
100 |
101 | }
102 | \seealso{
103 | \href{https://docs.ohsome.org/ohsome-api/v1/}{ohsome API documentation}
104 | }
105 |
--------------------------------------------------------------------------------
/man/ohsome_users_count.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_users_count.R
3 | \name{ohsome_users_count}
4 | \alias{ohsome_users_count}
5 | \title{Count OSM users}
6 | \usage{
7 | ohsome_users_count(
8 | boundary = NULL,
9 | return_value = c("absolute", "density"),
10 | grouping = NULL,
11 | time = NULL,
12 | ...
13 | )
14 | }
15 | \arguments{
16 | \item{boundary}{Bounding geometries specified by WGS84 coordinates in the
17 | order \verb{lon,lat}. The geometries of \code{sf} are transformed to WGS84 if the CRS
18 | of the object is known. The following classes are supported:
19 | \itemize{
20 | \item \code{sf} with (MULTI)POLYGON geometries
21 | \item \code{sfc} with (MULTI)POLYGON geometries
22 | \item \code{sfg} with (MULTI)POLYGON geometries and WGS 84 coordinates
23 | \item \code{bbox} created with \code{\link[sf:st_bbox]{sf::st_bbox()}} or \code{\link[tmaptools:bb]{tmaptools::bb()}}
24 | \item \code{matrix} created with \code{\link[sp:bbox]{sp::bbox()}} or \code{\link[osmdata:getbb]{osmdata::getbb()}}
25 | \item \code{character} providing textual definitions of bounding polygons, boxes or
26 | circles as allowed by the ohsome API (see
27 | \href{https://docs.ohsome.org/ohsome-api/stable/boundaries.html}{ohsome API - Boundaries}
28 | ):
29 | \itemize{
30 | \item bboxes: WGS84 coordinates in the following format:
31 | \code{"id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|..."} OR
32 | \code{"lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|..."}
33 | \item bcircles: WGS84 coordinates + radius in meter in the following
34 | format: \code{"id1:lon,lat,r|id2:lon,lat,r|..."} OR
35 | \code{"lon,lat,r|lon,lat,r|..."}
36 | \item bpolys: WGS84 coordinates given as a list of coordinate pairs (as for
37 | bboxes) or GeoJSON FeatureCollection. The first point has to be the same
38 | as the last point and MultiPolygons are only supported in GeoJSON.
39 | }
40 | \item \code{list} of \code{bbox}, \code{matrix} or \code{character}. Bounding geometry types of all
41 | list elements must be the same. Does not work with GeoJSON
42 | FeatureCollections.
43 | }}
44 |
45 | \item{return_value}{character; the value to be returned by the ohsome API:
46 | \itemize{
47 | \item \code{"absolute"} returns the absolute number of users. This is the
48 | default.
49 | \item \code{"density"} returns the number of users per square kilometer.
50 | }}
51 |
52 | \item{grouping}{character; group type(s) for grouped aggregations (only
53 | available for queries to aggregation endpoints). The following group types
54 | are available:
55 | \itemize{
56 | \item \code{"boundary"} groups the result by the given boundaries that are defined
57 | through any of the \code{boundary} query parameters.
58 | \item \code{"key"} groups the result by the given keys that are defined through the
59 | \code{groupByKeys} query parameter.
60 | \item \code{"tag"} groups the result by the given tags that are defined through the
61 | \code{groupByKey} and \code{groupByValues} query parameters.
62 | \item \code{"type"} groups the result by OSM element type.
63 | \item \code{c("boundary", "tag")} groups the result by the given boundaries and
64 | tags.
65 | }
66 |
67 | Not all of these group types are accepted by all of the aggregation
68 | endpoints. Check
69 | \href{https://docs.ohsome.org/ohsome-api/v1/group-by.html}{Grouping}
70 | for available group types.}
71 |
72 | \item{time}{character; \code{time} parameter of the query (see
73 | \href{https://docs.ohsome.org/ohsome-api/v1/time.html}{Supported time formats}).}
74 |
75 | \item{...}{Parameters of the request to the ohsome API endpoint.}
76 | }
77 | \value{
78 | An \code{ohsome_query} object. The object can be sent to the ohsome API
79 | with \code{\link[=ohsome_post]{ohsome_post()}}. It consists of the following elements:
80 | \itemize{
81 | \item \code{url}: The URL of the endpoint.
82 | \item \code{encode}: The way the information is encoded and then posted to the
83 | ohsome API. Set as \code{"form"}.
84 | \item \code{body}: The parameters of the query such as \code{format}, \code{filter} or
85 | \code{bpolys}.
86 | }
87 | }
88 | \description{
89 | Create an \code{ohsome_query} object for OSM users count
90 | }
91 | \details{
92 | \code{ohsome_users_count()} creates an \code{ohsome_query} object for OSM users
93 | aggregation. Boundary objects are passed via \code{\link[=set_boundary]{set_boundary()}} into
94 | \code{\link[=ohsome_boundary]{ohsome_boundary()}}.
95 | }
96 | \examples{
97 | # Yearly count of users contributing to man-made objects around "Null Island"
98 | ohsome_users_count("0,0,10", filter = "man_made=*", time = "2012/2022/P1Y")
99 |
100 | }
101 | \seealso{
102 | \href{https://docs.ohsome.org/ohsome-api/stable/endpoints.html#users-aggregation}{ohsome API Endpoints -- Users Aggregation}
103 | }
104 |
--------------------------------------------------------------------------------
/R/ohsome_aggregate_elements.R:
--------------------------------------------------------------------------------
1 | #' Aggregate OSM elements
2 | #'
3 | #' Creates an `ohsome_query` object for OSM element aggregation
4 | #'
5 | #' `ohsome_aggregate_elements()` creates an `ohsome_query` object for
6 | #' OSM element aggregation. `ohsome_elements_count()`,
7 | #' `ohsome_elements_length()`, `ohsome_elements_perimeter()` and
8 | #' `ohsome_elements_area()` are wrapper functions for specific aggregation
9 | #' endpoints. Boundary objects are passed via [set_boundary()] into
10 | #' [ohsome_boundary()].
11 | #'
12 | #' @inherit ohsome_query params return
13 | #' @param aggregation character; aggregation type:
14 | #' * `"count"` returns the total number of elements. This is the default.
15 | #' * `"length"` returns the total length of elements in meters.
16 | #' * `"perimeter"` returns the total perimeter of elements in meters.
17 | #' * `"area"` returns the total area of elements in square meters.
18 | #' @param return_value character; the value to be returned by the ohsome API:
19 | #' * `"absolute"` returns the absolute number, length, perimeter or area of
20 | #' elements. This is the default.
21 | #' * `"density"` returns the number, length, perimeter or area (in meters!) of
22 | #' elements per square kilometer.
23 | #' * `"ratio"` returns an absolute `value` for elements satisfying the
24 | #' `filter` argument, an absolute `value2` for elements satisfying the
25 | #' `filter2` argument, and the `ratio` of `value2` to `value`.
26 | #' @param time character; `time` parameter of the query (see
27 | #' [Supported time formats](https://docs.ohsome.org/ohsome-api/v1/time.html)).
28 | #' @seealso [ohsome API Endpoints - Elements Aggregation](https://docs.ohsome.org/ohsome-api/stable/endpoints.html#elements-aggregation)
29 | #' @export
30 | #' @family Aggregate elements
31 | #' @examples
32 | #' \donttest{
33 | #' # Count of breweries in Franconia
34 | #' ohsome_aggregate_elements(
35 | #' mapview::franconia,
36 | #' aggregation = "count",
37 | #' filter = "craft=brewery",
38 | #' time = "2022-01-01"
39 | #' )
40 | #'
41 | #' ohsome_elements_count(
42 | #' mapview::franconia,
43 | #' filter = "craft=brewery",
44 | #' time = "2022-01-01"
45 | #' )
46 | #'
47 | #' # Monthly counts of breweries in Franconia from 2012 to 2022
48 | #' ohsome_elements_count(
49 | #' mapview::franconia,
50 | #' filter = "craft=brewery",
51 | #' time = "2012/2022/P1M"
52 | #' )
53 | #'
54 | #' # Count of breweries per district of Franconia
55 | #' ohsome_elements_count(
56 | #' mapview::franconia,
57 | #' filter = "craft=brewery",
58 | #' grouping = "boundary",
59 | #' time = "2022-01-01"
60 | #' )
61 | #'
62 | #' # Number of breweries per square kilometer
63 | #' ohsome_elements_count(
64 | #' mapview::franconia,
65 | #' filter = "craft=brewery",
66 | #' return_value = "density",
67 | #' time = "2022-01-01"
68 | #' )
69 | #'
70 | #' # Proportion of breweries that are microbreweries
71 | #' ohsome_elements_count(
72 | #' mapview::franconia,
73 | #' filter = "craft=brewery",
74 | #' filter2 = "craft=brewery and microbrewery=yes",
75 | #' return_value = "ratio",
76 | #' time = "2022-01-01"
77 | #' )
78 | #'
79 | #' # Total length of highway elements in Franconia
80 | #' ohsome_elements_length(
81 | #' mapview::franconia,
82 | #' filter = "highway=* and geometry:line",
83 | #' time = "2022-01-01"
84 | #' )
85 | #' }
86 | #'
87 | ohsome_aggregate_elements <- function(
88 | boundary = NULL,
89 | aggregation = c("count", "length", "perimeter", "area"),
90 | return_value = c("absolute", "density", "ratio"),
91 | grouping = NULL,
92 | time = NULL,
93 | ...
94 | ) {
95 | aggregation <- match.arg(aggregation)
96 | return_value <- match.arg(return_value)
97 | if(return_value == "absolute") return_value <- NULL
98 | q <- ohsome_query(c("elements", aggregation, return_value), boundary, grouping, ...)
99 | set_time(q, time)
100 | }
101 |
102 | #' @export
103 | #' @rdname ohsome_aggregate_elements
104 | ohsome_elements_count <- function(boundary = NULL, ...) {
105 | ohsome_aggregate_elements(boundary, aggregation = "count", ...)
106 | }
107 |
108 | #' @export
109 | #' @rdname ohsome_aggregate_elements
110 | ohsome_elements_length <- function(boundary = NULL, ...) {
111 | ohsome_aggregate_elements(boundary, aggregation = "length", ...)
112 | }
113 |
114 | #' @export
115 | #' @rdname ohsome_aggregate_elements
116 | ohsome_elements_perimeter <- function(boundary = NULL, ...) {
117 | ohsome_aggregate_elements(boundary, aggregation = "perimeter", ...)
118 | }
119 |
120 | #' @export
121 | #' @rdname ohsome_aggregate_elements
122 | ohsome_elements_area <- function(boundary = NULL, ...) {
123 | ohsome_aggregate_elements(boundary, aggregation = "area", ...)
124 | }
125 |
--------------------------------------------------------------------------------
/tests/testthat/test-validate.R:
--------------------------------------------------------------------------------
1 | # simple valid query:
2 | q <- ohsome_query(
3 | "elements/count",
4 | boundary = "0,0,1000",
5 | filter = "highway=*",
6 | time = "2020-01-01"
7 | )
8 |
9 | test_that("silent on valid query and returns true", {
10 | expect_silent(validate_query(q))
11 | expect_true(validate_query(q))
12 | })
13 |
14 | test_that("issues warning on unknown endpoint and returns false", {
15 | q <- set_endpoint(q, "foo")
16 | expect_warning(
17 | validate_query(q),
18 | regexp = "ohsome does not know endpoint foo"
19 | )
20 | expect_false(suppressWarnings(validate_query(q)))
21 | })
22 |
23 | test_that("issues warning on missing bounding geometry and returns fals", {
24 | q <- set_parameters(q, bcircles = NULL)
25 | expect_warning(
26 | validate_query(q),
27 | regexp = "bpolys, bboxes, or bcircles"
28 | )
29 | expect_false(suppressWarnings(validate_query(q)))
30 | })
31 |
32 | test_that("issues warning on unknown param", {
33 | q <- set_parameters(q, foo = "bar")
34 | expect_warning(
35 | validate_query(q),
36 | regexp = "foo is not a known parameter"
37 | )
38 | expect_false(suppressWarnings(validate_query(q)))
39 | })
40 |
41 | test_that("issues warning on missing required param", {
42 | q <- set_endpoint(q, "groupBy/key", append = TRUE)
43 | expect_warning(
44 | validate_query(q),
45 | regexp = "groupByKeys is a required parameter"
46 | )
47 | expect_false(suppressWarnings(validate_query(q)))
48 | })
49 |
50 | test_that("issues warning on defaulting time param", {
51 | q <- set_parameters(q, time = NULL)
52 | expect_warning(
53 | validate_query(q),
54 | regexp = "time parameter is not defined and defaults"
55 | )
56 | expect_false(suppressWarnings(validate_query(q)))
57 | })
58 |
59 | test_that("does not issue warn on missing time param when time has default", {
60 | q <- set_parameters(q, time = NULL)
61 | suppressWarnings(expect_failure(
62 | expect_warning(
63 | validate_query(q),
64 | regexp = "time is a required parameter"
65 | )
66 | ))
67 | expect_false(suppressWarnings(validate_query(q)))
68 | })
69 |
70 | test_that("does not warn on defaulting time param when time is required", {
71 | q <- set_endpoint(q, "elementsFullHistory/centroid")
72 | q <- set_parameters(q, time = NULL)
73 | suppressWarnings(expect_failure(
74 | expect_warning(
75 | validate_query(q),
76 | regexp = "time parameter is not defined and defaults"
77 | )
78 | ))
79 | expect_false(suppressWarnings(validate_query(q)))
80 | })
81 |
82 | test_that("issues warning on missing time param when time is required", {
83 | q <- set_endpoint(q, "elementsFullHistory/centroid")
84 | q <- set_parameters(q, time = NULL)
85 | expect_warning(
86 | validate_query(q),
87 | regexp = "time is a required parameter"
88 | )
89 | expect_false(suppressWarnings(validate_query(q)))
90 | })
91 |
92 | test_that("issues warning on missing filter param", {
93 | q <- set_parameters(q, filter = NULL)
94 | expect_warning(
95 | validate_query(q),
96 | regexp = "filter parameter is not defined"
97 | )
98 | expect_false(suppressWarnings(validate_query(q)))
99 | })
100 |
101 | test_that("issues warning on ratio query without filter2 param", {
102 | q <- set_endpoint(q, "ratio", append = TRUE)
103 | expect_warning(
104 | validate_query(q),
105 | regexp = "filter2 parameter needs to be defined in ratio queries."
106 | )
107 | expect_false(suppressWarnings(validate_query(q)))
108 | })
109 |
110 | test_that("issues specific warning on endpoint with unavailable grouping", {
111 | q <- set_endpoint(q, "groupBy/foo", append = TRUE)
112 | expect_warning(
113 | validate_query(q),
114 | regexp = "Only the following groupings are allowed with"
115 | )
116 | expect_false(suppressWarnings(validate_query(q)))
117 | })
118 |
119 | test_that("issues specific warning on endpoint that allows no grouping", {
120 | q <- ohsome_query("elements/geometry", grouping = "tag")
121 | expect_warning(
122 | validate_query(q),
123 | regexp = "Grouping is not allowed"
124 | )
125 | expect_false(suppressWarnings(validate_query(q)))
126 | })
127 |
128 | # original_query
129 | # q <- ohsome_elements_geometry(
130 | # rgeoboundaries::gb_adm0("Germany"),
131 | # filter ="amenity=hospital",
132 | # time="2022-01-01",
133 | # timeout = 200
134 | # )
135 | # r <- ohsome_post(q, parse = FALSE, validate = FALSE)
136 | # content <- httr::content(r, as = "text", encoding = "utf-8")
137 |
138 | content <- readRDS("data/elements-geometry-amenity-hospitals-Germany-content.rds")
139 |
140 | test_that(
141 | "issues specific warning on invalid JSON with 413 timeout message", {
142 | expect_warning(
143 | validate_json(content),
144 | "response content:\nThe given query is too large"
145 | )
146 | expect_false(suppressWarnings(validate_json(content)))
147 | }
148 | )
149 |
--------------------------------------------------------------------------------
/R/set_parameters.R:
--------------------------------------------------------------------------------
1 | #' Set parameters
2 | #'
3 | #' Sets or modifies parameters of an existing `ohsome_query` object
4 | #'
5 | #' `set_parameters()` takes an `ohsome_query` object and an arbitrary number of
6 | #' named parameters as an input. It sets or modifies these parameters in the
7 | #' `ohsome_query` and returns the modified object. `set_time()`, `set_filter()`,
8 | #' `set_groupByKeys()`, `set_groupByKey()`, `set_groupByValues()` and
9 | #' `set_properties()` are wrapper functions to set specific parameters. By
10 | #' default, an unmodified `ohsome_query` object is returned. In order to remove
11 | #' a parameter from the query object, you can set the respective argument
12 | #' explicitly to `NULL` (e.g. `set_filter(query, filter = NULL)`).
13 | #'
14 | #' @inherit ohsome_query params return
15 | #' @inheritParams ohsome_post
16 | #' @param time character; `time` parameter of the query (see
17 | #' [Supported time formats](https://docs.ohsome.org/ohsome-api/v1/time.html)).
18 | #' @param filter character; `filter` parameter of the query (see
19 | #' [Filter](https://docs.ohsome.org/ohsome-api/v1/filter.html))
20 | #' @param filter2 character; `filter2` parameter of a ratio query
21 | #' @param groupByKeys character; `groupByKeys` parameter of a `groupBy/key` query
22 | #' @param groupByKey character; `groupByKey` parameter of a `groupBy/tag` query
23 | #' @param groupByValues character; `groupByValues` parameter of a `groupBy/tag`
24 | #' query
25 | #' @param properties character; properties to be extracted with extraction
26 | #' queries:
27 | #' * `"tags"`, and/or
28 | #' * `"metadata"` (i.e. `@changesetId`, `@lastEdit`, `@osmType`,
29 | #' `@version`), and/or
30 | #' * `"contributionTypes"` (i.e. `@creation`, `@tagChange`, `@deletion`, and
31 | #' `@geometryChange`; only for contributions extraction)
32 | #'
33 | #' Multiple values can be provided as comma-separated character or as
34 | #' character vector. This defaults to `NULL` (removes `properties` parameter
35 | #' from the query body).
36 | #' @family Set parameters
37 | #' @seealso \url{https://docs.ohsome.org/ohsome-api/v1/}
38 | #' @export
39 | #' @examples
40 | #' # Query ratio grouped by boundary
41 | #' q1 <- ohsome_query(
42 | #' endpoint = "elements/count/ratio/groupBy/boundary",
43 | #' boundary = "HD:8.5992,49.3567,8.7499,49.4371|HN:9.1638,49.113,9.2672,49.1766"
44 | #' )
45 | #'
46 | #' # Add time, filter and format parameters
47 | #' q1 |>
48 | #' set_time("2021/2022/P3M") |>
49 | #' set_filter("building=*", filter2 = "building=* and building:levels=3") |>
50 | #' set_parameters(format = "csv")
51 | #'
52 | #' # Query elements area grouped by tag
53 | #' q2 <- ohsome_query(
54 | #' endpoint = "elements/area/groupBy/tag",
55 | #' boundary = "HD:8.5992,49.3567,8.7499,49.4371"
56 | #' )
57 | #'
58 | #' # Add time, filter and groupByKey parameters
59 | #' q2 |>
60 | #' set_time("2021/2022/P3M") |>
61 | #' set_filter("building=*") |>
62 | #' set_groupByKey("building:levels")
63 | #'
64 | set_parameters <- function(query, ...) {
65 |
66 | endpoint <- extract_endpoint(query)
67 | body <- query$body
68 |
69 | params <- list(...)
70 |
71 | if(length(params) > 0) {
72 | for(i in 1:length(params)) body[[names(params[i])]] <- params[[i]]
73 | }
74 |
75 | return(do.call(ohsome_query, c(endpoint, body)))
76 | }
77 |
78 | #' @export
79 | #' @rdname set_parameters
80 | set_time <- function(query, time = query$body$time) {
81 | set_parameters(query, time = time)
82 | }
83 |
84 | #' @export
85 | #' @rdname set_parameters
86 | set_filter <- function(query, filter = query$body$filter, filter2 = query$body$filter2) {
87 | set_parameters(query, filter = filter, filter2 = filter2)
88 | }
89 |
90 | #' @export
91 | #' @rdname set_parameters
92 | set_groupByKeys <- function(query, groupByKeys = query$body$groupByKeys) {
93 | set_parameters(query, groupByKeys = groupByKeys)
94 | }
95 |
96 | #' @export
97 | #' @rdname set_parameters
98 | set_groupByKey <- function(query, groupByKey = query$body$groupByKey) {
99 | set_parameters(query, groupByKey = groupByKey)
100 | }
101 |
102 | #' @export
103 | #' @rdname set_parameters
104 | set_groupByValues <- function(query, groupByValues = query$body$groupByValues) {
105 | set_parameters(query, groupByValues = groupByValues)
106 | }
107 |
108 | #' @export
109 | #' @rdname set_parameters
110 | set_properties <- function(query, properties = NULL) {
111 |
112 | if(is.null(properties)) return(set_parameters(query, properties = NULL))
113 |
114 | endpoint <- extract_endpoint(query)
115 | choices <- c("tags", "metadata")
116 | if(grepl("contributions", endpoint)) choices <- c(choices, "contributionTypes")
117 |
118 | properties <- gsub(" ", "", unlist(strsplit(properties, ",")))
119 | properties <- match.arg(properties, choices = choices, several.ok = TRUE)
120 | properties <- paste(properties, collapse = ",")
121 |
122 | set_parameters(query, properties = properties)
123 | }
124 |
--------------------------------------------------------------------------------
/man/ohsome_extract_elements.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_extract_elements.R
3 | \name{ohsome_extract_elements}
4 | \alias{ohsome_extract_elements}
5 | \alias{ohsome_elements_bbox}
6 | \alias{ohsome_elements_centroid}
7 | \alias{ohsome_elements_geometry}
8 | \title{Extract OSM elements}
9 | \usage{
10 | ohsome_extract_elements(
11 | boundary = NULL,
12 | geometryType = c("centroid", "bbox", "geometry"),
13 | time = NULL,
14 | properties = NULL,
15 | clipGeometry = TRUE,
16 | ...
17 | )
18 |
19 | ohsome_elements_bbox(boundary = NULL, ...)
20 |
21 | ohsome_elements_centroid(boundary = NULL, ...)
22 |
23 | ohsome_elements_geometry(boundary = NULL, ...)
24 | }
25 | \arguments{
26 | \item{boundary}{Bounding geometries specified by WGS84 coordinates in the
27 | order \verb{lon,lat}. The geometries of \code{sf} are transformed to WGS84 if the CRS
28 | of the object is known. The following classes are supported:
29 | \itemize{
30 | \item \code{sf} with (MULTI)POLYGON geometries
31 | \item \code{sfc} with (MULTI)POLYGON geometries
32 | \item \code{sfg} with (MULTI)POLYGON geometries and WGS 84 coordinates
33 | \item \code{bbox} created with \code{\link[sf:st_bbox]{sf::st_bbox()}} or \code{\link[tmaptools:bb]{tmaptools::bb()}}
34 | \item \code{matrix} created with \code{\link[sp:bbox]{sp::bbox()}} or \code{\link[osmdata:getbb]{osmdata::getbb()}}
35 | \item \code{character} providing textual definitions of bounding polygons, boxes or
36 | circles as allowed by the ohsome API (see
37 | \href{https://docs.ohsome.org/ohsome-api/stable/boundaries.html}{ohsome API - Boundaries}
38 | ):
39 | \itemize{
40 | \item bboxes: WGS84 coordinates in the following format:
41 | \code{"id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|..."} OR
42 | \code{"lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|..."}
43 | \item bcircles: WGS84 coordinates + radius in meter in the following
44 | format: \code{"id1:lon,lat,r|id2:lon,lat,r|..."} OR
45 | \code{"lon,lat,r|lon,lat,r|..."}
46 | \item bpolys: WGS84 coordinates given as a list of coordinate pairs (as for
47 | bboxes) or GeoJSON FeatureCollection. The first point has to be the same
48 | as the last point and MultiPolygons are only supported in GeoJSON.
49 | }
50 | \item \code{list} of \code{bbox}, \code{matrix} or \code{character}. Bounding geometry types of all
51 | list elements must be the same. Does not work with GeoJSON
52 | FeatureCollections.
53 | }}
54 |
55 | \item{geometryType}{character; type of geometry to be extracted:
56 | \itemize{
57 | \item \code{"centroid"},
58 | \item \code{"bboxes"} (bounding boxes), or
59 | \item \code{"geometry"}
60 | }
61 |
62 | Caveat: Node elements are omitted from results in queries for bounding
63 | boxes.}
64 |
65 | \item{time}{character; \code{time} parameter of the query (see
66 | \href{https://docs.ohsome.org/ohsome-api/v1/time.html}{Supported time formats}).}
67 |
68 | \item{properties}{character; properties to be extracted with the features:
69 | \itemize{
70 | \item \code{"tags"}, and/or
71 | \item \code{"metadata"} (i.e. \verb{@changesetId}, \verb{@lastEdit}, \verb{@osmType}, and
72 | \verb{@version})
73 | }
74 |
75 | Multiple values can be provided as comma-separated character or as
76 | character vector. This defaults to \code{NULL} (provides \verb{@osmId}).}
77 |
78 | \item{clipGeometry}{logical; specifies whether the returned geometries should
79 | be clipped to the query’s spatial boundary}
80 |
81 | \item{...}{Parameters of the request to the ohsome API endpoint.}
82 | }
83 | \value{
84 | An \code{ohsome_query} object. The object can be sent to the ohsome API
85 | with \code{\link[=ohsome_post]{ohsome_post()}}. It consists of the following elements:
86 | \itemize{
87 | \item \code{url}: The URL of the endpoint.
88 | \item \code{encode}: The way the information is encoded and then posted to the
89 | ohsome API. Set as \code{"form"}.
90 | \item \code{body}: The parameters of the query such as \code{format}, \code{filter} or
91 | \code{bpolys}.
92 | }
93 | }
94 | \description{
95 | Create an \code{ohsome_query} object for OSM element extraction
96 | }
97 | \details{
98 | \code{ohsome_extract_elements()} creates an \code{ohsome_query} object for OSM element
99 | extraction. \code{ohsome_elements_bbox()}, \code{ohsome_elements_centroid()} and
100 | \code{ohsome_elements_geometry()} are wrapper functions for specific elements
101 | extraction endpoints. Boundary objects are passed via \code{\link[=set_boundary]{set_boundary()}} into
102 | \code{\link[=ohsome_boundary]{ohsome_boundary()}}.
103 | }
104 | \examples{
105 | # Extract geometries, metadata and tags of man-made objects around "Null Island":
106 | ohsome_elements_geometry(
107 | "0,0,10",
108 | filter = "man_made=*",
109 | time = "2022-01-01",
110 | properties = c("metadata", "tags")
111 | )
112 |
113 | }
114 | \seealso{
115 | \href{https://docs.ohsome.org/ohsome-api/stable/endpoints.html#elements-extraction}{ohsome API Endpoints -- Elements Extraction}
116 | }
117 | \concept{Extract elements}
118 |
--------------------------------------------------------------------------------
/man/ohsome_extract_elementsFullHistory.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_extract_elementsFullHistory.R
3 | \name{ohsome_extract_elementsFullHistory}
4 | \alias{ohsome_extract_elementsFullHistory}
5 | \alias{ohsome_elementsFullHistory_bbox}
6 | \alias{ohsome_elementsFullHistory_centroid}
7 | \alias{ohsome_elementsFullHistory_geometry}
8 | \title{Extract OSM elements' full history}
9 | \usage{
10 | ohsome_extract_elementsFullHistory(
11 | boundary = NULL,
12 | geometryType = c("centroid", "bbox", "geometry"),
13 | time = NULL,
14 | properties = NULL,
15 | clipGeometry = TRUE,
16 | ...
17 | )
18 |
19 | ohsome_elementsFullHistory_bbox(boundary = NULL, ...)
20 |
21 | ohsome_elementsFullHistory_centroid(boundary = NULL, ...)
22 |
23 | ohsome_elementsFullHistory_geometry(boundary = NULL, ...)
24 | }
25 | \arguments{
26 | \item{boundary}{Bounding geometries specified by WGS84 coordinates in the
27 | order \verb{lon,lat}. The geometries of \code{sf} are transformed to WGS84 if the CRS
28 | of the object is known. The following classes are supported:
29 | \itemize{
30 | \item \code{sf} with (MULTI)POLYGON geometries
31 | \item \code{sfc} with (MULTI)POLYGON geometries
32 | \item \code{sfg} with (MULTI)POLYGON geometries and WGS 84 coordinates
33 | \item \code{bbox} created with \code{\link[sf:st_bbox]{sf::st_bbox()}} or \code{\link[tmaptools:bb]{tmaptools::bb()}}
34 | \item \code{matrix} created with \code{\link[sp:bbox]{sp::bbox()}} or \code{\link[osmdata:getbb]{osmdata::getbb()}}
35 | \item \code{character} providing textual definitions of bounding polygons, boxes or
36 | circles as allowed by the ohsome API (see
37 | \href{https://docs.ohsome.org/ohsome-api/stable/boundaries.html}{ohsome API - Boundaries}
38 | ):
39 | \itemize{
40 | \item bboxes: WGS84 coordinates in the following format:
41 | \code{"id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|..."} OR
42 | \code{"lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|..."}
43 | \item bcircles: WGS84 coordinates + radius in meter in the following
44 | format: \code{"id1:lon,lat,r|id2:lon,lat,r|..."} OR
45 | \code{"lon,lat,r|lon,lat,r|..."}
46 | \item bpolys: WGS84 coordinates given as a list of coordinate pairs (as for
47 | bboxes) or GeoJSON FeatureCollection. The first point has to be the same
48 | as the last point and MultiPolygons are only supported in GeoJSON.
49 | }
50 | \item \code{list} of \code{bbox}, \code{matrix} or \code{character}. Bounding geometry types of all
51 | list elements must be the same. Does not work with GeoJSON
52 | FeatureCollections.
53 | }}
54 |
55 | \item{geometryType}{character; type of geometry to be extracted:
56 | \itemize{
57 | \item \code{"centroid"},
58 | \item \code{"bboxes"} (bounding boxes), or
59 | \item \code{"geometry"}
60 | }
61 |
62 | Caveat: Node elements are omitted from results in queries for bounding
63 | boxes.}
64 |
65 | \item{time}{character; \code{time} parameter of the query (see
66 | \href{https://docs.ohsome.org/ohsome-api/v1/time.html}{Supported time formats}).}
67 |
68 | \item{properties}{character; properties to be extracted with the features:
69 | \itemize{
70 | \item \code{"tags"}, and/or
71 | \item \code{"metadata"} (i.e. \verb{@changesetId}, \verb{@lastEdit}, \verb{@osmType}, and
72 | \verb{@version})
73 | }
74 |
75 | Multiple values can be provided as comma-separated character or as
76 | character vector. This defaults to \code{NULL} (provides \verb{@osmId}).}
77 |
78 | \item{clipGeometry}{logical; specifies whether the returned geometries should
79 | be clipped to the query’s spatial boundary}
80 |
81 | \item{...}{Parameters of the request to the ohsome API endpoint.}
82 | }
83 | \value{
84 | An \code{ohsome_query} object. The object can be sent to the ohsome API
85 | with \code{\link[=ohsome_post]{ohsome_post()}}. It consists of the following elements:
86 | \itemize{
87 | \item \code{url}: The URL of the endpoint.
88 | \item \code{encode}: The way the information is encoded and then posted to the
89 | ohsome API. Set as \code{"form"}.
90 | \item \code{body}: The parameters of the query such as \code{format}, \code{filter} or
91 | \code{bpolys}.
92 | }
93 | }
94 | \description{
95 | Creates an \code{ohsome_query} object for the extraction of OSM elements' full
96 | history
97 | }
98 | \details{
99 | \code{ohsome_extract_elementsFullHistory()} creates an \code{ohsome_query} object for OSM
100 | element full history extraction. \code{ohsome_elementsFullHistory_bbox()},
101 | \code{ohsome_elementsFullHistory_centroid()} and
102 | \code{ohsome_elementsFullHistory_geometry()} are wrapper functions for specific
103 | elementsFullHistory extraction endpoints. Boundary objects are passed via
104 | \code{\link[=set_boundary]{set_boundary()}} into \code{\link[=ohsome_boundary]{ohsome_boundary()}}.
105 | }
106 | \examples{
107 |
108 | # Extract full history of building geometries around Heidelberg main station:
109 | ohsome_elementsFullHistory_geometry(
110 | boundary = "8.67542,49.40347,1000",
111 | time = "2012,2022",
112 | filter = "building=* and geometry:polygon",
113 | clipGeometry = FALSE
114 | )
115 | }
116 | \seealso{
117 | \href{https://docs.ohsome.org/ohsome-api/v1/endpoints.html#elements-full-history-extraction}{ohsome API Endpoints -- Elements Full History Extraction}
118 | }
119 | \concept{Extract elements full History}
120 |
--------------------------------------------------------------------------------
/man/ohsome_extract_contributions.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_extract_contributions.R
3 | \name{ohsome_extract_contributions}
4 | \alias{ohsome_extract_contributions}
5 | \alias{ohsome_contributions_bbox}
6 | \alias{ohsome_contributions_centroid}
7 | \alias{ohsome_contributions_geometry}
8 | \title{Extract OSM contributions}
9 | \usage{
10 | ohsome_extract_contributions(
11 | boundary = NULL,
12 | geometryType = c("centroid", "bbox", "geometry"),
13 | latest = FALSE,
14 | time = NULL,
15 | properties = NULL,
16 | clipGeometry = TRUE,
17 | ...
18 | )
19 |
20 | ohsome_contributions_bbox(boundary = NULL, ...)
21 |
22 | ohsome_contributions_centroid(boundary = NULL, ...)
23 |
24 | ohsome_contributions_geometry(boundary = NULL, ...)
25 | }
26 | \arguments{
27 | \item{boundary}{Bounding geometries specified by WGS84 coordinates in the
28 | order \verb{lon,lat}. The geometries of \code{sf} are transformed to WGS84 if the CRS
29 | of the object is known. The following classes are supported:
30 | \itemize{
31 | \item \code{sf} with (MULTI)POLYGON geometries
32 | \item \code{sfc} with (MULTI)POLYGON geometries
33 | \item \code{sfg} with (MULTI)POLYGON geometries and WGS 84 coordinates
34 | \item \code{bbox} created with \code{\link[sf:st_bbox]{sf::st_bbox()}} or \code{\link[tmaptools:bb]{tmaptools::bb()}}
35 | \item \code{matrix} created with \code{\link[sp:bbox]{sp::bbox()}} or \code{\link[osmdata:getbb]{osmdata::getbb()}}
36 | \item \code{character} providing textual definitions of bounding polygons, boxes or
37 | circles as allowed by the ohsome API (see
38 | \href{https://docs.ohsome.org/ohsome-api/stable/boundaries.html}{ohsome API - Boundaries}
39 | ):
40 | \itemize{
41 | \item bboxes: WGS84 coordinates in the following format:
42 | \code{"id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|..."} OR
43 | \code{"lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|..."}
44 | \item bcircles: WGS84 coordinates + radius in meter in the following
45 | format: \code{"id1:lon,lat,r|id2:lon,lat,r|..."} OR
46 | \code{"lon,lat,r|lon,lat,r|..."}
47 | \item bpolys: WGS84 coordinates given as a list of coordinate pairs (as for
48 | bboxes) or GeoJSON FeatureCollection. The first point has to be the same
49 | as the last point and MultiPolygons are only supported in GeoJSON.
50 | }
51 | \item \code{list} of \code{bbox}, \code{matrix} or \code{character}. Bounding geometry types of all
52 | list elements must be the same. Does not work with GeoJSON
53 | FeatureCollections.
54 | }}
55 |
56 | \item{geometryType}{character; type of geometry to be extracted:
57 | \itemize{
58 | \item \code{"centroid"},
59 | \item \code{"bboxes"} (bounding boxes), or
60 | \item \code{"geometry"}
61 | }
62 |
63 | Caveat: Node elements are omitted from results in queries for bounding
64 | boxes.}
65 |
66 | \item{latest}{logical; if \code{TRUE}, request only the latest contributions
67 | provided to each OSM element.}
68 |
69 | \item{time}{character; \code{time} parameter of the query (see
70 | \href{https://docs.ohsome.org/ohsome-api/v1/time.html}{Supported time formats}).}
71 |
72 | \item{properties}{character; properties to be extracted with the
73 | contributions:
74 | \itemize{
75 | \item \code{"tags"}, and/or
76 | \item \code{"metadata"} (i.e. \verb{@changesetId}, \verb{@lastEdit}, \verb{@osmType},
77 | \verb{@version}), and/or
78 | \item \code{"contributionTypes"} (i.e. \verb{@creation}, \verb{@tagChange}, \verb{@deletion}, and
79 | \verb{@geometryChange})
80 | }
81 |
82 | Multiple values can be provided as comma-separated character or as
83 | character vector. This defaults to \code{NULL} (provides
84 | \verb{@contributionChangesetId}, \verb{@osmId} and \verb{@timestamp}).}
85 |
86 | \item{clipGeometry}{logical; specifies whether the returned geometries should
87 | be clipped to the query’s spatial boundary}
88 |
89 | \item{...}{Parameters of the request to the ohsome API endpoint.}
90 | }
91 | \value{
92 | An \code{ohsome_query} object. The object can be sent to the ohsome API
93 | with \code{\link[=ohsome_post]{ohsome_post()}}. It consists of the following elements:
94 | \itemize{
95 | \item \code{url}: The URL of the endpoint.
96 | \item \code{encode}: The way the information is encoded and then posted to the
97 | ohsome API. Set as \code{"form"}.
98 | \item \code{body}: The parameters of the query such as \code{format}, \code{filter} or
99 | \code{bpolys}.
100 | }
101 | }
102 | \description{
103 | Creates an \code{ohsome_query} object for OSM contribution extraction
104 | }
105 | \details{
106 | \code{ohsome_extract_contributions()} creates an \code{ohsome_query} object for OSM
107 | contribution extraction. \code{ohsome_contributions_bbox()},
108 | \code{ohsome_contributions_centroid()} and \code{ohsome_contributions_geometry()}
109 | are wrapper functions for specific contributions extraction endpoints.
110 | Boundary objects are passed via \code{\link[=set_boundary]{set_boundary()}} into \code{\link[=ohsome_boundary]{ohsome_boundary()}}.
111 | }
112 | \examples{
113 | # Extract contributions to man-made objects around "Null Island" with metadata:
114 | ohsome_contributions_geometry(
115 | "0,0,10",
116 | filter = "man_made=*",
117 | time = c("2021-01-01", "2022-01-01"),
118 | properties = "metadata"
119 | )
120 |
121 | }
122 | \seealso{
123 | \href{https://docs.ohsome.org/ohsome-api/stable/endpoints.html#contributions-extraction}{ohsome API Endpoints -- Contributions Extraction}
124 | }
125 | \concept{Extract contributions}
126 |
--------------------------------------------------------------------------------
/R/ohsome_parse.R:
--------------------------------------------------------------------------------
1 | #' Parse content from an ohsome API response
2 | #'
3 | #' Extracts and parses the content from an ohsome API response
4 | #'
5 | #' `ohsome_parse()` parses an `ohsome_response` object into an object of the
6 | #' specified class. By default, this is an `sf` object if the ohsome API
7 | #' response contains GeoJSON data or a `data.frame` if it does not.
8 | #' `ohsome_sf()` and `ohsome_df()` wrapper functions for specific return
9 | #' classes.
10 | #'
11 | #' @param response An `ohsome_response` object
12 | #' @param returnclass character; one of the following:
13 | #' * `"default"` returns `sf` if the `ohsome_response` contains GeoJSON, or
14 | #' else a `data.frame`.
15 | #' * `"sf"` returns `sf` if the `ohsome_response` contains GeoJSON, else
16 | #' issues a warning and returns a `data.frame`.
17 | #' * `"data.frame"` returns a `data.frame`.
18 | #' * `"list"` returns a `list`.
19 | #' * `"character"` returns the ohsome API response body as text (JSON or
20 | #' semicolon-separated values)
21 | #' @param omit_empty logical; omit features with empty geometries (only if
22 | #' `returnclass = "sf"`)
23 | #' @family Extract and parse the content from an ohsome API response
24 | #' @return An `sf` object, a `data.frame`, a `list` or a `character`
25 | #' @export
26 | #' @examples
27 | #' \dontrun{
28 | #' # Create and send a query to ohsome API
29 | #' r <- ohsome_query("elements/centroid", filter = "amenity=*") |>
30 | #' set_boundary(osmdata::getbb("Heidelberg")) |>
31 | #' set_time("2021") |>
32 | #' set_properties("metadata") |>
33 | #' ohsome_post(parse = FALSE)
34 | #'
35 | #' # Parse response to object of default class (here: sf)
36 | #' ohsome_parse(r)
37 | #'
38 | #' # Parse response to data.frame
39 | #' ohsome_df(r)
40 | #'
41 | #' # Parse response to sf
42 | #' ohsome_sf(r)
43 | #' }
44 | #'
45 | ohsome_parse <- function(
46 | response,
47 | returnclass = c("default", "sf", "data.frame", "list", "character"),
48 | omit_empty = TRUE
49 | ) {
50 |
51 | returnclass <- match.arg(returnclass)
52 |
53 | type <- httr::http_type(response)
54 | content <- httr::content(response, as = "text", encoding = "utf-8")
55 |
56 | if(returnclass == "character") {
57 |
58 | return(content)
59 |
60 | } else if(
61 | type == "application/json" &&
62 | grepl('\"type\" : \"FeatureCollection\"', content) ||
63 | type == "application/geo+json"
64 |
65 | ) {
66 | if(!validate_json(content)) {
67 | warning("Invalid JSON in ohsome API response. Returning character.")
68 | return(content)
69 | }
70 |
71 | content <- jsonlite::minify(content)
72 | pattern <- '\"(Multi)?(Point|LineString|Polygon)\",\"coordinates\":\\[+\\]+'
73 | loc <- gregexpr(pattern = pattern, text = content)
74 | empty_coords <- sapply(loc, function(x) {
75 | match.length <- attr(x, "match.length")
76 | length(match.length[match.length > 0])
77 | })
78 |
79 |
80 | if(empty_coords > 0) {
81 | content <- gsub(pattern, '"Point","coordinates":[360, 360]', content)
82 | }
83 |
84 | p <- geojsonsf::geojson_sf(content)
85 |
86 | if(empty_coords > 0) {
87 | i <- suppressWarnings(suppressMessages(
88 | sf::st_intersects(
89 | p,
90 | sf::st_point(rep(360, 2)),
91 | sparse = FALSE
92 | )))
93 | p[i, "geometry"] <- NULL
94 | }
95 |
96 | if(returnclass == "data.frame") {
97 | return(convert_quietly(sf::st_drop_geometry(p)))
98 | } else if(returnclass == "list") {
99 | return(as.list(sf::st_sf(convert_quietly(as.data.frame(p)))))
100 | } else {
101 |
102 | empty <- sf::st_is_empty(p)
103 | if(omit_empty & sum(empty) > 0) {
104 | p <- subset(p, !sf::st_is_empty(p))
105 | warning(
106 | paste(sum(empty), "element(s) with empty geometries omitted."),
107 | call. = FALSE
108 | )
109 | }
110 |
111 | return(sf::st_sf(convert_quietly(as.data.frame(p))))
112 | }
113 |
114 | } else if(type == "application/json") {
115 |
116 | if(!validate_json(content)) {
117 | warning("Invalid JSON in ohsome API response. Returning character.")
118 | return(content)
119 | }
120 |
121 | p <- jsonlite::fromJSON(content, simplifyVector = TRUE)
122 |
123 | if(returnclass == "list") {
124 | return(p)
125 | } else {
126 | if(returnclass == "sf") {
127 | warning(
128 | "No geodata in ohsome API response. Returning data.frame ",
129 | "instead of sf."
130 | )
131 | }
132 |
133 | return(convert_quietly(as.data.frame(p)))
134 | }
135 |
136 | } else if(type == "text/csv") {
137 |
138 | p <- utils::read.csv2(
139 | textConnection(content),
140 | comment.char = "#",
141 | header = TRUE,
142 | stringsAsFactors = FALSE
143 | )
144 |
145 | if(returnclass == "list") {
146 | return(as.list(convert_quietly(p)))
147 | } else {
148 | if(returnclass == "sf") {
149 | warning(
150 | "No geodata in ohsome API response. Returning data.frame ",
151 | "instead of sf."
152 | )
153 | }
154 |
155 | return(convert_quietly(p))
156 | }
157 | } else {
158 | stop("ohsome API response content is neither of type (Geo)JSON nor CSV.")
159 | }
160 | }
161 |
162 | #' @export
163 | #' @rdname ohsome_parse
164 | ohsome_sf <- function(response, omit_empty = TRUE) {
165 | ohsome_parse(response, returnclass = "sf", omit_empty = omit_empty)
166 | }
167 |
168 | #' @export
169 | #' @rdname ohsome_parse
170 | ohsome_df <- function(response, omit_empty = TRUE) {
171 | ohsome_parse(response, returnclass = "data.frame", omit_empty = omit_empty)
172 | }
173 |
--------------------------------------------------------------------------------
/R/validate.R:
--------------------------------------------------------------------------------
1 | #' Validate parameters
2 | #'
3 | #' Checks if the specified parameters in a request body are valid and issues a
4 | #' warning if not. Returns a logical that indicates the validity of the
5 | #' parameters.
6 | #'
7 | #' @inherit validate_query return
8 | #' @param endpoint The path to the ohsome API endpoint as a single string
9 | #' (e.g. `"elements/count"`)
10 | #' @param body A list of named parameters to the ohsome API request
11 | #' @keywords Internal
12 | #' @noRd
13 | validate_parameters <- function(endpoint, body) {
14 |
15 | valid <- TRUE
16 |
17 | endpoint <- gsub("/$", "", endpoint)
18 | params <- ohsome::ohsome_endpoints[[endpoint]]$parameters$name
19 | required <- params[ohsome::ohsome_endpoints[[endpoint]]$parameters$required]
20 | unknown_params <- setdiff(names(body), params)
21 | missing_params <- setdiff(required, names(body))
22 |
23 | if(length(intersect(names(body), c("bpolys", "bboxes", "bcircles"))) != 1) {
24 | warning(
25 | "One (and only one) of the following parameters should be set: ",
26 | "bpolys, bboxes, or bcircles.",
27 | "\nYou can use set_boundary() to set a bounding geometry parameter.",
28 | call. = FALSE,
29 | immediate. = TRUE
30 | )
31 | valid <- FALSE
32 | }
33 |
34 | if(!("time" %in% names(body)) && !("time" %in% missing_params)) {
35 | warning(
36 | "The time parameter is not defined and defaults to the latest ",
37 | "available timestamp within the underlying OSHDB.",
38 | "\nYou can use set_time() to set the time parameter.",
39 | call. = FALSE,
40 | immediate. = TRUE
41 | )
42 | valid <- FALSE
43 | }
44 |
45 | if(!("filter" %in% names(body))) {
46 | warning(
47 | "The filter parameter is not defined.",
48 | "\nYou can use set_filter() to set the filter parameter.",
49 | call. = FALSE,
50 | immediate. = TRUE
51 | )
52 | valid <- FALSE
53 | }
54 |
55 | if(grepl("ratio", endpoint) & !("filter2" %in% names(body))) {
56 | warning(
57 | "The filter2 parameter needs to be defined in ratio queries.",
58 | "\nYou can use set_filter() to set the filter2 parameter.",
59 | call. = FALSE,
60 | immediate. = TRUE
61 | )
62 | valid <- FALSE
63 | }
64 |
65 | for(param in unknown_params) {
66 | warning(
67 | param, " is not a known parameter of ",
68 | "endpoint ", endpoint, ".",
69 | "\nYou can use set_parameters() with the argument ",
70 | param, " = NULL to remove it from the query.",
71 | call. = FALSE,
72 | immediate. = TRUE
73 | )
74 | valid <- FALSE
75 | }
76 |
77 | for(param in missing_params) {
78 | warning(
79 | param, " is a required parameter in queries to the endpoint ",
80 | endpoint, ".",
81 | "\nYou can use set_parameters() to set the ",
82 | param, " parameter.",
83 | call. = FALSE,
84 | immediate. = TRUE
85 | )
86 | valid <- FALSE
87 | }
88 |
89 | return(valid)
90 | }
91 |
92 | #' Validate endpoint
93 | #'
94 | #' Checks if the specified endpoint is in the list of known ohsome API endpoints
95 | #' and issues a warning if not. Specifically checks for invalid groupings in
96 | #' the endpoint path. Returns a logical that indicates the validity of
97 | #' the endpoint.
98 | #'
99 | #' @inheritParams validate_parameters
100 | #' @inherit validate_query return
101 | #' @keywords Internal
102 | #' @noRd
103 | validate_endpoint <- function(endpoint) {
104 |
105 | endpoint <- gsub("/$", "", endpoint)
106 | endpoints <- names(ohsome::ohsome_endpoints)
107 | split <- unlist(strsplit(endpoint, "/groupBy"))
108 | grouping_message <- NULL
109 |
110 | if(endpoint %in% endpoints) {
111 | return(TRUE)
112 | } else if(split[1] %in% endpoints) {
113 |
114 | if(length(split) > 1) {
115 | allowed <- endpoints[grepl(paste0("^", split[[1]], "/groupBy"), endpoints)]
116 | grouping_message <- ifelse(
117 | length(allowed) > 0,
118 | paste0(
119 | "\nOnly the following groupings are allowed with ",
120 | split[1], ":\n",
121 | paste("\t", gsub(split[[1]], "", allowed), collapse = "\n")
122 | ),
123 | paste0("\nGrouping is not allowed with ", split[1], "."
124 | )
125 | )
126 | }
127 | }
128 |
129 | warning(
130 | "ohsome does not know endpoint ", endpoint,
131 | grouping_message,
132 | "\nSee ",
133 | "https://docs.ohsome.org/ohsome-api/v1/endpoint-visualisation.html",
134 | " for available endpoints.",
135 | call. = FALSE,
136 | immediate. = TRUE
137 | )
138 | return(FALSE)
139 |
140 | }
141 |
142 | #' Validate ohsome_query
143 | #'
144 | #' Validates an ohsome_query object by checking against [ohsome_endpoints].
145 | #' Returns a logical that indicates the validity of the query.
146 | #'
147 | #' @inheritParams ohsome_post
148 | #' @return logical
149 | #' @keywords Internal
150 | #' @noRd
151 | validate_query <- function(query) {
152 |
153 | endpoint <- gsub("^.*?/", "", httr::parse_url(query$url)$path)
154 | valid_endpoint <- validate_endpoint(endpoint)
155 | if(valid_endpoint) {
156 | valid_params <- validate_parameters(endpoint, query$body)
157 | }
158 | return(valid_endpoint && valid_params)
159 | }
160 |
161 | #' Validate JSON response
162 | #'
163 | #' Validates ohsome API response content of type (Geo)JSON. Specifically checks
164 | #' for HTTP status messages in the content and uses any message to issue a
165 | #' warning. Returns a logical that indicates the validity of the JSON.
166 | #'
167 | #' @param json A JSON text string
168 | #' @return logical
169 | #' @keywords Internal
170 | #' @noRd
171 | validate_json <- function(json) {
172 |
173 | valid_json <- jsonlite::validate(json)
174 | status_message_pattern <- '.*status\" : [0-9]{3},\n \"message\" : \"'
175 |
176 | if(!valid_json && grepl(status_message_pattern, json)) {
177 | warning(
178 | paste(
179 | "HTTP status message in ohsome API response content:",
180 | sub('\".*$', "", sub(status_message_pattern, "", json)),
181 | sep = "\n"
182 | ),
183 | call. = FALSE
184 | )
185 | }
186 | return(valid_json)
187 | }
--------------------------------------------------------------------------------
/R/ohsome_boundary.R:
--------------------------------------------------------------------------------
1 | #' Create an `ohsome_boundary` object
2 | #'
3 | #' Creates an `ohsome_boundary` object from various classes of input geometries.
4 | #' The `ohsome_boundary` object is used to set the `bpolys`, `bboxes` or
5 | #' `bcircles` parameter of an `ohsome_query` object.
6 | #'
7 | #' @param boundary Bounding geometries specified by WGS84 coordinates in the
8 | #' order `lon,lat`. The geometries of `sf` are transformed to WGS84 if the CRS
9 | #' of the object is known. The following classes are supported:
10 | #' * `sf` with (MULTI)POLYGON geometries
11 | #' * `sfc` with (MULTI)POLYGON geometries
12 | #' * `sfg` with (MULTI)POLYGON geometries and WGS 84 coordinates
13 | #' * `bbox` created with [sf::st_bbox()] or [tmaptools::bb()]
14 | #' * `matrix` created with [sp::bbox()] or [osmdata::getbb()]
15 | #' * `character` providing textual definitions of bounding polygons, boxes or
16 | #' circles as allowed by the ohsome API (see
17 | #' [ohsome API - Boundaries](https://docs.ohsome.org/ohsome-api/stable/boundaries.html)
18 | #' ):
19 | #' * bboxes: WGS84 coordinates in the following format:
20 | #' `"id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|..."` OR
21 | #' `"lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|..."`
22 | #' * bcircles: WGS84 coordinates + radius in meter in the following
23 | #' format: `"id1:lon,lat,r|id2:lon,lat,r|..."` OR
24 | #' `"lon,lat,r|lon,lat,r|..."`
25 | #' * bpolys: WGS84 coordinates given as a list of coordinate pairs (as for
26 | #' bboxes) or GeoJSON FeatureCollection. The first point has to be the same
27 | #' as the last point and MultiPolygons are only supported in GeoJSON.
28 | #' * `list` of `bbox`, `matrix` or `character`. Bounding geometry types of all
29 | #' list elements must be the same. Does not work with GeoJSON
30 | #' FeatureCollections.
31 | #' @param ... Additional arguments other than `digits` are ignored.
32 | #' @param digits integer; number of decimal places of coordinates in the
33 | #' resulting GeoJSON when converting `sf` to GeoJSON (defaults to 6).
34 | #' @return An `ohsome_boundary` object which contains the following elements:
35 | #' * `boundary`: the boundary in textual format
36 | #' * `type` of the boundary (`bpolys`, `bcircles`, or `bboxes`).
37 | #' @export
38 | #' @examples
39 | #' # Defintion of a bounding circle (lon,lat,radius in meters)
40 | #' ohsome_boundary("8.6528,49.3683,1000")
41 | #'
42 | #' # Definition of two named bounding circles
43 | #' ohsome_boundary("Circle 1:8.6528,49.3683,1000|Circle 2:8.7294,49.4376,1000")
44 | #'
45 | #' # Definition of two named bounding circles with a character vector
46 | #' ohsome_boundary(c("Circle 1:8.6528,49.3683,1000", "Circle 2:8.7294,49.4376,1000"))
47 | #'
48 | #' # Use franconia from the mapview package as bounding polygons
49 | #' \donttest{
50 | #' ohsome_boundary(mapview::franconia, digits = 4)
51 | #' }
52 | #'
53 | #' # Use the bounding box of franconia
54 | #' \donttest{
55 | #' ohsome_boundary(sf::st_bbox(mapview::franconia))
56 | #' }
57 | #'
58 | #' # Get bounding box of the city of Berlin from OSM
59 | #' \dontrun{
60 | #' ohsome_boundary(osmdata::getbb("Berlin"))
61 | #' }
62 | #'
63 | #' # Use a list of two bounding boxes
64 | #' \dontrun{
65 | #' ohsome_boundary(list(osmdata::getbb("Berlin"), sf::st_bbox(mapview::franconia)))
66 | #' }
67 | #'
68 | ohsome_boundary <- function(boundary, ...) UseMethod("ohsome_boundary")
69 |
70 | #' @name ohsome_boundary
71 | #' @export
72 | ohsome_boundary.ohsome_boundary <- function(boundary, ...) return(boundary)
73 |
74 | #' @name ohsome_boundary
75 | #' @export
76 | ohsome_boundary.character <- function(boundary, ...) {
77 |
78 | if(jsonlite::validate(boundary) && length(boundary) == 1) {
79 | type <- "bpolys"
80 | } else {
81 | splt <- unlist(strsplit(boundary, split = "|", fixed = TRUE))
82 | len <- unique(sapply(strsplit(splt, split = ","), length))
83 |
84 | if(length(len) == 1 && len == 3) {
85 | type <- "bcircles"
86 | } else if(length(len) == 1 && len == 4) {
87 | type <- "bboxes"
88 | } else type <- "bpolys"
89 | }
90 |
91 | structure(list(
92 | boundary = paste(boundary, collapse = "|"), type = type),
93 | class = "ohsome_boundary"
94 | )
95 | }
96 |
97 | #' @name ohsome_boundary
98 | #' @export
99 | ohsome_boundary.sf <- function(boundary, digits = 6, ...) {
100 |
101 | if( (sf::st_crs(boundary)$input != "EPSG:4326") & !is.na(sf::st_crs(boundary)) )
102 | boundary <- sf::st_transform(boundary, 4326)
103 |
104 | types <- sf::st_geometry_type(boundary)
105 |
106 | if(!any(types %in% c("POLYGON", "MULTIPOLYGON"))) {
107 | stop(
108 | "None of the geometries provided are of type (MULTI)POLYGON.",
109 | call. = FALSE
110 | )
111 | }
112 |
113 | if(!all(types %in% c("POLYGON", "MULTIPOLYGON"))) {
114 | warning(
115 | "At least one of the bounding geometries is not of type ",
116 | "(MULTI)POLYGON and was omitted.",
117 | call. = FALSE
118 | )
119 | boundary <- boundary[types %in% c("POLYGON", "MULTIPOLYGON"),]
120 | }
121 |
122 | geojson <- geojsonsf::sf_geojson(boundary, digits = digits, simplify = FALSE)
123 | type <- "bpolys"
124 |
125 | structure(list(boundary = geojson, type = type), class = "ohsome_boundary")
126 | }
127 |
128 | #' @name ohsome_boundary
129 | #' @export
130 | ohsome_boundary.sfc <- function(boundary, ...) ohsome_boundary(sf::st_as_sf(boundary), ...)
131 |
132 | #' @name ohsome_boundary
133 | #' @export
134 | ohsome_boundary.sfg <- function(boundary, ...) ohsome_boundary(sf::st_sfc(boundary, crs = 4326), ...)
135 |
136 | #' @name ohsome_boundary
137 | #' @export
138 | ohsome_boundary.bbox <- function(boundary, ...) {
139 |
140 | if( (attributes(boundary)$crs$input != "EPSG:4326") & (!is.na((attributes(boundary)$crs$input)) ) ) {
141 | boundary <- sf::st_bbox(sf::st_transform(sf::st_as_sfc(boundary), 4326))
142 | }
143 |
144 | ohsome_boundary(paste(boundary, collapse = ","))
145 | }
146 |
147 | #' @name ohsome_boundary
148 | #' @export
149 | ohsome_boundary.matrix <- function(boundary, ...) ohsome_boundary(paste(boundary, collapse = ","))
150 |
151 | #' @name ohsome_boundary
152 | #' @export
153 | ohsome_boundary.list <- function(boundary, ...) {
154 | ohsome_boundary(paste(sapply(boundary, ohsome_boundary)[1,], collapse = "|"))
155 | }
156 |
--------------------------------------------------------------------------------
/man/ohsome_aggregate_elements.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ohsome_aggregate_elements.R
3 | \name{ohsome_aggregate_elements}
4 | \alias{ohsome_aggregate_elements}
5 | \alias{ohsome_elements_count}
6 | \alias{ohsome_elements_length}
7 | \alias{ohsome_elements_perimeter}
8 | \alias{ohsome_elements_area}
9 | \title{Aggregate OSM elements}
10 | \usage{
11 | ohsome_aggregate_elements(
12 | boundary = NULL,
13 | aggregation = c("count", "length", "perimeter", "area"),
14 | return_value = c("absolute", "density", "ratio"),
15 | grouping = NULL,
16 | time = NULL,
17 | ...
18 | )
19 |
20 | ohsome_elements_count(boundary = NULL, ...)
21 |
22 | ohsome_elements_length(boundary = NULL, ...)
23 |
24 | ohsome_elements_perimeter(boundary = NULL, ...)
25 |
26 | ohsome_elements_area(boundary = NULL, ...)
27 | }
28 | \arguments{
29 | \item{boundary}{Bounding geometries specified by WGS84 coordinates in the
30 | order \verb{lon,lat}. The geometries of \code{sf} are transformed to WGS84 if the CRS
31 | of the object is known. The following classes are supported:
32 | \itemize{
33 | \item \code{sf} with (MULTI)POLYGON geometries
34 | \item \code{sfc} with (MULTI)POLYGON geometries
35 | \item \code{sfg} with (MULTI)POLYGON geometries and WGS 84 coordinates
36 | \item \code{bbox} created with \code{\link[sf:st_bbox]{sf::st_bbox()}} or \code{\link[tmaptools:bb]{tmaptools::bb()}}
37 | \item \code{matrix} created with \code{\link[sp:bbox]{sp::bbox()}} or \code{\link[osmdata:getbb]{osmdata::getbb()}}
38 | \item \code{character} providing textual definitions of bounding polygons, boxes or
39 | circles as allowed by the ohsome API (see
40 | \href{https://docs.ohsome.org/ohsome-api/stable/boundaries.html}{ohsome API - Boundaries}
41 | ):
42 | \itemize{
43 | \item bboxes: WGS84 coordinates in the following format:
44 | \code{"id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|..."} OR
45 | \code{"lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|..."}
46 | \item bcircles: WGS84 coordinates + radius in meter in the following
47 | format: \code{"id1:lon,lat,r|id2:lon,lat,r|..."} OR
48 | \code{"lon,lat,r|lon,lat,r|..."}
49 | \item bpolys: WGS84 coordinates given as a list of coordinate pairs (as for
50 | bboxes) or GeoJSON FeatureCollection. The first point has to be the same
51 | as the last point and MultiPolygons are only supported in GeoJSON.
52 | }
53 | \item \code{list} of \code{bbox}, \code{matrix} or \code{character}. Bounding geometry types of all
54 | list elements must be the same. Does not work with GeoJSON
55 | FeatureCollections.
56 | }}
57 |
58 | \item{aggregation}{character; aggregation type:
59 | \itemize{
60 | \item \code{"count"} returns the total number of elements. This is the default.
61 | \item \code{"length"} returns the total length of elements in meters.
62 | \item \code{"perimeter"} returns the total perimeter of elements in meters.
63 | \item \code{"area"} returns the total area of elements in square meters.
64 | }}
65 |
66 | \item{return_value}{character; the value to be returned by the ohsome API:
67 | \itemize{
68 | \item \code{"absolute"} returns the absolute number, length, perimeter or area of
69 | elements. This is the default.
70 | \item \code{"density"} returns the number, length, perimeter or area (in meters!) of
71 | elements per square kilometer.
72 | \item \code{"ratio"} returns an absolute \code{value} for elements satisfying the
73 | \code{filter} argument, an absolute \code{value2} for elements satisfying the
74 | \code{filter2} argument, and the \code{ratio} of \code{value2} to \code{value}.
75 | }}
76 |
77 | \item{grouping}{character; group type(s) for grouped aggregations (only
78 | available for queries to aggregation endpoints). The following group types
79 | are available:
80 | \itemize{
81 | \item \code{"boundary"} groups the result by the given boundaries that are defined
82 | through any of the \code{boundary} query parameters.
83 | \item \code{"key"} groups the result by the given keys that are defined through the
84 | \code{groupByKeys} query parameter.
85 | \item \code{"tag"} groups the result by the given tags that are defined through the
86 | \code{groupByKey} and \code{groupByValues} query parameters.
87 | \item \code{"type"} groups the result by OSM element type.
88 | \item \code{c("boundary", "tag")} groups the result by the given boundaries and
89 | tags.
90 | }
91 |
92 | Not all of these group types are accepted by all of the aggregation
93 | endpoints. Check
94 | \href{https://docs.ohsome.org/ohsome-api/v1/group-by.html}{Grouping}
95 | for available group types.}
96 |
97 | \item{time}{character; \code{time} parameter of the query (see
98 | \href{https://docs.ohsome.org/ohsome-api/v1/time.html}{Supported time formats}).}
99 |
100 | \item{...}{Parameters of the request to the ohsome API endpoint.}
101 | }
102 | \value{
103 | An \code{ohsome_query} object. The object can be sent to the ohsome API
104 | with \code{\link[=ohsome_post]{ohsome_post()}}. It consists of the following elements:
105 | \itemize{
106 | \item \code{url}: The URL of the endpoint.
107 | \item \code{encode}: The way the information is encoded and then posted to the
108 | ohsome API. Set as \code{"form"}.
109 | \item \code{body}: The parameters of the query such as \code{format}, \code{filter} or
110 | \code{bpolys}.
111 | }
112 | }
113 | \description{
114 | Creates an \code{ohsome_query} object for OSM element aggregation
115 | }
116 | \details{
117 | \code{ohsome_aggregate_elements()} creates an \code{ohsome_query} object for
118 | OSM element aggregation. \code{ohsome_elements_count()},
119 | \code{ohsome_elements_length()}, \code{ohsome_elements_perimeter()} and
120 | \code{ohsome_elements_area()} are wrapper functions for specific aggregation
121 | endpoints. Boundary objects are passed via \code{\link[=set_boundary]{set_boundary()}} into
122 | \code{\link[=ohsome_boundary]{ohsome_boundary()}}.
123 | }
124 | \examples{
125 | \donttest{
126 | # Count of breweries in Franconia
127 | ohsome_aggregate_elements(
128 | mapview::franconia,
129 | aggregation = "count",
130 | filter = "craft=brewery",
131 | time = "2022-01-01"
132 | )
133 |
134 | ohsome_elements_count(
135 | mapview::franconia,
136 | filter = "craft=brewery",
137 | time = "2022-01-01"
138 | )
139 |
140 | # Monthly counts of breweries in Franconia from 2012 to 2022
141 | ohsome_elements_count(
142 | mapview::franconia,
143 | filter = "craft=brewery",
144 | time = "2012/2022/P1M"
145 | )
146 |
147 | # Count of breweries per district of Franconia
148 | ohsome_elements_count(
149 | mapview::franconia,
150 | filter = "craft=brewery",
151 | grouping = "boundary",
152 | time = "2022-01-01"
153 | )
154 |
155 | # Number of breweries per square kilometer
156 | ohsome_elements_count(
157 | mapview::franconia,
158 | filter = "craft=brewery",
159 | return_value = "density",
160 | time = "2022-01-01"
161 | )
162 |
163 | # Proportion of breweries that are microbreweries
164 | ohsome_elements_count(
165 | mapview::franconia,
166 | filter = "craft=brewery",
167 | filter2 = "craft=brewery and microbrewery=yes",
168 | return_value = "ratio",
169 | time = "2022-01-01"
170 | )
171 |
172 | # Total length of highway elements in Franconia
173 | ohsome_elements_length(
174 | mapview::franconia,
175 | filter = "highway=* and geometry:line",
176 | time = "2022-01-01"
177 | )
178 | }
179 |
180 | }
181 | \seealso{
182 | \href{https://docs.ohsome.org/ohsome-api/stable/endpoints.html#elements-aggregation}{ohsome API Endpoints - Elements Aggregation}
183 | }
184 | \concept{Aggregate elements}
185 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | GNU Lesser General Public License
2 | =================================
3 |
4 | _Version 3, 29 June 2007_
5 | _Copyright © 2007 Free Software Foundation, Inc. <>_
6 |
7 | Everyone is permitted to copy and distribute verbatim copies
8 | of this license document, but changing it is not allowed.
9 |
10 |
11 | This version of the GNU Lesser General Public License incorporates
12 | the terms and conditions of version 3 of the GNU General Public
13 | License, supplemented by the additional permissions listed below.
14 |
15 | ### 0. Additional Definitions
16 |
17 | As used herein, “this License” refers to version 3 of the GNU Lesser
18 | General Public License, and the “GNU GPL” refers to version 3 of the GNU
19 | General Public License.
20 |
21 | “The Library” refers to a covered work governed by this License,
22 | other than an Application or a Combined Work as defined below.
23 |
24 | An “Application” is any work that makes use of an interface provided
25 | by the Library, but which is not otherwise based on the Library.
26 | Defining a subclass of a class defined by the Library is deemed a mode
27 | of using an interface provided by the Library.
28 |
29 | A “Combined Work” is a work produced by combining or linking an
30 | Application with the Library. The particular version of the Library
31 | with which the Combined Work was made is also called the “Linked
32 | Version”.
33 |
34 | The “Minimal Corresponding Source” for a Combined Work means the
35 | Corresponding Source for the Combined Work, excluding any source code
36 | for portions of the Combined Work that, considered in isolation, are
37 | based on the Application, and not on the Linked Version.
38 |
39 | The “Corresponding Application Code” for a Combined Work means the
40 | object code and/or source code for the Application, including any data
41 | and utility programs needed for reproducing the Combined Work from the
42 | Application, but excluding the System Libraries of the Combined Work.
43 |
44 | ### 1. Exception to Section 3 of the GNU GPL
45 |
46 | You may convey a covered work under sections 3 and 4 of this License
47 | without being bound by section 3 of the GNU GPL.
48 |
49 | ### 2. Conveying Modified Versions
50 |
51 | If you modify a copy of the Library, and, in your modifications, a
52 | facility refers to a function or data to be supplied by an Application
53 | that uses the facility (other than as an argument passed when the
54 | facility is invoked), then you may convey a copy of the modified
55 | version:
56 |
57 | * **a)** under this License, provided that you make a good faith effort to
58 | ensure that, in the event an Application does not supply the
59 | function or data, the facility still operates, and performs
60 | whatever part of its purpose remains meaningful, or
61 |
62 | * **b)** under the GNU GPL, with none of the additional permissions of
63 | this License applicable to that copy.
64 |
65 | ### 3. Object Code Incorporating Material from Library Header Files
66 |
67 | The object code form of an Application may incorporate material from
68 | a header file that is part of the Library. You may convey such object
69 | code under terms of your choice, provided that, if the incorporated
70 | material is not limited to numerical parameters, data structure
71 | layouts and accessors, or small macros, inline functions and templates
72 | (ten or fewer lines in length), you do both of the following:
73 |
74 | * **a)** Give prominent notice with each copy of the object code that the
75 | Library is used in it and that the Library and its use are
76 | covered by this License.
77 | * **b)** Accompany the object code with a copy of the GNU GPL and this license
78 | document.
79 |
80 | ### 4. Combined Works
81 |
82 | You may convey a Combined Work under terms of your choice that,
83 | taken together, effectively do not restrict modification of the
84 | portions of the Library contained in the Combined Work and reverse
85 | engineering for debugging such modifications, if you also do each of
86 | the following:
87 |
88 | * **a)** Give prominent notice with each copy of the Combined Work that
89 | the Library is used in it and that the Library and its use are
90 | covered by this License.
91 |
92 | * **b)** Accompany the Combined Work with a copy of the GNU GPL and this license
93 | document.
94 |
95 | * **c)** For a Combined Work that displays copyright notices during
96 | execution, include the copyright notice for the Library among
97 | these notices, as well as a reference directing the user to the
98 | copies of the GNU GPL and this license document.
99 |
100 | * **d)** Do one of the following:
101 | - **0)** Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 | - **1)** Use a suitable shared library mechanism for linking with the
109 | Library. A suitable mechanism is one that **(a)** uses at run time
110 | a copy of the Library already present on the user's computer
111 | system, and **(b)** will operate properly with a modified version
112 | of the Library that is interface-compatible with the Linked
113 | Version.
114 |
115 | * **e)** Provide Installation Information, but only if you would otherwise
116 | be required to provide such information under section 6 of the
117 | GNU GPL, and only to the extent that such information is
118 | necessary to install and execute a modified version of the
119 | Combined Work produced by recombining or relinking the
120 | Application with a modified version of the Linked Version. (If
121 | you use option **4d0**, the Installation Information must accompany
122 | the Minimal Corresponding Source and Corresponding Application
123 | Code. If you use option **4d1**, you must provide the Installation
124 | Information in the manner specified by section 6 of the GNU GPL
125 | for conveying Corresponding Source.)
126 |
127 | ### 5. Combined Libraries
128 |
129 | You may place library facilities that are a work based on the
130 | Library side by side in a single library together with other library
131 | facilities that are not Applications and are not covered by this
132 | License, and convey such a combined library under terms of your
133 | choice, if you do both of the following:
134 |
135 | * **a)** Accompany the combined library with a copy of the same work based
136 | on the Library, uncombined with any other library facilities,
137 | conveyed under the terms of this License.
138 | * **b)** Give prominent notice with the combined library that part of it
139 | is a work based on the Library, and explaining where to find the
140 | accompanying uncombined form of the same work.
141 |
142 | ### 6. Revised Versions of the GNU Lesser General Public License
143 |
144 | The Free Software Foundation may publish revised and/or new versions
145 | of the GNU Lesser General Public License from time to time. Such new
146 | versions will be similar in spirit to the present version, but may
147 | differ in detail to address new problems or concerns.
148 |
149 | Each version is given a distinguishing version number. If the
150 | Library as you received it specifies that a certain numbered version
151 | of the GNU Lesser General Public License “or any later version”
152 | applies to it, you have the option of following the terms and
153 | conditions either of that published version or of any later version
154 | published by the Free Software Foundation. If the Library as you
155 | received it does not specify a version number of the GNU Lesser
156 | General Public License, you may choose any version of the GNU Lesser
157 | General Public License ever published by the Free Software Foundation.
158 |
159 | If the Library as you received it specifies that a proxy can decide
160 | whether future versions of the GNU Lesser General Public License shall
161 | apply, that proxy's public statement of acceptance of any version is
162 | permanent authorization for you to choose that version for the
163 | Library.
164 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | # -----------------------------------------------------------
2 | # CITATION file created with {cffr} R package, v0.4.0
3 | # See also: https://docs.ropensci.org/cffr/
4 | # -----------------------------------------------------------
5 |
6 | cff-version: 1.2.0
7 | message: 'To cite package "ohsome" in publications use:'
8 | type: software
9 | license: LGPL-3.0-or-later
10 | title: 'ohsome: An ''ohsome API'' Client'
11 | version: 0.2.0
12 | doi: 10.5281/zenodo.5512545
13 | abstract: A client that grants access to the power of the 'ohsome API' from R. It
14 | lets you analyze the rich data source of the 'OpenStreetMap (OSM)' history. You
15 | can retrieve the geometry of 'OSM' data at specific points in time, and you can
16 | get aggregated statistics on the evolution of 'OSM' elements and specify your own
17 | temporal, spatial and/or thematic filters.
18 | authors:
19 | - family-names: Fritz
20 | given-names: Oliver
21 | email: oliver.fritz@heigit.org
22 | orcid: https://orcid.org/0000-0001-6324-7295
23 | preferred-citation:
24 | type: generic
25 | title: OSHDB - OpenStreetMap History Data Analysis (0.7.2)
26 | authors:
27 | - family-names: Raifer
28 | given-names: Martin
29 | - family-names: Troilo
30 | given-names: Rafael
31 | - family-names: Mocnik
32 | given-names: Franz-Benjamin
33 | - family-names: Schott
34 | given-names: Moritz
35 | month: '9'
36 | year: '2021'
37 | publisher:
38 | name: Zenodo
39 | version: 0.7.2
40 | doi: 10.5281/zenodo.5512545
41 | url: https://doi.org/10.5281/zenodo.5512545
42 | repository-code: https://github.com/GIScience/ohsome-r
43 | url: https://docs.ohsome.org/ohsome-api/stable/
44 | contact:
45 | - family-names: Fritz
46 | given-names: Oliver
47 | email: oliver.fritz@heigit.org
48 | orcid: https://orcid.org/0000-0001-6324-7295
49 | keywords:
50 | - heigit
51 | - ohsome
52 | - openstreetmap
53 | - openstreetmap-data
54 | - openstreetmap-history
55 | - osm
56 | - osm-data
57 | references:
58 | - type: article
59 | title: 'OSHDB: a framework for spatio-temporal analysis of OpenStreetMap history
60 | data'
61 | authors:
62 | - family-names: Raifer
63 | given-names: Martin
64 | - family-names: Troilo
65 | given-names: Rafael
66 | - family-names: Kowatsch
67 | given-names: Fabian
68 | - family-names: Auer
69 | given-names: Michael
70 | - family-names: Loos
71 | given-names: Lukas
72 | - family-names: Marx
73 | given-names: Sabrina
74 | - family-names: Przybill
75 | given-names: Katharina
76 | - family-names: Fendrich
77 | given-names: Sascha
78 | - family-names: Mocnik
79 | given-names: Franz-Benjamin
80 | - family-names: Zipf
81 | given-names: Alexander
82 | journal: Open Geospatial Data, Software and Standards
83 | year: '2019'
84 | month: '4'
85 | volume: '4'
86 | issue: '1'
87 | doi: 10.1186/s40965-019-0061-3
88 | url: https://doi.org/10.1186/s40965-019-0061-3
89 | start: '3'
90 | - type: software
91 | title: 'R: A Language and Environment for Statistical Computing'
92 | notes: Depends
93 | url: https://www.R-project.org/
94 | authors:
95 | - name: R Core Team
96 | location:
97 | name: Vienna, Austria
98 | year: '2023'
99 | institution:
100 | name: R Foundation for Statistical Computing
101 | version: '>= 2.10'
102 | - type: software
103 | title: geojsonsf
104 | abstract: 'geojsonsf: GeoJSON to Simple Feature Converter'
105 | notes: Imports
106 | url: https://github.com/SymbolixAU/geojsonsf
107 | repository: https://CRAN.R-project.org/package=geojsonsf
108 | authors:
109 | - family-names: Cooley
110 | given-names: David
111 | email: dcooley@symbolix.com.au
112 | year: '2023'
113 | - type: software
114 | title: httr
115 | abstract: 'httr: Tools for Working with URLs and HTTP'
116 | notes: Imports
117 | url: https://httr.r-lib.org/
118 | repository: https://CRAN.R-project.org/package=httr
119 | authors:
120 | - family-names: Wickham
121 | given-names: Hadley
122 | email: hadley@rstudio.com
123 | year: '2023'
124 | - type: software
125 | title: jsonlite
126 | abstract: 'jsonlite: A Simple and Robust JSON Parser and Generator for R'
127 | notes: Imports
128 | url: https://arxiv.org/abs/1403.2805
129 | repository: https://CRAN.R-project.org/package=jsonlite
130 | authors:
131 | - family-names: Ooms
132 | given-names: Jeroen
133 | email: jeroen@berkeley.edu
134 | orcid: https://orcid.org/0000-0002-4035-0289
135 | year: '2023'
136 | - type: software
137 | title: readr
138 | abstract: 'readr: Read Rectangular Text Data'
139 | notes: Imports
140 | url: https://readr.tidyverse.org
141 | repository: https://CRAN.R-project.org/package=readr
142 | authors:
143 | - family-names: Wickham
144 | given-names: Hadley
145 | email: hadley@rstudio.com
146 | - family-names: Hester
147 | given-names: Jim
148 | - family-names: Bryan
149 | given-names: Jennifer
150 | email: jenny@rstudio.com
151 | orcid: https://orcid.org/0000-0002-6983-2759
152 | year: '2023'
153 | - type: software
154 | title: sf
155 | abstract: 'sf: Simple Features for R'
156 | notes: Imports
157 | url: https://r-spatial.github.io/sf/
158 | repository: https://CRAN.R-project.org/package=sf
159 | authors:
160 | - family-names: Pebesma
161 | given-names: Edzer
162 | email: edzer.pebesma@uni-muenster.de
163 | orcid: https://orcid.org/0000-0001-8049-7069
164 | year: '2023'
165 | - type: software
166 | title: utils
167 | abstract: 'R: A Language and Environment for Statistical Computing'
168 | notes: Imports
169 | authors:
170 | - name: R Core Team
171 | location:
172 | name: Vienna, Austria
173 | year: '2023'
174 | institution:
175 | name: R Foundation for Statistical Computing
176 | - type: software
177 | title: dplyr
178 | abstract: 'dplyr: A Grammar of Data Manipulation'
179 | notes: Suggests
180 | url: https://dplyr.tidyverse.org
181 | repository: https://CRAN.R-project.org/package=dplyr
182 | authors:
183 | - family-names: Wickham
184 | given-names: Hadley
185 | email: hadley@rstudio.com
186 | orcid: https://orcid.org/0000-0003-4757-117X
187 | - family-names: François
188 | given-names: Romain
189 | orcid: https://orcid.org/0000-0002-2444-4226
190 | - family-names: Henry
191 | given-names: Lionel
192 | - family-names: Müller
193 | given-names: Kirill
194 | orcid: https://orcid.org/0000-0002-1416-3412
195 | year: '2023'
196 | - type: software
197 | title: ggplot2
198 | abstract: 'ggplot2: Create Elegant Data Visualisations Using the Grammar of Graphics'
199 | notes: Suggests
200 | url: https://ggplot2.tidyverse.org
201 | repository: https://CRAN.R-project.org/package=ggplot2
202 | authors:
203 | - family-names: Wickham
204 | given-names: Hadley
205 | email: hadley@rstudio.com
206 | orcid: https://orcid.org/0000-0003-4757-117X
207 | - family-names: Chang
208 | given-names: Winston
209 | orcid: https://orcid.org/0000-0002-1576-2126
210 | - family-names: Henry
211 | given-names: Lionel
212 | - family-names: Pedersen
213 | given-names: Thomas Lin
214 | email: thomas.pedersen@rstudio.com
215 | orcid: https://orcid.org/0000-0002-5147-4711
216 | - family-names: Takahashi
217 | given-names: Kohske
218 | - family-names: Wilke
219 | given-names: Claus
220 | orcid: https://orcid.org/0000-0002-7470-9261
221 | - family-names: Woo
222 | given-names: Kara
223 | orcid: https://orcid.org/0000-0002-5125-4188
224 | - family-names: Yutani
225 | given-names: Hiroaki
226 | orcid: https://orcid.org/0000-0002-3385-7233
227 | - family-names: Dunnington
228 | given-names: Dewey
229 | orcid: https://orcid.org/0000-0002-9415-4582
230 | year: '2023'
231 | - type: software
232 | title: httptest
233 | abstract: 'httptest: A Test Environment for HTTP Requests'
234 | notes: Suggests
235 | url: https://enpiar.com/r/httptest/
236 | repository: https://CRAN.R-project.org/package=httptest
237 | authors:
238 | - family-names: Richardson
239 | given-names: Neal
240 | email: neal.p.richardson@gmail.com
241 | year: '2023'
242 | - type: software
243 | title: janitor
244 | abstract: 'janitor: Simple Tools for Examining and Cleaning Dirty Data'
245 | notes: Suggests
246 | url: https://github.com/sfirke/janitor
247 | repository: https://CRAN.R-project.org/package=janitor
248 | authors:
249 | - family-names: Firke
250 | given-names: Sam
251 | email: samuel.firke@gmail.com
252 | year: '2023'
253 | - type: software
254 | title: knitr
255 | abstract: 'knitr: A General-Purpose Package for Dynamic Report Generation in R'
256 | notes: Suggests
257 | url: https://yihui.org/knitr/
258 | repository: https://CRAN.R-project.org/package=knitr
259 | authors:
260 | - family-names: Xie
261 | given-names: Yihui
262 | email: xie@yihui.name
263 | orcid: https://orcid.org/0000-0003-0645-5666
264 | year: '2023'
265 | - type: software
266 | title: mapview
267 | abstract: 'mapview: Interactive Viewing of Spatial Data in R'
268 | notes: Suggests
269 | url: https://github.com/r-spatial/mapview
270 | repository: https://CRAN.R-project.org/package=mapview
271 | authors:
272 | - family-names: Appelhans
273 | given-names: Tim
274 | email: tim.appelhans@gmail.com
275 | - family-names: Detsch
276 | given-names: Florian
277 | email: fdetsch@web.de
278 | - family-names: Reudenbach
279 | given-names: Christoph
280 | email: reudenbach@geo.uni-marburg.de
281 | - family-names: Woellauer
282 | given-names: Stefan
283 | email: stephan.woellauer@geo.uni-marburg.de
284 | year: '2023'
285 | - type: software
286 | title: nominatimlite
287 | abstract: 'nominatimlite: Interface with ''Nominatim'' API Service'
288 | notes: Suggests
289 | url: https://dieghernan.github.io/nominatimlite/
290 | repository: https://CRAN.R-project.org/package=nominatimlite
291 | authors:
292 | - family-names: Hernangómez
293 | given-names: Diego
294 | email: diego.hernangomezherrero@gmail.com
295 | orcid: https://orcid.org/0000-0001-8457-4658
296 | year: '2023'
297 | - type: software
298 | title: osmdata
299 | abstract: 'osmdata: Import ''OpenStreetMap'' Data as Simple Features or Spatial
300 | Objects'
301 | notes: Suggests
302 | url: https://docs.ropensci.org/osmdata/
303 | repository: https://CRAN.R-project.org/package=osmdata
304 | authors:
305 | - family-names: Padgham
306 | given-names: Mark
307 | email: mark.padgham@email.com
308 | - family-names: Rudis
309 | given-names: Bob
310 | - family-names: Lovelace
311 | given-names: Robin
312 | - family-names: Salmon
313 | given-names: Maëlle
314 | year: '2023'
315 | - type: software
316 | title: rmarkdown
317 | abstract: 'rmarkdown: Dynamic Documents for R'
318 | notes: Suggests
319 | url: https://pkgs.rstudio.com/rmarkdown/
320 | repository: https://CRAN.R-project.org/package=rmarkdown
321 | authors:
322 | - family-names: Allaire
323 | given-names: JJ
324 | email: jj@rstudio.com
325 | - family-names: Xie
326 | given-names: Yihui
327 | email: xie@yihui.name
328 | orcid: https://orcid.org/0000-0003-0645-5666
329 | - family-names: McPherson
330 | given-names: Jonathan
331 | email: jonathan@rstudio.com
332 | - family-names: Luraschi
333 | given-names: Javier
334 | email: javier@rstudio.com
335 | - family-names: Ushey
336 | given-names: Kevin
337 | email: kevin@rstudio.com
338 | - family-names: Atkins
339 | given-names: Aron
340 | email: aron@rstudio.com
341 | - family-names: Wickham
342 | given-names: Hadley
343 | email: hadley@rstudio.com
344 | - family-names: Cheng
345 | given-names: Joe
346 | email: joe@rstudio.com
347 | - family-names: Chang
348 | given-names: Winston
349 | email: winston@rstudio.com
350 | - family-names: Iannone
351 | given-names: Richard
352 | email: rich@rstudio.com
353 | orcid: https://orcid.org/0000-0003-3925-190X
354 | year: '2023'
355 | - type: software
356 | title: spelling
357 | abstract: 'spelling: Tools for Spell Checking in R'
358 | notes: Suggests
359 | url: https://docs.ropensci.org/spelling/
360 | repository: https://CRAN.R-project.org/package=spelling
361 | authors:
362 | - family-names: Ooms
363 | given-names: Jeroen
364 | email: jeroen@berkeley.edu
365 | orcid: https://orcid.org/0000-0002-4035-0289
366 | - family-names: Hester
367 | given-names: Jim
368 | email: james.hester@rstudio.com
369 | year: '2023'
370 | - type: software
371 | title: testthat
372 | abstract: 'testthat: Unit Testing for R'
373 | notes: Suggests
374 | url: https://testthat.r-lib.org
375 | repository: https://CRAN.R-project.org/package=testthat
376 | authors:
377 | - family-names: Wickham
378 | given-names: Hadley
379 | email: hadley@rstudio.com
380 | year: '2023'
381 | version: '>= 3.0.0'
382 | - type: software
383 | title: tmaptools
384 | abstract: 'tmaptools: Thematic Map Tools'
385 | notes: Suggests
386 | url: https://github.com/mtennekes/tmaptools
387 | repository: https://CRAN.R-project.org/package=tmaptools
388 | authors:
389 | - family-names: Tennekes
390 | given-names: Martijn
391 | email: mtennekes@gmail.com
392 | year: '2023'
393 | - type: software
394 | title: tidyr
395 | abstract: 'tidyr: Tidy Messy Data'
396 | notes: Suggests
397 | url: https://tidyr.tidyverse.org
398 | repository: https://CRAN.R-project.org/package=tidyr
399 | authors:
400 | - family-names: Wickham
401 | given-names: Hadley
402 | email: hadley@rstudio.com
403 | - family-names: Girlich
404 | given-names: Maximilian
405 | year: '2023'
406 |
--------------------------------------------------------------------------------
/vignettes/ohsome.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "ohsome"
3 | output: rmarkdown::html_vignette
4 | vignette: >
5 | %\VignetteIndexEntry{ohsome}
6 | %\VignetteEngine{knitr::rmarkdown}
7 | %\VignetteEncoding{UTF-8}
8 | ---
9 |
10 | ```{r, include = FALSE}
11 | NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true")
12 | httr::set_config(httr::config(http_version = 1))
13 | knitr::opts_chunk$set(
14 | collapse = TRUE,
15 | comment = "#>",
16 | fig.path = "figures/",
17 | out.width = "100%",
18 | purl = NOT_CRAN,
19 | eval = NOT_CRAN
20 | )
21 | ```
22 |
23 | This ohsome R package grants access to the power of the [ohsome API](https://api.ohsome.org){target=blank}
24 | from R. ohsome lets you analyze the rich data source of the
25 | [OpenStreetMap](https://www.openstreetmap.org/){target=blank}
26 | (OSM) history. It aims to leverage the tools of the
27 | [OpenStreetMap History Database](https://github.com/GIScience/oshdb){target=blank}
28 | (OSHDB).
29 |
30 | With ohsome, you can ...
31 |
32 | - Get **aggregated statistics** on the evolution of OpenStreetMap elements and
33 | specify your own temporal, spatial and/or thematic filters. The data aggregation
34 | endpoint allows you to access functions, e.g., to calculate the area of
35 | buildings or the length of streets at any given timestamp.
36 |
37 | - Retrieve the **geometry** of the historical OpenStreetMap data, e.g., to
38 | visualize the evolution of certain OpenStreetMap elements over time. You can get
39 | the geometries for specific points in time or all changes within a timespan
40 | (full-history).
41 |
42 | ## Getting started
43 |
44 | Upon attaching the ohsome package, a metadata request is sent to the ohsome
45 | API. The package message provides some essential metadata information, such as
46 | the current temporal extent of the underlying OSHDB:
47 |
48 | ```{r library}
49 | library(ohsome)
50 | ```
51 |
52 | The metadata is stored in `.ohsome_metadata`. You can print it to the console
53 | to get more details.
54 |
55 | You can create any ohsome API query using the generic `ohsome_query()` function.
56 | It takes the endpoint path and any query parameters as inputs. For information
57 | on all available endpoints with their parameters, consult the
58 | [ohsome API documentation](https://docs.ohsome.org/ohsome-api/stable/endpoints.html){target=blank}
59 | or print `ohsome_endpoints` to the console.
60 |
61 | However, this ohsome R package provides specific wrapper functions for queries
62 | to all available endpoints.
63 |
64 | ### OSM elements
65 |
66 | #### Aggregating OSM elements
67 |
68 | The
69 | [elements aggregation endpoints](https://docs.ohsome.org/ohsome-api/stable/endpoints.html#elements-aggregation){target=blank}
70 | of the ohsome API allow querying for the aggregated amount, length, area or
71 | perimeter of OpenStreetMap elements with given properties, within given
72 | boundaries and at given points in time.
73 |
74 | Let us create a query for the total amount of breweries on OSM in the region of
75 | Franconia. The first argument to `ohsome_elements_count()` is the `sf` object
76 | `franconia` that is included in the
77 | [mapview](https://r-spatial.github.io/mapview/){target=blank}
78 | package and contains boundary
79 | polygons of the `r nrow(mapview::franconia)` districts of the region:
80 |
81 | ```{r fix, include = FALSE}
82 | # avoid messages when handling franconia with old-style crs object
83 | franconia <- sf::st_set_crs(mapview::franconia, 4326)
84 | ```
85 |
86 | ```{r elements_count}
87 | library(mapview)
88 |
89 | q <- ohsome_elements_count(franconia, filter = "craft=brewery")
90 | ```
91 |
92 | The resulting `ohsome_query` object can be sent to the ohsome API with
93 | `ohsome_post()`. By default, `ohsome_post()` returns the parsed API
94 | response. In this case, this is a simple `data.frame` of only one row.
95 |
96 | ```{r post}
97 | ohsome_post(q, strict = FALSE)
98 | ```
99 |
100 | As you can see, `ohsome_post()` issues a warning that the time parameter of the
101 | query is not defined. The `ohsome` API returns the number of elements at the
102 | latest available timestamp by default. ^[When the `strict`
103 | argument is set to TRUE (default), `ohsome_post` throws an error on a missing
104 | `time` parameter and does not send the request to the API at all.]
105 |
106 | Defining the `time` parameter unlocks the full power of ohsome API by giving
107 | access to the OSM history. The `time` parameter requires one or more
108 | [ISO-8601 conform timestring(s)](https://docs.ohsome.org/ohsome-api/stable/time.html){target=blank}.
109 | Here is how to create a query for the number of breweries at the first of each
110 | month between 2010 and 2020:
111 |
112 | ```{r time, eval = FALSE}
113 | ohsome_elements_count(franconia, filter = "craft=brewery", time = "2010/2020/P1M")
114 | ```
115 |
116 | Alternatively, we can update the existing `ohsome_query` object `q` with the
117 | `set_time()` function,
118 | pipe ^[Instead of the new R native pipe `|>` you may choose to use `magrittr`'s `%>%`.]
119 | the modified query directly into `ohsome_post()`
120 | and make a quick visualization with `ggplot2`:
121 |
122 | ```{r pipe, dev = "svg"}
123 | library(ggplot2)
124 |
125 | q |>
126 | set_time("2010/2020/P1M") |>
127 | ohsome_post() |>
128 | ggplot(aes(x = timestamp, y = value)) +
129 | geom_line()
130 | ```
131 |
132 | This is how to query the total number of breweries in all of Franconia. But
133 | what if we want to aggregate the amount per district? The ohsome API provides
134 | specific endpoints for different grouped calculations, such as aggregation
135 | grouped by bounding geometry.
136 |
137 | There are several ways to define a query for an aggregation grouped by boundary:
138 |
139 | The `set_endpoint`function is used to change or append the endpoint path of an
140 | API request. In this case, we could append `groupBy/boundary` to the existing
141 | query to the `elements/count` endpoint. The endpoint path can either be given
142 | as a single string (`/groupBy/boundary`) or as a character vector:
143 | `set_endpoint(q, c("groupBy", "boundary"), append = TRUE)`
144 | ^[The order of the elements in the character vector is critical!].
145 |
146 | More comfortable, however, is the use of either the grouping argument with an
147 | elements aggregation function (e.g.
148 | `ohsome_elements_count(grouping = "boundary)`) or of the `set_grouping()`
149 | function to modify an existing query object:
150 |
151 | ```{r groupBy_boundary, message = FALSE}
152 | library(dplyr)
153 |
154 | franconia |>
155 | mutate(id = NAME_ASCI) |>
156 | ohsome_elements_count(filter = "craft=brewery", time = "2021-06-01") |>
157 | set_grouping("boundary") |>
158 | ohsome_post()
159 | ```
160 |
161 | If you want your own identifiers for the geometries returned by ohsome, your
162 | input `sf` object needs a column explicitly named `id`. You can use `mutate()`
163 | or `rename()` from the
164 | [dplyr](https://dplyr.tidyverse.org){target=blank}
165 | package to create such a column as in the example
166 | below.
167 |
168 | By default, `ohsome_post()` returns an `sf` object whenever the ohsome API
169 | is capable of delivering GeoJSON data. This is the case for elements
170 | extraction queries as well as for aggregations grouped by boundaries.
171 |
172 | Thus, you can easily create a choropleth map from the query results.
173 | In addition, you can set the argument `return_value` to `density`. This will
174 | modify the endpoint path of the query so that ohsome returns the number of
175 | breweries per area instead of the absolute value:
176 |
177 | ```{r density}
178 | franconia |>
179 | mutate(id = NAME_ASCI) |>
180 | ohsome_elements_count(filter = "craft=brewery", return_value = "density") |>
181 | set_time("2021-06-01") |>
182 | set_grouping("boundary") |>
183 | ohsome_post() |>
184 | mapview(zcol = "value", layer.name = "Breweries per sqkm")
185 | ```
186 |
187 | #### Extracting OSM elements
188 |
189 | The
190 | [elements extraction endpoints](https://docs.ohsome.org/ohsome-api/stable/endpoints.html#elements-extraction){target=blank}
191 | of the ohsome API allow obtaining geometries, bounding boxes or centroids of OSM
192 | elements with given properties, within given boundaries and at given points in
193 | time. Together with the elements, you can choose to query for their tags and/or
194 | their metadata such as the changeset ID, the time of the last edit or the
195 | version number.
196 |
197 | The following query extracts the geometries of buildings within 500 m of
198 | Heidelberg main station with their tags. The response is used to visualize
199 | the buildings and the values of their `building:levels` tag (if available):
200 |
201 | ```{r building_levels, warning = FALSE}
202 | hd_station_500m <- ohsome_boundary("8.67542,49.40347,500")
203 |
204 | ohsome_elements_geometry(
205 | boundary = hd_station_500m,
206 | filter = "building=* and type:way",
207 | time = "2021-12-01",
208 | properties = "tags",
209 | clipGeometry = FALSE
210 | ) |>
211 | ohsome_post() |>
212 | transmute(level = factor(`building:levels`)) |>
213 | mapview(zcol = "level", lwd = 0, layer.name = "Building level")
214 | ```
215 |
216 | Similarly, you can use `ohsome_elements_centroid()` to extract centroids of OSM
217 | elements and `ohsome_elements_bbox()` for their bounding boxes. Note that OSM
218 | node elements (with point geometries) are omitted from the results if querying
219 | for bounding boxes.
220 |
221 |
222 | #### Extracting the full history of OSM elements
223 |
224 | While the elements extraction endpoints provide geometries and properties of OSM
225 | elements at specific timestamps, results of queries to the
226 | [full history endpoints](https://docs.ohsome.org/ohsome-api/v1/endpoints.html#elements-full-history-extraction){target=blank}
227 | will include all changes to matching OSM features with corresponding
228 | `validFrom` and `validTo` timestamps.
229 |
230 | Here, we request the full history of OSM buildings within 500 m of Heidelberg
231 | main station, filter for features that still exist and visualize all building
232 | features with their year of creation:
233 |
234 | ```{r buildings}
235 | hd_station_1km <- ohsome_boundary("8.67542,49.40347,1000")
236 |
237 | ohsome_elements_geometry(
238 | boundary = hd_station_1km,
239 | filter = "building=* and type:way",
240 | time = "2021-12-01",
241 | properties = "tags",
242 | clipGeometry = FALSE
243 | ) |>
244 | ohsome_post() |>
245 | transmute(level = factor(`building:levels`)) |>
246 | mapview(zcol = "level", lwd = 0, layer.name = "Building level")
247 | ```
248 |
249 | You may find using `clean_names()` from the
250 | [janitor](https://github.com/sfirke/janitor){target=blank}
251 | package helpful in order to remove special characters from column names in the
252 | parsed ohsome API response -- just as in the example above.
253 |
254 | ### OSM contributions
255 |
256 | #### Aggregating OSM contributions
257 |
258 | With queries to the ohsome API's
259 | [contributions aggregation endpoints](https://docs.ohsome.org/ohsome-api/v1/endpoints.html#contributions-aggregation){target=blank},
260 | you can get counts of the contributions provided by users to OSM. The following
261 | code requests the number of deletions of man-made objects at the location
262 | of the hypothetical
263 | [Null Island](https://en.wikipedia.org/wiki/Null_Island){target=blank}
264 | per year between 2010 and 2020:
265 |
266 | ```{r contribution_count}
267 | ohsome_contributions_count(
268 | boundary = "0,0,10",
269 | filter = "man_made=*",
270 | time = "2010/2020/P1Y",
271 | contributionType = "deletion"
272 | ) |>
273 | ohsome_post()
274 | ```
275 |
276 | The `contributionType` parameter is used to filter for specific types of
277 | contributions (in this case: deletions). If it is not set, any contribution is
278 | counted. Note that the resulting values apply to time intervals defined by a
279 | `fromTimestamp` and a `toTimestamp`.
280 |
281 | #### Extracting OSM contributions
282 |
283 | The
284 | [contributions extraction](https://docs.ohsome.org/ohsome-api/v1/endpoints.html#contributions-extraction){target=blank}
285 | endpoints of the ohsome API can be used to extract feature geometries of
286 | contributions.
287 |
288 | In the following example, we extract the centroids of all amenities in the Berlin
289 | city district of Neukölln that have had contributions in March 2020.
290 | Consequently, we filter for features that have had tags changed and visualize
291 | their locations:
292 |
293 | ```{r contribution_extraction}
294 | nominatimlite::geo_lite_sf("Berlin Neukoelln", points_only = FALSE) |>
295 | ohsome_contributions_centroid() |>
296 | set_filter("amenity=*") |>
297 | set_time("2020-03,2020-04") |>
298 | set_properties("contributionTypes") |>
299 | ohsome_post() |>
300 | filter(`@tagChange`) |>
301 | mapview(layer.name = "Amenities with Tag Changes")
302 | ```
303 |
304 | ### OSM users
305 |
306 | You can get statistics on the number of users editing specific features through
307 | the
308 | [users aggregation](https://docs.ohsome.org/ohsome-api/v1/endpoints.html#users-aggregation){target=blank}
309 | endpoints of the ohsome API.
310 |
311 | Here, we show the number of users editing buildings before, during and after
312 | the Nepal earthquake 2015:
313 |
314 | ```{r nepal}
315 | ohsome_users_count(
316 | boundary = "82.3055,6.7576,87.4663,28.7025",
317 | filter = "building=* and geometry:polygon",
318 | time = "2015-03-01/2015-08-01/P1M"
319 | ) |>
320 | ohsome_post()
321 | ```
322 |
323 | ### Bounding geometries
324 |
325 | The ohsome API requires bounding geometries either as bounding polygons
326 | (`bpolys`), bounding boxes (`bboxes`) or bounding circles (`bcircles`)
327 | parameters to the query in a textual form (see
328 | [ohsome API documentation](https://docs.ohsome.org/ohsome-api/stable/boundaries.html){target=blank}).
329 | The ohsome R package uses the generic function `ohsome_boundary()` under the
330 | hood to make your life easier. It accepts a wider range of input geometry
331 | formats, while guessing the right type of bounding geometry.
332 |
333 | As seen above, `sf` objects can be passed into the `boundary` argument of
334 | `ohsome_query()` and any of its wrapper functions. You can also update queries
335 | with `set_boundary()`. The `sf` object will be converted into GeoJSON and passed
336 | into the `bpolys` parameter of the query.
337 |
338 | If you wish to aggregate or extract OSM elements on administrative boundaries in
339 | the `sf` format, you might want to check out packages such as
340 | [rnaturalearth](https://github.com/ropensci/rnaturalearth){target=blank},
341 | [geodata](https://github.com/rspatial/geodata){target=blank},
342 | [raster](https://github.com/rspatial/raster){target=blank}
343 | (in particular its `getData()` function),
344 | [rgeoboundaries](https://gitlab.com/dickoa/rgeoboundaries){target=blank} or
345 | [nominatimlite](https://github.com/dieghernan/nominatimlite){target=blank}
346 | for the acquisition of boundary data that can be used with
347 | `ohsome_boundary()`.
348 |
349 | There are also the following methods of `ohsome_boundary()` for other classes
350 | of input geometry objects:
351 |
352 | 1. `bbox` objects created with `st_bbox` are converted into a textual `bboxes`
353 | parameter to the query:
354 |
355 | ```{r bbox}
356 | q <- ohsome_query("users/count") |>
357 | set_boundary(sf::st_bbox(franconia))
358 |
359 | q$body$bboxes
360 | ```
361 |
362 | 2. `matrix` objects created with `sp::bbox()`, `raster::bbox()` or
363 | `terra::bbox()` are also converted into a textual `bboxes` parameter. This even
364 | applies for matrices created with `osmdata::getbb()` and `tmaptools::bb()`, so
365 | that you can comfortably acquire bounding boxes from the Nominatim API:
366 |
367 | ```{r getbb}
368 | osmdata::getbb("Kigali") |>
369 | ohsome_elements_length(time = "2018/2018-12/P1M", filter = "route=bus") |>
370 | ohsome_post()
371 | ```
372 |
373 | 3. You can pass any `character` object with text in the
374 | [format allowed by the ohsome API](https://docs.ohsome.org/ohsome-api/stable/boundaries.html){target=blank}
375 | to `ohsome_boundary()` -- even GeoJSON FeatureCollections. It will automatically
376 | detect whether you have passed the definition of `bpolys`, `bboxes` or
377 | `bcircles`. It is possible to use `character` vectors where each element
378 | represents one geometry:
379 |
380 | ```{r circles}
381 | c("Circle 1:8.6528,49.3683,1000", "Circle 2:8.7294,49.4376,1000") |>
382 | ohsome_elements_count(filter = "amenity=*", grouping = "boundary", time = 2021) |>
383 | ohsome_post()
384 | ```
385 |
386 | While `sf` and `bbox` objects will be automatically
387 | transformed to WGS 84 if in a different coordinate reference system, coordinates
388 | in `character` and `matrix` objects always need to be provided as WGS 84.
389 |
390 | ### Modifying queries
391 |
392 | As seen above, existing `ohsome_query` objects can be modified by
393 | `set_endpoint()`, `set_grouping()`, `set_boundary()` or `set_time()`. The latter
394 | and other functions such as `set_filter()` are just wrappers around the more
395 | generic `set_parameters()`. This can be used to modify the parameters of a query
396 | in any possible way:
397 |
398 | ```{r set_parameters}
399 | q <- ohsome_elements_count("8.5992,49.3567,8.7499,49.4371")
400 |
401 | q |>
402 | set_endpoint("ratio", append = TRUE) |>
403 | set_parameters(
404 | filter = "building=*",
405 | filter2 = "building=* and building:levels=*",
406 | time = "2010/2020/P2Y"
407 | ) |>
408 | ohsome_post()
409 |
410 | ```
411 |
412 | ### Grouping
413 |
414 | [Grouping endpoints](https://docs.ohsome.org/ohsome-api/v1/group-by.html){target=blank}
415 | are available for aggregation resources and can be used to compute the
416 | aggregated results grouped by:
417 |
418 | - boundary,
419 | - key,
420 | - tag, and
421 | - type.
422 |
423 | In many cases, a grouping by `boundary` can be combined with a grouping by `tag`.
424 | Some of the grouping endpoints require additional query parameters, e.g. `tag`
425 | groupings require a `groupByKey` parameter. Not all grouping endpoints are
426 | available for all aggregation resources -- please consult the
427 | [ohsome API documentation](https://docs.ohsome.org/ohsome-api/v1/group-by.html){target=blank}
428 | for details.
429 |
430 | You can set the `grouping` argument to any aggregation endpoint wrapper function
431 | (e.g. `ohsome_elements_count(grouping = c("boundary", "tag"))`) or use
432 | `set_grouping()` to modify existing query objects.
433 |
434 | ### Density and ratio requests
435 |
436 | Many
437 | [aggregation resources](https://docs.ohsome.org/ohsome-api/v1/endpoints.html){target=blank}
438 | have endpoints for requesting density (i.e. count, length, perimeter or area of
439 | features **per area**) or ratios (of OSM elements satisfying a `filter2` to elements
440 | satisfying a `filter`) instead of or in addition to absolute values.
441 |
442 | You can request density or ratio values by setting the `return_value` argument
443 | to aggregation endpoint wrapper functions (e.g.
444 | `ohsome_elements_count(return_value = "density")`). Mind that ratio endpoints
445 | require an additional `filter2` query parameter. Please consult the
446 | [ohsome API documentation](https://docs.ohsome.org/ohsome-api/v1/endpoints.html){target=blank}
447 | or print `names(ohsome_endpoints)` to the console in order to check for the
448 | availability of specific density and ratio endpoints.
449 |
450 | ### Dealing with complex API responses
451 |
452 | The ohsome API allows grouping aggregate values for various timestamps by
453 | boundary and tag at the same time. The parsed content of the response can be
454 | rather complex. In the following case, building feature counts for the districts
455 | of Franconia at two different timestamps are requested -- additionally grouped
456 | by the building:levels tag. To avoid lots of redundant geometries,
457 | comma-separated values (instead of GeoJSON) are explicitly requested as the
458 | response format:
459 |
460 | ```{r groupby_boundary_groupby_tag, message = FALSE}
461 | building_levels <- franconia |>
462 | mutate(id = NUTS_ID) |>
463 | ohsome_elements_count(grouping = c("boundary", "tag"), format = "csv") |>
464 | set_filter("building=* and geometry:polygon") |>
465 | set_time("2015/2020") |>
466 | set_groupByKey("building:levels") |>
467 | ohsome_post()
468 |
469 | dim(building_levels)
470 | ```
471 |
472 | The query results in a confusing data.frame. This happens because there is a
473 | building count column for each combination of boundary polygon and number of
474 | levels, while the two requested timestamps are in the rows. Fortunately, there
475 | is the
476 | [tidyr](https://tidyr.tidyverse.org){target=blank}
477 | package to do its magic and pivot this table into a long format
478 | with one value per row:
479 |
480 | ```{r tidy}
481 | library(tidyr)
482 |
483 | building_levels |>
484 | pivot_longer(-timestamp, names_to = c("id", "levels"), names_sep = "_")
485 | ```
486 |
487 | ## How to cite this package
488 |
489 | In order to cite this package in publications, please use the citation
490 | information provided through `citation("ohsome")`.
491 |
492 | -----
493 |
494 |
495 |
--------------------------------------------------------------------------------