Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@ Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2
Imports:
archive,
cli,
data.table,
dplyr,
httr2,
jsonlite,
lubridate,
sf,
stringr
stringr,
tibble,
tidyr
URL: https://samherniman.github.io/autocruller/
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Generated by roxygen2: do not edit by hand

export(ac_get_co2)
export(ac_get_co2_download)
export(ac_get_co2_transit)
export(ac_get_co2_web)
export(ac_unnest_longer)
55 changes: 27 additions & 28 deletions R/ac_get_co2.R
Original file line number Diff line number Diff line change
@@ -1,44 +1,43 @@
#' Get data from indoorco2map.org
#'
#' @param x Character specifying which dataset to download one of c("web", "download", "transit")
#'
#' @returns A dataframe with up to date co2 measurements
#' @export
#'
#' @examples
#' \dontrun{
#' # Get building data with one of three options
#' ac_df <- ac_get_co2()
#' ac_df <- ac_get_co2("web")
#' ac_df <- ac_get_co2("download")
#'
#' # Get transit data
#' ac_df <- ac_get_co2("transit")
#' }
#'
ac_get_co2 <- function() {
measurements <- .id <- startTime <- NULL
ac_get_co2 <- function(x = "web") {

icm_response <-
httr2::request("https://indoorco2map.com/chartdata/IndoorCO2MapData.json.gz") |>
httr2::req_perform() |>
httr2::resp_body_json()
if (!(x %in% c("web", "download", "transit"))) {
cli::cli_abort(c(
"Error while getting co2 data:",
"x must be either \"web\", \"download\", or \"transit\"",
"if you want building data, set x to \"web\"",
"if you want transit data, set x to \"transit\""
))
}

if (x == "web") {
return(ac_get_co2_web())
}

icm_response <-
data.table::rbindlist(icm_response, idcol = TRUE) |>
suppressWarnings()
if (x == "download") {
return(ac_get_co2_download())
}

j_lst <- lapply(icm_response$measurements, jsonlite::fromJSON)
j_lst <- lapply(j_lst, co2_to_numeric)
j_lst <- data.table::rbindlist(j_lst, idcol = TRUE)

ac_df <- icm_response |>
dplyr::select(-measurements) |>
dplyr::left_join(j_lst, by = dplyr::join_by(.id)) |>
dplyr::mutate(
# remove the last few digits from the unix time because they are in milliseconds and not needed
date = stringr::str_sub(startTime, end = -4) |>
as.numeric() |>
as.POSIXct()
) |>
sf::st_as_sf(
coords = c("lon", "lat"),
crs = sf::st_crs(4326)
)

return(ac_df)
if (x == "transit") {
return(ac_get_co2_transit())
}
}

#' Convert the co2 character array to a numeric list
Expand Down
39 changes: 39 additions & 0 deletions R/ac_get_co2_download.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

#' Get data from indoorco2map.org - "download version"
#'
#' @returns A dataframe with co2 building measurements
#'
#' @details
#' This function will download the version of building
#' data that is available using the "download" button on
#' the website
#'
#'
#' @export
#' @examples
#'
#' \dontrun{
#' ac_df <- ac_get_co2_download()
#' }
ac_get_co2_download <- function() {
co2readingsAvg <- startOfMeasurement <- NULL
icm_response <-
archive::archive_extract(
"https://indoorco2map.com/chartdata/IndoorCO2MapData.zip",
files = 3
) |>
jsonlite::fromJSON() |>
tibble::rowid_to_column("obs_number") |>
dplyr::mutate(
date = lubridate::as_datetime(startOfMeasurement),
day = lubridate::date(date)
) |>
sf::st_as_sf(
coords = c("longitude", "latitude"),
crs = sf::st_crs(4326)
)
unlink('indoorco2mapData.json')

return(icm_response)
}

93 changes: 93 additions & 0 deletions R/ac_get_co2_transit.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#' Get transit data from indoorco2map.org
#'
#' @returns A dataframe with up to date co2 transit measurements
#'
#' @export
#' @examples
#' \dontrun{
#' ac_df <- ac_get_co2_transit()
#' }
ac_get_co2_transit <- function() {
icm_response <-
httr2::request("https://rkhby3mvq3.execute-api.eu-central-1.amazonaws.com/GetTransportCO2Data") |>
httr2::req_perform() |>
httr2::resp_body_json() |>
unlist() |>
lapply(jsonlite::fromJSON)

j_df <- do.call(rbind, icm_response) |>
tibble::rowid_to_column("uid")

j_df <- lapply(1:nrow(j_df), \(x) json_to_df(j_df[x,]))
j_df <-
do.call(rbind, j_df) |>
sf::st_as_sf(
coords = c("long_first", "lat_first"),
crs = sf::st_crs(4326)
) |>
sf::st_make_valid()

return(j_df)
}

#' Turn a co2 json into a dataframe
#'
#' @param x A json
#'
#' @returns a dataframe
json_to_df <- function(x) {
timestampArray <-
co2Array <-
longitudeArray <-
latitudeArray <-
startTime <-
uid <-
ppmAvg <-
NULL
x |>
dplyr::mutate(
timestampArray = split_to_numeric(timestampArray) |> range01() |> paste(collapse = ";"),
# mod_loess = list(train_loess(co2_vec = co2Array, time_vec = timestampArray)),
co2Array = stringr::str_replace_all(co2Array, ";", ","),
longitudeArray = stringr::str_remove_all(longitudeArray, "(0;|0$)") |>
stringr::str_replace_all(",", "\\.") |>
stringr::str_replace_all(";", ","),
latitudeArray = stringr::str_remove_all(latitudeArray, "(0;|0$)") |>
stringr::str_replace_all(",", "\\.") |>
stringr::str_replace_all(";", ","),
date = stringr::str_sub(startTime, end = -4) |>
as.numeric() |>
as.POSIXct()
) |>
tidyr::separate_longer_delim(cols = c(co2Array), delim = ",") |>
dplyr::distinct() |>
dplyr::mutate(
long_first = stringr::str_split_i(longitudeArray, ",", 1) |> as.numeric(),
lat_first = stringr::str_split_i(latitudeArray, ",", 1) |> as.numeric()
) |>
# sf::st_as_sf(coords = c("long_first", "lat_first"), crs = sf::st_crs(4326)) |>
dplyr::group_by(uid) |>
tibble::rowid_to_column("tsa") |>
dplyr::select(-ppmAvg) |>
tidyr::drop_na()
}

#' Create a vector of values evenly spaced between 0 and 1
#'
#' @param x vector of values
#' @param ... other parameters passed to min() or max()
#'
#' @returns vector of values evenly spaced between 0 and 1 the same length as x
range01 <- function(x, ...){(x - min(x, ...)) / (max(x, ...) - min(x, ...))}

#' Split a string seperated by ";" into numbers
#'
#' @param x a string of numbers seperated by ";"
#'
#' @returns a numeric vector
split_to_numeric <- function(x) {
x |>
strsplit(split = ";") |>
unlist() |>
as.numeric()
}
64 changes: 64 additions & 0 deletions R/ac_get_co2_web.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#' Get data from indoorco2map.org
#'
#' @returns A dataframe with up to date co2 measurements - "web version"
#' @export
#'
#' @details
#' This function will download the version of building
#' data that is displayed on the website map
#'
#'
#' @examples
#' \dontrun{
#' ac_df <- ac_get_co2_web()
#' }
#'
ac_get_co2_web <- function() {
measurements <- .id <- startTime <- obs_number <- co2array <- NULL

icm_response <-
httr2::request("https://indoorco2map.com/chartdata/IndoorCO2MapData.json.gz") |>
httr2::req_perform() |>
httr2::resp_body_json()

icm_response <-
data.table::rbindlist(icm_response, idcol = "obs_number") |>
suppressWarnings()

j_lst <- lapply(icm_response$measurements, jsonlite::fromJSON)
j_lst <- lapply(j_lst, co2_to_numeric)
j_lst <- data.table::rbindlist(j_lst, idcol = "obs_number")

ac_df <- icm_response |>
dplyr::select(-measurements) |>
dplyr::left_join(j_lst, by = dplyr::join_by(obs_number)) |>
dplyr::mutate(
# remove the last few digits from the unix time because they are in milliseconds and not needed
date = stringr::str_sub(startTime, end = -4) |>
as.numeric() |>
as.POSIXct()
) |>
dplyr::select(-co2array) |>
sf::st_as_sf(
coords = c("lon", "lat"),
crs = sf::st_crs(4326)
)

return(ac_df)
}

#' Convert the co2 character array to a numeric list
#'
#' @param x a list containing measurements from json
#'
#' @returns list of co2 records
#'
co2_to_numeric <- function(x) {
x$co2readings <-
x$co2array |>
stringr::str_split(";", simplify = TRUE) |>
as.numeric() |>
list()

return(x)
}
27 changes: 27 additions & 0 deletions R/ac_unnest_longer.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#' Unnest a co2 df list-column into rows
#'
#' @param x a dataframe from ac_get_co2()
#'
#' @returns a dataframe in long format
#'
#' @export
#' @examples
#' ac_df <- ac_get_co2("download") |>
#' ac_unnest_longer()
ac_unnest_longer <- function(x) {
co2readings <- obs_number <- offset <- interval <- reading_index <- NULL
x_df <- x |> tidyr::unnest_longer(co2readings)

if (all(c("offset", "interval") %in% names(x))) {
x_df <- x_df |>
dplyr::group_by(obs_number) |>
dplyr::mutate(
reading_index = dplyr::row_number(),
date_time = lubridate::as_datetime(date) +
lubridate::dminutes(offset) +
lubridate::dminutes(interval * reading_index)
)
}

return(x_df)
}
27 changes: 12 additions & 15 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Download the latest data with `ac_get_co2()`
```{r getco2}
library(autocruller)

ac_df <- ac_get_co2()
ac_df <- ac_get_co2("download")
```

That will give you a dataframe with all the current CO^2^ measurements.
Expand All @@ -67,10 +67,10 @@ That will give you a dataframe with all the current CO^2^ measurements.
dplyr::glimpse(ac_df)
```

If you want the co2arrays to be in long format, you can do this:
If you want the co2readingss to be in long format, you can do this:

```{r}
ac_df_long <- tidyr::unnest_longer(ac_df, co2array)
ac_df_long <- ac_unnest_longer(ac_df)
```


Expand All @@ -91,11 +91,11 @@ types_c <- c(
"music", "nightclub", "social_centre", "concert_hall"
)
ac_df |>
dplyr::filter(osmtag %in% types_c) |>
dplyr::filter(osmTag %in% types_c) |>
tidyplot(
x = ventilation,
y = ppmavg,
color = ppmavg
x = ventilationSystem,
y = co2readingsAvg,
color = co2readingsAvg
) |>
add_data_points_beeswarm(size = 3) |>
adjust_y_axis(transform = "log2") |>
Expand All @@ -112,21 +112,18 @@ And track things over time with the long format data

```{r}
ac_df_long |>
dplyr::filter(.id == 127) |>
dplyr::mutate(
measurement_sequence = dplyr::row_number()
) |>
dplyr::filter(obs_number == 458) |>
tidyplot(
x = measurement_sequence,
y = co2array,
color = co2array
x = reading_index,
y = co2readings,
color = co2readings
) |>
add_data_points() |>
adjust_size(width = NA, height = NA, unit = "cm") |>
adjust_font(fontsize = 16) |>
adjust_x_axis_title("Time") |>
adjust_y_axis_title("CO2 ppm") |>
remove_legend() |>
adjust_title("CO2 measurements at recording 127") |>
adjust_title("CO2 measurements at recording 458") |>
adjust_caption("Data from indoorCO2map.com")
```
Loading
Loading