Compare commits

...

2 Commits

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

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

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

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

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

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

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

@ -2,21 +2,9 @@ source('testhelpers.R')
context('box')
try({
boxes = osem_boxes()
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', {
check_api()
@ -61,11 +49,6 @@ test_that('unknown box throws', {
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", {
check_api()

@ -172,3 +172,44 @@ test_that('requests can be cached', {
osem_clear_cache()
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')
context('measurements')
try({
boxes = osem_boxes()
})
test_that('measurements can be retrieved for a phenomenon', {
check_api()
@ -47,20 +44,6 @@ test_that('measurements can be retrieved for a phenomenon and exposure', {
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', {
check_api()
@ -105,7 +88,6 @@ test_that('phenomenon is required when requesting measurements, error otherwise'
check_api()
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)
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_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(
berlin,
phenomenon = 'PM2.5',
@ -129,7 +131,7 @@ plot(pm25)
Now we can get started with actual spatiotemporal data analysis.
First, lets mask the seemingly uncalibrated sensors:
```{r}
```{r, eval=FALSE}
outliers = filter(pm25, value > 100)$sensorId
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:
```{r}
```{r, eval=FALSE}
st_as_sf(pm25) %>% st_geometry() %>% plot(col = factor(pm25$invalid), axes = T)
```
Removing these sensors yields a nicer time series plot:
```{r}
```{r, eval=FALSE}
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,
here's how:
```{r data, results='hide'}
```{r data, results='hide', eval=FALSE}
# first get our example data:
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
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.
```{r serialize_json}
```{r serialize_json, eval=FALSE}
# serializing senseBoxes to JSON, and loading from file again:
write(jsonlite::serializeJSON(measurements), '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
could re-apply it with the following functions:
```{r serialize_attrs}
```{r serialize_attrs, eval=FALSE}
# note the toJSON call instead of serializeJSON
write(jsonlite::toJSON(measurements), '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()`.
```{r cleanup, include=FALSE}
```{r cleanup, include=FALSE, eval=FALSE}
file.remove('measurements.json', 'measurements_bad.json')
```

Loading…
Cancel
Save