diff --git a/NAMESPACE b/NAMESPACE index 092369c..2fa77d9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -17,9 +17,8 @@ export(gap_handler) export(gapless_Datetimes) export(gg_day) export(gg_overview) -export(import.ActLumus) +export(import) export(import.Dataset) -export(import.LYS) export(import.Statechanges) export(interval2state) export(join.datasets) diff --git a/NEWS.md b/NEWS.md index d62f48b..383ca0c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # LightLogR 0.2.1.9000 +* Reworked the internals of the light logger data import functions. They now use a more straightforward function factory approach. For users the only visible change it that device specific functions now have the form `import$device()` instead of the old `import.device()`. + * Added the `symlog_trans()` function from a [post on stack overflow](https://stackoverflow.com/a/14674703). This function leads to a better visualization of light logger data, as a logarithmic transformation is necessary, but values of 0 are common. The function was integrated as a default for `gg_day()` and will likely be the basis of upcoming visualization functions. * Added the `aggregate_Datetime()` function to aggregate data to a given time interval. diff --git a/R/aaa.r b/R/aaa.r index 0b4f14f..14e55c2 100644 --- a/R/aaa.r +++ b/R/aaa.r @@ -1,4 +1,4 @@ -Time <- mEDI <- Time.data <- Datetime <- timestamp <- tz <- Day.data <- `DATE/TIME` <- n <- Datetime.rounded <- id <- sleep.colname.string <- file.name <- Interval <- original.datapoints.fleeting <- MEDI <- State.Brown <- Reference <- Reference.check <- Id <- Start.date.shift <- data <- Shift <- `MELANOPIC EDI` <- State <- group <- End <- Start <- Quant.x <- Quant.y <- is.implicit <- group.indices <- Id2 <- gap.id <- start <- end <- NULL +Time <- mEDI <- Time.data <- Datetime <- timestamp <- tz <- Day.data <- `DATE/TIME` <- n <- Datetime.rounded <- id <- sleep.colname.string <- file.name <- Interval <- original.datapoints.fleeting <- MEDI <- State.Brown <- Reference <- Reference.check <- Id <- Start.date.shift <- data <- Shift <- `MELANOPIC EDI` <- State <- group <- End <- Start <- Quant.x <- Quant.y <- is.implicit <- group.indices <- Id2 <- gap.id <- start <- end <- path <- auto.id <- n_max <- manual.id <- NULL empty_function <- function() { rsconnect::accountInfo() diff --git a/R/data.r b/R/data.r index 0c36ad8..74037bf 100644 --- a/R/data.r +++ b/R/data.r @@ -22,6 +22,11 @@ #' A vector of all supported devices for import functions #' +#' These are all supported devices where there is a dedicated import function. +#' Import functions can be called either through [import.Dataset()] with the +#' respective `device = "device"` argument, or directly, e.g., +#' `import$ActLumus()`. +#' #' @format `supported.devices` A character vector, listing all supported devices #' \describe{ #' \item{suppored.devices}{strings} diff --git a/R/import_LL.R b/R/import_LL.R index 3b5370d..28a1e8f 100644 --- a/R/import_LL.R +++ b/R/import_LL.R @@ -2,33 +2,44 @@ #' Import a light logger dataset or related data #' +#' @description +#' #' Imports a dataset and does the necessary transformations to get the right #' column formats. Unless specified otherwise, the function will set the #' timezone of the data to `UTC`. It will also enforce an `id` to separate #' different datasets and will order/arrange the dataset within each `id`. #' -#' If the `Id` column is already part of the `dataset` it will just use this -#' column. If the column is not present it will add this column and fill it with -#' the filename of the importfile (see param `auto.id`). +#' There are specific and a general import function. The general import function +#' is described below, whereas the specific import functions take the form of +#' `import$device()`. The general import function is a thin wrapper around the +#' specific import functions. The specific import functions take the following +#' arguments: +#' +#' * `filename`: Filename(s) for the Dataset. Can also contain the filepath, +#' but `path` must then be `NULL`. Expects a `character`. If the vector is +#' longer than `1`, multiple files will be read in into one Tibble. +#' * `path`: Optional path for the dataset(s). `NULL` is the default. Expects +#' a `character`. +#' * `n_max`: maximum number of lines to read. Default is `Inf`. +#' * `tz`: Timezone of the data. `"UTC"` is the default. Expects a +#' `character`. You can look up the supported timezones with [OlsonNames()]. +#' * `ID.colname`: Lets you specify a column for the participant id. Expects a +#' symbol (Default is `Id`). This column will be used for grouping +#' ([dplyr::group_by()]). +#' * `auto.id`: If the `Id.colname` column is added to the `dataset`, the `Id` +#' can be automatically extracted from the filename. The argument expects a +#' regular expression [regex] and will by default just give the whole filename +#' without file extension. +#' * `manual.id`: If this argument is not `NULL`, and no `ID` column is part +#' of the `dataset`, this `character` scalar will be used. **Don´t use this +#' argument if multiple files from different participants are used!** +#' * `locale`: The locale controls defaults that vary from place to place. +#' * `...`: supply additional arguments to the [readr] import functions, like `na`. Might also be used to supply arguments to the specific import functions, like `column_names` for `Actiwatch_Spectrum` devices. Those devices will alway throw a helpful error message if you forget to supply the necessary arguments. +#' +#' @details If the `Id` column is already part of the `dataset` it will just use +#' this column. If the column is not present it will add this column and fill +#' it with the filename of the importfile (see param `auto.id`). #' -#' @param filename Filename(s) for the Dataset. Can also contain the filepath, -#' but `path` must then be `NULL`. Expects a `character`. If the vector is -#' longer than `1`, multiple files will be read in into one Tibble. -#' @param path Optional path for the dataset(s). `NULL` is the default. Expects -#' a `character`. -#' @param n_max maximum number of lines to read. Default is `Inf`. -#' @param tz Timezone of the data. `"UTC"` is the default. Expects a -#' `character`. You can look up the supported timezones with [OlsonNames()]. -#' @param ID.colname Lets you specify a column for the participant id. Expects a -#' symbol (Default is `Id`). This column will be used for grouping -#' ([dplyr::group_by()]). -#' @param auto.id If the `Id.colname` column is added to the `dataset`, the `Id` -#' can be automatically extracted from the filename. The argument expects a -#' regular expression [regex] and will by default just give the whole filename -#' without file extension. -#' @param manual.id If this argument is not `NULL`, and no `ID` column is part -#' of the `dataset`, this `character` scalar will be used. -#' **Don´t use this argument if multiple files from different participants are used!**. #' @param ... Parameters that get handed down to the specific import functions #' @param device From what device do you want to import? For every supported #' device, there is a sample data file that you can use to test the function @@ -36,6 +47,7 @@ #' by the `device.ext` spec to access the sample file): #' * `"ActLumus"` (ActLumus.txt) #' * `"LYS"` (LYS.csv) +#' * `"Actiwatch_Spectrum"` (Actiwatch.csv) *Note: as the `locale` argument use `readr::locale(encoding="latin1")` . This is due to the fact that the German Actiwatch software from which this sample file was taken, uses a different encoding than UTF-8.* #' @importFrom rlang := #' @return Tibble/Dataframe with a POSIXct column for the datetime #' @export @@ -68,12 +80,12 @@ #' #' ```{r} #' filepath <- system.file("extdata/sample_data_ActLumus.txt", package = "LightLogR") -#' dataset <- import.ActLumus(filepath) +#' dataset <- import$ActLumus(filepath) #' ``` #' #' ```{r} #' dataset %>% -#' dplyr::select(Datetime, TEMPERATURE, LIGHT, MEDI) %>% +#' dplyr::select(Datetime, TEMPERATURE, LIGHT, MEDI, Id) %>% #' dplyr::slice(1500:1505) %>% #' flextable::flextable() %>% #' flextable::autofit() @@ -87,89 +99,172 @@ import.Dataset <- function(device, ...) { device %in% supported.devices ) - import_function_expr <- rlang::parse_expr(paste0("import.", device)) + import_function_expr <- rlang::parse_expr(paste0("import$", device)) eval(import_function_expr)(...) } -# ActLumus ---------------------------------------------------------------- - -#' Import Dataset from ActLumus -#' -#' @rdname import.Dataset -#' @export - -import.ActLumus <- - function(filename, - path = NULL, - n_max = Inf, - tz = "UTC", - ID.colname = Id, - auto.id = ".*", - manual.id = NULL) { - - if (!is.null(path)) { - filename <- file.path(path, filename) - } - - #special handling for ActLumus files - import.expr <- rlang::expr( - {tmp <- readr::read_delim(!!filename, - skip = 32, - delim = ";", - n_max = !!n_max, - col_types = paste0("c",rep("d",32)), - id = "file.name" +# General ---------------------------------------------------------------- +#This internal helper function is a function factory to create import functions +#based on device name and specific import expression +imports <- function(device, + import.expr) { + + import.expr <- rlang::enexpr(import.expr) + ID.colname <- quote({{ ID.colname}}) + + rlang::new_function( + #function arguments + rlang::exprs( + filename =, + path = NULL, + n_max = Inf, + tz = "UTC", + ID.colname = Id, + auto.id = ".*", + manual.id = NULL, + locale = readr::default_locale(), + ... = + ), + #function expression + rlang::expr({ + + if (!is.null(path)) { + filename <- file.path(path, filename) + } + + id.colname.defused <- colname.defused(!!ID.colname) + #initial checks + stopifnot( + "filename needs to be a character (vector)" = is.character(filename), + "device needs to be a character" = is.character(!!device), + "tz needs to be a character" = is.character(tz), + "tz needs to be a valid time zone, see `OlsonNames()`" = tz %in% OlsonNames(), + "auto.id needs to be a string" = is.character(auto.id), + "n_max needs to be a positive numeric" = is.numeric(n_max) ) - tmp <- tmp %>% - dplyr::rename(Datetime = `DATE/TIME`, - MEDI = `MELANOPIC EDI`) %>% - dplyr::mutate(Datetime = - Datetime %>% lubridate::dmy_hms(tz = !!tz)) + #import the file + tmp <- rlang::eval_tidy(!!import.expr) + + #validate/manipulate the file + if(!id.colname.defused %in% names(tmp)) { + switch(is.null(manual.id) %>% as.character(), + "TRUE" = + {tmp <- tmp %>% + dplyr::mutate(!!ID.colname := + basename(file.name) %>% + tools::file_path_sans_ext() %>% + stringr::str_extract(auto.id), + .before = 1)}, + "FALSE" = + {tmp <- tmp %>% + dplyr::mutate(!!ID.colname := manual.id, .before = 1)} + ) } + tmp <- tmp %>% + dplyr::mutate(file.name = basename(file.name) %>% + tools::file_path_sans_ext(), + !!ID.colname := factor(!!ID.colname)) %>% + dplyr::group_by(!!ID.colname) %>% + dplyr::arrange(Datetime, .by_group = TRUE) + + #give info about the file + import.info(tmp, !!device, tz, !!ID.colname) + + #return the file + tmp + + }), + rlang::caller_env() + ) +} + +import_arguments <- list( + #ActLumus + ActLumus = rlang::expr({ + tmp <- readr::read_delim( + filename, + skip = 32, + delim = ";", + n_max = n_max, + col_types = paste0("c", rep("d", 32)), + id = "file.name", + locale = locale, + ... + ) + tmp <- tmp %>% + dplyr::rename(Datetime = `DATE/TIME`, + MEDI = `MELANOPIC EDI`) %>% + dplyr::mutate(Datetime = + Datetime %>% lubridate::dmy_hms(tz = tz)) + }), + #LYS + LYS = rlang::expr({ + tmp <- readr::read_csv(filename, + n_max = n_max, + col_types = c("cfddddddddddd"), + id = "file.name", + locale = locale, + ... ) - - #generic import function - import.link("ActLumus", {{ ID.colname }}) - - } + tmp <- tmp %>% + dplyr::rename(Datetime = timestamp, + MEDI = mEDI) %>% + dplyr::mutate(Datetime = + Datetime %>% lubridate::dmy_hms(tz = tz)) + }), + #Actiwatch Spectrum + Actiwatch_Spectrum = rlang::expr({ + #separate the dots list in the column_names and the rest + dots <- rlang::list2(...) + column_names <- dots$column_names + if(is.null(column_names)) + stop("Actiwatch Spectrum requires a vector of `column_names` in the order in which they appear in the file in order to properly detect the starting row") + dots$column_names <- NULL + tmp <- + purrr::map( + filename, + \(x) { + rows_to_skip <- detect_starting_row(x, + locale = locale, + column_names = column_names, + n_max = n_max) + df <- suppressMessages(do.call( + readr::read_csv, + append(list( + x, + skip = rows_to_skip, + locale=locale, + id = "file.name", + show_col_types = FALSE + ), + dots))) + + df %>% + dplyr::select(!dplyr::starts_with("...")) + + }) %>% purrr::list_rbind() + tmp <- tmp %>% + tidyr::unite(col = "Datetime", + tidyselect::where(lubridate::is.Date), + tidyselect::where(hms::is_hms), + remove = FALSE + ) %>% + dplyr::mutate( + Datetime = lubridate::ymd_hms(Datetime), + dplyr::across( + dplyr::where(is.character) & + dplyr::where(~ any(stringr::str_detect(.x, ","), na.rm = TRUE)), + ~ stringr::str_replace(.x, ",", ".") %>% + as.numeric() + )) + }) -# LYS --------------------------------------------------------------------- +) -#' Import Dataset from LYS Button +#' Import Datasets from supported devices #' #' @rdname import.Dataset #' @export - -import.LYS <- function(filename, - path = NULL, - n_max = Inf, - tz = "UTC", - ID.colname = Id, - auto.id = ".*", - manual.id = NULL) { - - if (!is.null(path)) { - filename <- file.path(path, filename) - } - - #special handling for LYS files - import.expr <- rlang::expr( - {tmp <- readr::read_csv(!!filename, - n_max = !!n_max, - col_types = c("cfddddddddddd"), - id = "file.name" - ) - tmp <- tmp %>% - dplyr::rename(Datetime = timestamp, - MEDI = mEDI) %>% - dplyr::mutate(Datetime = - Datetime %>% lubridate::dmy_hms(tz = !!tz)) - } - ) - - #generic import function - import.link("LYS", {{ ID.colname }}) - -} +import <- purrr::imap(import_arguments, \(x, idx) imports(idx,x)) diff --git a/R/import_States.R b/R/import_States.R index e24bf68..7eb7671 100644 --- a/R/import_States.R +++ b/R/import_States.R @@ -8,7 +8,13 @@ #' * In the `wide` format, multiple `Datetime` columns indicate the state through the column name. These get pivoted to the `long` format and can be recoded through the `State.encoding` argument. #' * In the `long` format, one column indicates the `State`, while the other gives the `Datetime`. #' -#' @inheritParams import.Dataset +#' @param filename Filename(s) for the Dataset. Can also contain the filepath, +#' but `path` must then be `NULL`. Expects a `character`. If the vector is +#' longer than `1`, multiple files will be read in into one Tibble. +#' @param path Optional path for the dataset(s). `NULL` is the default. Expects +#' a `character`. +#' @param tz Timezone of the data. `"UTC"` is the default. Expects a +#' `character`. You can look up the supported timezones with [OlsonNames()]. #' @param sep String that separates columns in the import file. Defaults to #' `","`. #' @param dec String that indicates a decimal separator in the import file. diff --git a/R/import_helper.r b/R/import_helper.r index b989cc3..310a5c7 100644 --- a/R/import_helper.r +++ b/R/import_helper.r @@ -1,58 +1,3 @@ -#This internal helper function is used for setup of imports of various device files -import.LL <- function(filename, - device = "none", - import.expr, - n_max = Inf, - tz = "UTC", - ID.colname = Id, - auto.id = ".*", - manual.id = NULL) { - - id.colname.defused <- colname.defused(id) - tz <- tz - - #initial checks - stopifnot( - "filename needs to be a character (vector)" = is.character(filename), - "device needs to be a character" = is.character(device), - "tz needs to be a character" = is.character(tz), - "tz needs to be a valid time zone, see `OlsonNames()`" = tz %in% OlsonNames(), - "auto.id needs to be a string" = is.character(auto.id), - "n_max needs to be a positive numeric" = is.numeric(n_max) - ) - #import the file - tmp <- rlang::eval_tidy(import.expr) - - #validate/manipulate the file - if(!id.colname.defused %in% names(tmp)) { - switch(is.null(manual.id) %>% as.character(), - "TRUE" = - {tmp <- tmp %>% - dplyr::mutate({{ ID.colname }} := - basename(file.name) %>% - tools::file_path_sans_ext() %>% - stringr::str_extract(auto.id), - .before = 1)}, - "FALSE" = - {tmp <- tmp %>% - dplyr::mutate({{ ID.colname }} := manual.id, .before = 1)} - ) - } - tmp <- tmp %>% - dplyr::mutate(file.name = basename(file.name) %>% - tools::file_path_sans_ext(), - {{ ID.colname }} := factor({{ ID.colname }})) %>% - dplyr::group_by({{ ID.colname }}) %>% - dplyr::arrange(Datetime, .by_group = TRUE) - - #give info about the file - import.info(tmp, device, tz, {{ ID.colname }}) - - #return the file - tmp -} - - #This internal helper function prints basic information about a dataset and is used for import function import.info <- function(tmp, device, tz, ID.colname) { #give info about the file @@ -87,26 +32,43 @@ import.info <- function(tmp, device, tz, ID.colname) { utils::capture.output(interval.time)[c(-1,-2,-4)] %>% cat(sep = "\n") } -#This internal helper functions provides a link from the specific import function to the generic import function - -import.link <- function(device, ID.colname) { +#This internal helper function looks for the starting row of an import file based on a vector of column names in order. +detect_starting_row <- + function(filepath, + locale = readr::default_locale(), + column_names, + n_max = 250) { + + #make a regex pattern from the column names + column_names <- + column_names %>% + stringr::str_flatten(collapse = ".*") + + #read in all the lines and remove junk + line_read <- + readr::read_lines(filepath, n_max = n_max, locale=locale) - env <- parent.frame() - filename <- env$filename - tz<- env$tz - auto.id<- env$auto.id - manual.id <- env$manual.id - n_max<- env$n_max - path<- env$path - import.expr <- env$import.expr + #find the row where the column names are + which_lines <- + line_read %>% + purrr::map_vec( + \(x) stringr::str_detect(x,column_names) + ) %>% which() + + #if there is no line with the column names, return an error + if(length(which_lines) == 0) { + stop("Could not find a line with this order of column names in the file. Please check the correct order and spelling of the given columns.") + } + + #if there is more than one line with the column names, return an error + if(length(which_lines) > 1) { + stop(paste("Found", length(which_lines), "lines with the given column names, but require exactly 1. Please provide a more specific pattern.")) + } + + #if there is only one line with the column names, return the line number + #and reduce it by one to get the lines to skip + if(length(which_lines) == 1) { + return(which_lines-1) + } - #generic import function - import.LL(filename = filename, - device = device, - import.expr = import.expr, - n_max = n_max, - tz = tz, - manual.id = manual.id, - ID.colname = {{ ID.colname }}, - auto.id = auto.id) } \ No newline at end of file diff --git a/R/join.R b/R/join.R index 649da79..75e8726 100644 --- a/R/join.R +++ b/R/join.R @@ -17,8 +17,8 @@ #' package = "LightLogR") #' file.LL <- "205_actlumus_Log_1020_20230904101707532.txt.zip" #' file.env <- "cyepiamb_CW35_Log_1431_20230904081953614.txt.zip" -#' dataset.LL <- import.ActLumus(file.LL, path, auto.id = "^(\\d{3})") -#' dataset.env <- import.ActLumus(file.env, path, manual.id = "CW35") +#' dataset.LL <- import$ActLumus(file.LL, path, auto.id = "^(\\d{3})") +#' dataset.env <- import$ActLumus(file.env, path, manual.id = "CW35") #' #' #join the datasets #' joined <- join.datasets(dataset.LL, dataset.env) diff --git a/R/shiny_import.R b/R/shiny_import.R index f96ac35..fda4d87 100644 --- a/R/shiny_import.R +++ b/R/shiny_import.R @@ -15,8 +15,8 @@ server <- function(input, output) { writeLines(lines, temp_file) read_methods <- list( - LYS = import.LYS, - ActLumus = import.ActLumus, + LYS = import$LYS, + ActLumus = import$ActLumus, read_csv = function(x) readr::read_csv(x) ) diff --git a/README.Rmd b/README.Rmd index 0ed631b..9d14770 100644 --- a/README.Rmd +++ b/README.Rmd @@ -71,7 +71,7 @@ You can import a light logger dataset with ease. The import functions give quick ```{r, out.width="50%", fig.align='center'} filename <- system.file("extdata/sample_data_LYS.csv", package = "LightLogR") -dataset <- import.LYS(filename, tz = "Europe/Berlin") +dataset <- import$LYS(filename, tz = "Europe/Berlin") dataset %>% select(Datetime, lux, kelvin, MEDI) %>% slice(8000:8005) %>% flextable() %>% autofit() @@ -81,6 +81,7 @@ dataset %>% select(Datetime, lux, kelvin, MEDI) %>% slice(8000:8005) %>% Once imported, **LightLogR** allows you conveniently visualize the data. ```{r, fig.retina=2} +dataset %>% gg_overview() dataset %>% gg_day() ``` @@ -88,7 +89,8 @@ There is a wide range of options to the `gg_day()` function to customize the out ```{r, fig.retina=2} dataset %>% - gg_day(col = MEDI >= 250, scales = "fixed", size = 0.5) + + gg_day( + col = MEDI >= 250, scales = "fixed", size = 0.5) + scale_color_discrete(type = c("orange", "skyblue")) ``` diff --git a/README.md b/README.md index 31e2d85..7815636 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ give quick, helpful feedback about the dataset. ``` r filename <- system.file("extdata/sample_data_LYS.csv", package = "LightLogR") -dataset <- import.LYS(filename, tz = "Europe/Berlin") +dataset <- import$LYS(filename, tz = "Europe/Berlin") #> Successfully read in 11422 observations from LYS-file #> Timezone set is Europe/Berlin. #> Start: 2023-06-21 00:00:12 @@ -107,12 +107,17 @@ dataset %>% select(Datetime, lux, kelvin, MEDI) %>% slice(8000:8005) %>% Once imported, **LightLogR** allows you conveniently visualize the data. ``` r -dataset %>% gg_day() -#> Warning: Transformation introduced infinite values in continuous y-axis +dataset %>% gg_overview() ``` +``` r +dataset %>% gg_day() +``` + + + There is a wide range of options to the `gg_day()` function to customize the output. Have a look at the reference page (`?gg_day`) to see all options. You can also override most of the defaults, e.g., for different @@ -120,11 +125,11 @@ options. You can also override most of the defaults, e.g., for different ``` r dataset %>% - gg_day(col = MEDI >= 250, scales = "fixed", size = 0.5) + + gg_day( + col = MEDI >= 250, scales = "fixed", size = 0.5) + scale_color_discrete(type = c("orange", "skyblue")) #> Scale for colour is already present. #> Adding another scale for colour, which will replace the existing scale. -#> Warning: Transformation introduced infinite values in continuous y-axis ``` @@ -146,7 +151,6 @@ sample.data.environment %>% scales = "fixed", geom = "line") #> Only Dates will be used from start.date and end.date input. If you also want to set Datetimes or Times, consider using the `filter_Datetime()` function instead. -#> Warning: Transformation introduced infinite values in continuous y-axis ``` With @@ -172,8 +176,6 @@ sample.data.environment %>% group = interaction(Source, Datetime.rounded)) + theme(legend.position = "bottom") #> Only Dates will be used from start.date and end.date input. If you also want to set Datetimes or Times, consider using the `filter_Datetime()` function instead. -#> Warning: Transformation introduced infinite values in continuous y-axis -#> Warning: Removed 3429 rows containing non-finite values (`stat_boxplot()`). ``` diff --git a/_pkgdown.yml b/_pkgdown.yml index ed955f4..4cac854 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -12,8 +12,7 @@ reference: through `import.*()`. contents: - import.Dataset - - import.ActLumus - - import.LYS + - import - import.Statechanges - title: Process diff --git a/data-raw/supported-devices.R b/data-raw/supported-devices.R index e649d5b..8344bea 100644 --- a/data-raw/supported-devices.R +++ b/data-raw/supported-devices.R @@ -1,5 +1,6 @@ ## code to prepare `supported.devices` dataset goes here -supported.devices <- c("LYS", "ActLumus") +library(LightLogR) +supported.devices <- names(import_arguments) usethis::use_data(supported.devices, overwrite = TRUE) diff --git a/data/supported.devices.rda b/data/supported.devices.rda index 0cab54b..4f40719 100644 Binary files a/data/supported.devices.rda and b/data/supported.devices.rda differ diff --git a/man/figures/README-unnamed-chunk-4-1.png b/man/figures/README-unnamed-chunk-4-1.png index 61ac955..083cfb4 100644 Binary files a/man/figures/README-unnamed-chunk-4-1.png and b/man/figures/README-unnamed-chunk-4-1.png differ diff --git a/man/figures/README-unnamed-chunk-4-2.png b/man/figures/README-unnamed-chunk-4-2.png new file mode 100644 index 0000000..d4b85dd Binary files /dev/null and b/man/figures/README-unnamed-chunk-4-2.png differ diff --git a/man/figures/README-unnamed-chunk-5-1.png b/man/figures/README-unnamed-chunk-5-1.png index 430fe91..2f7c412 100644 Binary files a/man/figures/README-unnamed-chunk-5-1.png and b/man/figures/README-unnamed-chunk-5-1.png differ diff --git a/man/figures/README-unnamed-chunk-6-1.png b/man/figures/README-unnamed-chunk-6-1.png index ce72116..eb5587b 100644 Binary files a/man/figures/README-unnamed-chunk-6-1.png and b/man/figures/README-unnamed-chunk-6-1.png differ diff --git a/man/figures/README-unnamed-chunk-7-1.png b/man/figures/README-unnamed-chunk-7-1.png index 00dc164..f7ddcf4 100644 Binary files a/man/figures/README-unnamed-chunk-7-1.png and b/man/figures/README-unnamed-chunk-7-1.png differ diff --git a/man/import.Dataset.Rd b/man/import.Dataset.Rd index f780a81..d9c6c3b 100644 --- a/man/import.Dataset.Rd +++ b/man/import.Dataset.Rd @@ -1,32 +1,17 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/import_LL.R +\docType{data} \name{import.Dataset} \alias{import.Dataset} -\alias{import.ActLumus} -\alias{import.LYS} +\alias{import} \title{Import a light logger dataset or related data} +\format{ +An object of class \code{list} of length 3. +} \usage{ import.Dataset(device, ...) -import.ActLumus( - filename, - path = NULL, - n_max = Inf, - tz = "UTC", - ID.colname = Id, - auto.id = ".*", - manual.id = NULL -) - -import.LYS( - filename, - path = NULL, - n_max = Inf, - tz = "UTC", - ID.colname = Id, - auto.id = ".*", - manual.id = NULL -) +import } \arguments{ \item{device}{From what device do you want to import? For every supported @@ -36,34 +21,10 @@ by the \code{device.ext} spec to access the sample file): \itemize{ \item \code{"ActLumus"} (ActLumus.txt) \item \code{"LYS"} (LYS.csv) +\item \code{"Actiwatch_Spectrum"} (Actiwatch.csv) \emph{Note: as the \code{locale} argument use \code{readr::locale(encoding="latin1")} . This is due to the fact that the German Actiwatch software from which this sample file was taken, uses a different encoding than UTF-8.} }} \item{...}{Parameters that get handed down to the specific import functions} - -\item{filename}{Filename(s) for the Dataset. Can also contain the filepath, -but \code{path} must then be \code{NULL}. Expects a \code{character}. If the vector is -longer than \code{1}, multiple files will be read in into one Tibble.} - -\item{path}{Optional path for the dataset(s). \code{NULL} is the default. Expects -a \code{character}.} - -\item{n_max}{maximum number of lines to read. Default is \code{Inf}.} - -\item{tz}{Timezone of the data. \code{"UTC"} is the default. Expects a -\code{character}. You can look up the supported timezones with \code{\link[=OlsonNames]{OlsonNames()}}.} - -\item{ID.colname}{Lets you specify a column for the participant id. Expects a -symbol (Default is \code{Id}). This column will be used for grouping -(\code{\link[dplyr:group_by]{dplyr::group_by()}}).} - -\item{auto.id}{If the \code{Id.colname} column is added to the \code{dataset}, the \code{Id} -can be automatically extracted from the filename. The argument expects a -regular expression \link{regex} and will by default just give the whole filename -without file extension.} - -\item{manual.id}{If this argument is not \code{NULL}, and no \code{ID} column is part -of the \code{dataset}, this \code{character} scalar will be used. -\strong{Don´t use this argument if multiple files from different participants are used!}.} } \value{ Tibble/Dataframe with a POSIXct column for the datetime @@ -73,11 +34,39 @@ Imports a dataset and does the necessary transformations to get the right column formats. Unless specified otherwise, the function will set the timezone of the data to \code{UTC}. It will also enforce an \code{id} to separate different datasets and will order/arrange the dataset within each \code{id}. + +There are specific and a general import function. The general import function +is described below, whereas the specific import functions take the form of +\code{import$device()}. The general import function is a thin wrapper around the +specific import functions. The specific import functions take the following +arguments: +\itemize{ +\item \code{filename}: Filename(s) for the Dataset. Can also contain the filepath, +but \code{path} must then be \code{NULL}. Expects a \code{character}. If the vector is +longer than \code{1}, multiple files will be read in into one Tibble. +\item \code{path}: Optional path for the dataset(s). \code{NULL} is the default. Expects +a \code{character}. +\item \code{n_max}: maximum number of lines to read. Default is \code{Inf}. +\item \code{tz}: Timezone of the data. \code{"UTC"} is the default. Expects a +\code{character}. You can look up the supported timezones with \code{\link[=OlsonNames]{OlsonNames()}}. +\item \code{ID.colname}: Lets you specify a column for the participant id. Expects a +symbol (Default is \code{Id}). This column will be used for grouping +(\code{\link[dplyr:group_by]{dplyr::group_by()}}). +\item \code{auto.id}: If the \code{Id.colname} column is added to the \code{dataset}, the \code{Id} +can be automatically extracted from the filename. The argument expects a +regular expression \link{regex} and will by default just give the whole filename +without file extension. +\item \code{manual.id}: If this argument is not \code{NULL}, and no \code{ID} column is part +of the \code{dataset}, this \code{character} scalar will be used. \strong{Don´t use this +argument if multiple files from different participants are used!} +\item \code{locale}: The locale controls defaults that vary from place to place. +\item \code{...}: supply additional arguments to the \link{readr} import functions, like \code{na}. Might also be used to supply arguments to the specific import functions, like \code{column_names} for \code{Actiwatch_Spectrum} devices. Those devices will alway throw a helpful error message if you forget to supply the necessary arguments. +} } \details{ -If the \code{Id} column is already part of the \code{dataset} it will just use this -column. If the column is not present it will add this column and fill it with -the filename of the importfile (see param \code{auto.id}). +If the \code{Id} column is already part of the \code{dataset} it will just use +this column. If the column is not present it will add this column and fill +it with the filename of the importfile (see param \code{auto.id}). } \section{Examples}{ @@ -91,7 +80,7 @@ just work out of the box. To get an overview, you can simply call the is maintained. \if{html}{\out{
}}\preformatted{supported.devices -#> [1] "LYS" "ActLumus" +#> [1] "ActLumus" "LYS" }\if{html}{\out{
}} To import a file, simple specify the filename (and path) and feed it to the @@ -119,7 +108,7 @@ dataset <- import.Dataset("LYS", filepath) Import functions can also be called directly: \if{html}{\out{
}}\preformatted{filepath <- system.file("extdata/sample_data_ActLumus.txt", package = "LightLogR") -dataset <- import.ActLumus(filepath) +dataset <- import$ActLumus(filepath) #> Successfully read in 2065 observations from ActLumus-file #> Timezone set is UTC. #> The system timezone is Europe/Berlin. Please correct if necessary! @@ -137,13 +126,12 @@ dataset <- import.ActLumus(filepath) }\if{html}{\out{
}} \if{html}{\out{
}}\preformatted{dataset \%>\% -dplyr::select(Datetime, TEMPERATURE, LIGHT, MEDI) \%>\% +dplyr::select(Datetime, TEMPERATURE, LIGHT, MEDI, Id) \%>\% dplyr::slice(1500:1505) \%>\% flextable::flextable() \%>\% flextable::autofit() -#> Adding missing grouping variables: `Id` }\if{html}{\out{
}}\if{html}{\out{ -
}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}Id\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}Datetime\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}TEMPERATURE\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}LIGHT\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}MEDI\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:04:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.88\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}21,847.64\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,660.74\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:05:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.88\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}22,033.77\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,834.91\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:06:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.81\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}21,769.50\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,600.82\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:07:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.69\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}21,177.20\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,061.68\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:08:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.44\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,738.98\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}19,662.14\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:09:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.31\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,255.17\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}19,203.94\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{
}} +}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}Datetime\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}TEMPERATURE\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}LIGHT\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}MEDI\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}Id\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:04:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.88\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}21,847.64\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,660.74\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:05:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.88\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}22,033.77\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,834.91\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:06:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.81\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}21,769.50\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,600.82\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:07:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.69\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}21,177.20\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,061.68\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:08:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.44\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,738.98\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}19,662.14\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}2023-07-14 13:09:18\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}29.31\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}20,255.17\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}19,203.94\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{

}}\if{html}{\out{}}sample_data_ActLumus\if{html}{\out{}}\if{html}{\out{

}}\if{html}{\out{
}}\if{html}{\out{}} } } +\keyword{datasets} diff --git a/man/join.datasets.Rd b/man/join.datasets.Rd index 9ce1ea1..1847b1c 100644 --- a/man/join.datasets.Rd +++ b/man/join.datasets.Rd @@ -37,8 +37,8 @@ path <- system.file("extdata", package = "LightLogR") file.LL <- "205_actlumus_Log_1020_20230904101707532.txt.zip" file.env <- "cyepiamb_CW35_Log_1431_20230904081953614.txt.zip" -dataset.LL <- import.ActLumus(file.LL, path, auto.id = "^(\\\\d{3})") -dataset.env <- import.ActLumus(file.env, path, manual.id = "CW35") +dataset.LL <- import$ActLumus(file.LL, path, auto.id = "^(\\\\d{3})") +dataset.env <- import$ActLumus(file.env, path, manual.id = "CW35") #join the datasets joined <- join.datasets(dataset.LL, dataset.env) diff --git a/man/supported.devices.Rd b/man/supported.devices.Rd index 95dce26..2b68f60 100644 --- a/man/supported.devices.Rd +++ b/man/supported.devices.Rd @@ -14,6 +14,9 @@ supported.devices } \description{ -A vector of all supported devices for import functions +These are all supported devices where there is a dedicated import function. +Import functions can be called either through \code{\link[=import.Dataset]{import.Dataset()}} with the +respective \code{device = "device"} argument, or directly, e.g., +\code{import$ActLumus()}. } \keyword{datasets} diff --git a/vignettes/articles/Styling.Rmd b/vignettes/articles/Styling.Rmd index 9a90891..6f980d2 100644 --- a/vignettes/articles/Styling.Rmd +++ b/vignettes/articles/Styling.Rmd @@ -54,7 +54,7 @@ Every light logger dataset needs an `Id` to connect or separate observations fro ```{r} tz <- "Europe/Berlin" -dataset.LL <- import.ActLumus(file.LL, path, auto.id = "^(\\d{3})", tz = tz) +dataset.LL <- import$ActLumus(file.LL, path, auto.id = "^(\\d{3})", tz = tz) ``` @@ -80,7 +80,7 @@ We can already see some patterns and features in the luminous exposure across th On to our next dataset. This one contains measurement data from the same type of device, but recorded on a rooftop position of unobstructed daylight in roughly the same location as the participant data. As the device type is the same, import is the same as well. But since the filename does not contain the participant´s `ID` this time, we will give it a manual id: `"CW35"`. ```{r} -dataset.env <- import.ActLumus(file.env, path, manual.id = "CW35", tz = tz) +dataset.env <- import$ActLumus(file.env, path, manual.id = "CW35", tz = tz) ``` Here you can see that we follow roughly the same time span, but the measurement epoch is *30 seconds*, with one odd interval which is one second shorter. @@ -559,7 +559,7 @@ Plot + annotate("text", x=x, y = 4000, label = "- Daylight Potential", hjust = 0, col = "#0073C2DD") -# ggplot2::ggsave("Brown_et_al_2022.png", width = 7, height = 4, dpi = 600) +ggplot2::ggsave("images/Day.png", width = 7, height = 4, dpi = 600) ``` diff --git a/vignettes/articles/images/Day.png b/vignettes/articles/images/Day.png index 37e5628..1ff8b46 100644 Binary files a/vignettes/articles/images/Day.png and b/vignettes/articles/images/Day.png differ