Compare commits

...

2 Commits

@ -1,6 +1,6 @@
Package: opensensmapr Package: opensensmapr
Type: Package Type: Package
Title: Client for the Data API of openSenseMap.org Title: Client for the Data API of 'openSenseMap.org'
Version: 0.6.0 Version: 0.6.0
URL: https://github.com/sensebox/opensensmapR URL: https://github.com/sensebox/opensensmapR
BugReports: https://github.com/sensebox/opensensmapR/issues BugReports: https://github.com/sensebox/opensensmapR/issues

@ -4,7 +4,7 @@
\alias{filter.osem_measurements} \alias{filter.osem_measurements}
\title{Return rows with matching conditions, while maintaining class & attributes} \title{Return rows with matching conditions, while maintaining class & attributes}
\usage{ \usage{
filter.osem_measurements(.data, ..., .dots) \method{filter}{osem_measurements}(.data, ..., .dots)
} }
\arguments{ \arguments{
\item{.data}{A osem_measurements data.frame to filter} \item{.data}{A osem_measurements data.frame to filter}

@ -4,7 +4,7 @@
\alias{filter.sensebox} \alias{filter.sensebox}
\title{Return rows with matching conditions, while maintaining class & attributes} \title{Return rows with matching conditions, while maintaining class & attributes}
\usage{ \usage{
filter.sensebox(.data, ..., .dots) \method{filter}{sensebox}(.data, ..., .dots)
} }
\arguments{ \arguments{
\item{.data}{A sensebox data.frame to filter} \item{.data}{A sensebox data.frame to filter}

@ -4,7 +4,7 @@
\alias{mutate.osem_measurements} \alias{mutate.osem_measurements}
\title{Add new variables to the data, while maintaining class & attributes} \title{Add new variables to the data, while maintaining class & attributes}
\usage{ \usage{
mutate.osem_measurements(.data, ..., .dots) \method{mutate}{osem_measurements}(.data, ..., .dots)
} }
\arguments{ \arguments{
\item{.data}{A osem_measurements data.frame to mutate} \item{.data}{A osem_measurements data.frame to mutate}

@ -4,7 +4,7 @@
\alias{mutate.sensebox} \alias{mutate.sensebox}
\title{Add new variables to the data, while maintaining class & attributes} \title{Add new variables to the data, while maintaining class & attributes}
\usage{ \usage{
mutate.sensebox(.data, ..., .dots) \method{mutate}{sensebox}(.data, ..., .dots)
} }
\arguments{ \arguments{
\item{.data}{A sensebox data.frame to mutate} \item{.data}{A sensebox data.frame to mutate}

@ -4,7 +4,7 @@
\alias{st_as_sf.osem_measurements} \alias{st_as_sf.osem_measurements}
\title{Convert a \code{osem_measurements} dataframe to an \code{\link[sf]{st_sf}} object.} \title{Convert a \code{osem_measurements} dataframe to an \code{\link[sf]{st_sf}} object.}
\usage{ \usage{
st_as_sf.osem_measurements(x, ...) \method{st_as_sf}{osem_measurements}(x, ...)
} }
\arguments{ \arguments{
\item{x}{The object to convert} \item{x}{The object to convert}

@ -4,7 +4,7 @@
\alias{st_as_sf.sensebox} \alias{st_as_sf.sensebox}
\title{Convert a \code{sensebox} dataframe to an \code{\link[sf]{st_sf}} object.} \title{Convert a \code{sensebox} dataframe to an \code{\link[sf]{st_sf}} object.}
\usage{ \usage{
st_as_sf.sensebox(x, ...) \method{st_as_sf}{sensebox}(x, ...)
} }
\arguments{ \arguments{
\item{x}{The object to convert} \item{x}{The object to convert}

@ -2,21 +2,9 @@ source('testhelpers.R')
context('box') context('box')
try({ try({
boxes = osem_boxes()
box = osem_box('57000b8745fd40c8196ad04c') box = osem_box('57000b8745fd40c8196ad04c')
}) })
test_that('a single box can be retrieved by ID', {
check_api()
box = osem_box(boxes$X_id[[1]])
expect_true('sensebox' %in% class(box))
expect_true('data.frame' %in% class(box))
expect_true(nrow(box) == 1)
expect_true(box$X_id == boxes$X_id[[1]])
expect_silent(osem_box(boxes$X_id[[1]]))
})
test_that('required box attributes are correctly parsed', { test_that('required box attributes are correctly parsed', {
check_api() check_api()
@ -61,11 +49,6 @@ test_that('unknown box throws', {
expect_error(osem_box('57000b8745fd40c800000000'), 'not found') expect_error(osem_box('57000b8745fd40c800000000'), 'not found')
}) })
test_that('[.sensebox maintains attributes', {
check_api()
expect_true(all(attributes(boxes[1:nrow(boxes), ]) %in% attributes(boxes)))
})
test_that("print.sensebox filters important attributes for a single box", { test_that("print.sensebox filters important attributes for a single box", {
check_api() check_api()

@ -172,3 +172,44 @@ test_that('requests can be cached', {
osem_clear_cache() osem_clear_cache()
expect_length(list.files(tempdir(), pattern = 'osemcache\\..*\\.rds'), 0) expect_length(list.files(tempdir(), pattern = 'osemcache\\..*\\.rds'), 0)
}) })
context('single box from boxes')
test_that('a single box can be retrieved by ID', {
check_api()
box = osem_box(boxes$X_id[[1]])
expect_true('sensebox' %in% class(box))
expect_true('data.frame' %in% class(box))
expect_true(nrow(box) == 1)
expect_true(box$X_id == boxes$X_id[[1]])
expect_silent(osem_box(boxes$X_id[[1]]))
})
test_that('[.sensebox maintains attributes', {
check_api()
expect_true(all(attributes(boxes[1:nrow(boxes), ]) %in% attributes(boxes)))
})
context('measurements boxes')
test_that('measurements of specific boxes can be retrieved for one phenomenon and returns a measurements data.frame', {
check_api()
# fix for subsetting
class(boxes) = c('data.frame')
three_boxes = boxes[1:3, ]
class(boxes) = c('sensebox', 'data.frame')
three_boxes = osem_as_sensebox(three_boxes)
phens = names(osem_phenomena(three_boxes))
measurements = osem_measurements(x = three_boxes, phenomenon = phens[[1]])
expect_true(is.data.frame(measurements))
expect_true('osem_measurements' %in% class(measurements))
})
test_that('phenomenon is required when requesting measurements, error otherwise', {
check_api()
expect_error(osem_measurements(boxes), 'Parameter "phenomenon" is required')
})

@ -1,9 +1,6 @@
source('testhelpers.R') source('testhelpers.R')
context('measurements') context('measurements')
try({
boxes = osem_boxes()
})
test_that('measurements can be retrieved for a phenomenon', { test_that('measurements can be retrieved for a phenomenon', {
check_api() check_api()
@ -47,20 +44,6 @@ test_that('measurements can be retrieved for a phenomenon and exposure', {
expect_equal(nrow(measurements), 0) expect_equal(nrow(measurements), 0)
}) })
test_that('measurements of specific boxes can be retrieved for one phenomenon and returns a measurements data.frame', {
check_api()
# fix for subsetting
class(boxes) = c('data.frame')
three_boxes = boxes[1:3, ]
class(boxes) = c('sensebox', 'data.frame')
three_boxes = osem_as_sensebox(three_boxes)
phens = names(osem_phenomena(three_boxes))
measurements = osem_measurements(x = three_boxes, phenomenon = phens[[1]])
expect_true(is.data.frame(measurements))
expect_true('osem_measurements' %in% class(measurements))
})
test_that('measurements can be retrieved for a bounding box', { test_that('measurements can be retrieved for a bounding box', {
check_api() check_api()
@ -105,7 +88,6 @@ test_that('phenomenon is required when requesting measurements, error otherwise'
check_api() check_api()
expect_error(osem_measurements()) expect_error(osem_measurements())
expect_error(osem_measurements(boxes), 'Parameter "phenomenon" is required')
sfc = sf::st_sfc(sf::st_linestring(x = matrix(data = c(7, 8, 50, 51), ncol = 2)), crs = 4326) sfc = sf::st_sfc(sf::st_linestring(x = matrix(data = c(7, 8, 50, 51), ncol = 2)), crs = 4326)
bbox = sf::st_bbox(sfc) bbox = sf::st_bbox(sfc)

@ -115,7 +115,9 @@ berlin = st_point(c(13.4034, 52.5120)) %>%
st_transform(4326) %>% # the opensensemap expects WGS 84 st_transform(4326) %>% # the opensensemap expects WGS 84
st_bbox() st_bbox()
``` ```
```{r results = F}
Since the API takes quite long to response measurements, especially filtered on space and time, we do not run the following chunks for publication of the package on CRAN.
```{r results = F, eval=FALSE}
pm25 = osem_measurements( pm25 = osem_measurements(
berlin, berlin,
phenomenon = 'PM2.5', phenomenon = 'PM2.5',
@ -129,7 +131,7 @@ plot(pm25)
Now we can get started with actual spatiotemporal data analysis. Now we can get started with actual spatiotemporal data analysis.
First, lets mask the seemingly uncalibrated sensors: First, lets mask the seemingly uncalibrated sensors:
```{r} ```{r, eval=FALSE}
outliers = filter(pm25, value > 100)$sensorId outliers = filter(pm25, value > 100)$sensorId
bad_sensors = outliers[, drop = T] %>% levels() bad_sensors = outliers[, drop = T] %>% levels()
@ -138,13 +140,13 @@ pm25 = mutate(pm25, invalid = sensorId %in% bad_sensors)
Then plot the measuring locations, flagging the outliers: Then plot the measuring locations, flagging the outliers:
```{r} ```{r, eval=FALSE}
st_as_sf(pm25) %>% st_geometry() %>% plot(col = factor(pm25$invalid), axes = T) st_as_sf(pm25) %>% st_geometry() %>% plot(col = factor(pm25$invalid), axes = T)
``` ```
Removing these sensors yields a nicer time series plot: Removing these sensors yields a nicer time series plot:
```{r} ```{r, eval=FALSE}
pm25 %>% filter(invalid == FALSE) %>% plot() pm25 %>% filter(invalid == FALSE) %>% plot()
``` ```

@ -71,7 +71,7 @@ osem_clear_cache(getwd()) # clears a custom cache
If you want to roll your own serialization method to support custom data formats, If you want to roll your own serialization method to support custom data formats,
here's how: here's how:
```{r data, results='hide'} ```{r data, results='hide', eval=FALSE}
# first get our example data: # first get our example data:
measurements = osem_measurements('Windgeschwindigkeit') measurements = osem_measurements('Windgeschwindigkeit')
``` ```
@ -79,7 +79,7 @@ measurements = osem_measurements('Windgeschwindigkeit')
If you are paranoid and worry about `.rds` files not being decodable anymore If you are paranoid and worry about `.rds` files not being decodable anymore
in the (distant) future, you could serialize to a plain text format such as JSON. in the (distant) future, you could serialize to a plain text format such as JSON.
This of course comes at the cost of storage space and performance. This of course comes at the cost of storage space and performance.
```{r serialize_json} ```{r serialize_json, eval=FALSE}
# serializing senseBoxes to JSON, and loading from file again: # serializing senseBoxes to JSON, and loading from file again:
write(jsonlite::serializeJSON(measurements), 'measurements.json') write(jsonlite::serializeJSON(measurements), 'measurements.json')
measurements_from_file = jsonlite::unserializeJSON(readr::read_file('measurements.json')) measurements_from_file = jsonlite::unserializeJSON(readr::read_file('measurements.json'))
@ -90,7 +90,7 @@ This method also persists the R object metadata (classes, attributes).
If you were to use a serialization method that can't persist object metadata, you If you were to use a serialization method that can't persist object metadata, you
could re-apply it with the following functions: could re-apply it with the following functions:
```{r serialize_attrs} ```{r serialize_attrs, eval=FALSE}
# note the toJSON call instead of serializeJSON # note the toJSON call instead of serializeJSON
write(jsonlite::toJSON(measurements), 'measurements_bad.json') write(jsonlite::toJSON(measurements), 'measurements_bad.json')
measurements_without_attrs = jsonlite::fromJSON('measurements_bad.json') measurements_without_attrs = jsonlite::fromJSON('measurements_bad.json')
@ -101,6 +101,6 @@ class(measurements_with_attrs)
``` ```
The same goes for boxes via `osem_as_sensebox()`. The same goes for boxes via `osem_as_sensebox()`.
```{r cleanup, include=FALSE} ```{r cleanup, include=FALSE, eval=FALSE}
file.remove('measurements.json', 'measurements_bad.json') file.remove('measurements.json', 'measurements_bad.json')
``` ```

Loading…
Cancel
Save