diff --git a/.Rbuildignore b/.Rbuildignore index bfe7068..ec81ebe 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -13,3 +13,8 @@ ^docs$ ^pkgdown$ ^tools$ +^air.toml$ +^scratch-data$ +^format-R.sh$ +^scratch.R$ +^\.covrignore$ diff --git a/.covrignore b/.covrignore new file mode 100644 index 0000000..d90e23c --- /dev/null +++ b/.covrignore @@ -0,0 +1 @@ +R/import-*.R diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..39c9638 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +R/import-*.R linguist-generated=true diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index e1c58b9..09af814 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -47,11 +47,11 @@ jobs: - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: any::rcmdcheck + extra-packages: any::rcmdcheck, any::tzdb needs: check - uses: r-lib/actions/check-r-package@v2 with: upload-snapshots: true build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' - error-on: '"note"' + error-on: '"warning"' diff --git a/.gitignore b/.gitignore index 54b8e1e..6ee2008 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,6 @@ po/*~ rsconnect/ inst/doc docs +scratch-data +format-R.sh +scratch.R diff --git a/.lintr b/.lintr index 66a6688..5f041b4 100644 --- a/.lintr +++ b/.lintr @@ -1,12 +1,14 @@ linters: all_linters( indentation_linter = NULL, # unstable as of lintr 3.1.0 - extraction_operator_linter = NULL, # lints auto-generated vignette setup chunks implicit_integer_linter = NULL, # turn off due to multiple integerish values used duplicate_argument_linter = NULL, # due to cli_bullets object_name_linter = NULL, # due to S3 methods object_length_linter = NULL # due to length of method names ) exclusions: list( + "R/get_vimc_climate.R" = list( + object_overwrite_linter = Inf + ), "tests/testthat.R" = list( unused_import_linter = Inf, undesirable_function_linter = Inf @@ -23,5 +25,7 @@ exclusions: list( ), # do no attempt to lint auto-generated files "R/RcppExports.R", - "R/cpp11.R" + "R/cpp11.R", + "R/import-standalone-utils-assert.R", + "R/import-standalone-utils-assert-path.R" ) diff --git a/DESCRIPTION b/DESCRIPTION index 96f120b..b4bdcad 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,16 +1,20 @@ -Package: ji.rpkg.template -Title: Your Package Title in Title Case +Package: vimclimate +Title: Access Climate Data Time-series from the Vaccine Impact Modelling + Consortium Version: 0.0.0.9000 -Authors@R: c( +Authors@R: person("Pratik", "Gupte", , "pratik.gupte@lshtm.ac.uk", role = c("aut", "cre"), - comment = c(ORCID = "0000-0001-5294-7819")), - person("Abdul Latif Jameel Institute for Disease and Emergency Analytics", role = "fnd"), - person("Imperial College of Science, Technology and Medicine", role = c("cph", "fnd")) - ) -Description: Your package description. It must end with a period (".") and - include relevant bibliographical references if applicable, using the - following format: Author et al. (2023) . + comment = c(ORCID = "0000-0001-5294-7819")) +Description: Access pre-made climate data time-series. License: MIT + file LICENSE +URL: https://github.com/vimc/vimclimate, https://vimc.github.io/vimclimate +Imports: + arrow, + checkmate, + cli, + countrycode, + fs, + lubridate Suggests: knitr, rmarkdown, @@ -18,7 +22,6 @@ Suggests: testthat (>= 3.0.0) VignetteBuilder: knitr -Config/Needs/website: jameel-institute/jameelinst.rpkg.theme Config/testthat/edition: 3 Encoding: UTF-8 Language: en-GB diff --git a/LICENSE b/LICENSE index 6b42746..0c4d079 100644 --- a/LICENSE +++ b/LICENSE @@ -1,2 +1,2 @@ -YEAR: 2024 -COPYRIGHT HOLDER: ji.rpkg.template authors +YEAR: 2025 +COPYRIGHT HOLDER: Imperial College of Science, Technology and Medicine diff --git a/LICENSE.md b/LICENSE.md index 8c8f560..41e260a 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # MIT License -Copyright (c) 2024 ji.rpkg.template authors +Copyright (c) 2025 Imperial College of Science, Technology and Medicine Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NAMESPACE b/NAMESPACE index 76b6bbd..bb25a81 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,3 +1,3 @@ # Generated by roxygen2: do not edit by hand -export(get_manual_mean) +export(load_local_vimc_climate) diff --git a/NEWS.md b/NEWS.md index 4db0b83..1686b8b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,5 @@ -# ji.rpkg.template 0.0.1 +# vimclimate (development version) -* This project now includes a - [`NEWS.md`](https://r-pkgs.org/other-markdown.html#sec-news) file to inform - users about changes and new features. +- Initial package infrastructure from template. + +- Initial package function and data information constants. diff --git a/R/constants.R b/R/constants.R new file mode 100644 index 0000000..6aaa7ff --- /dev/null +++ b/R/constants.R @@ -0,0 +1,15 @@ +#' Climate data source names +#' @keywords internal constants +data_source_names <- c( + CHIRPS = "chirps", + ERA5_mean = "era5mean", + ERA5_min = "era5min", + ERA5_max = "era5max", + ERA5_RH = "era5rh", + ERA5_SH = "era5sh", + PERSIANN = "persiann" +) + +#' Allowed GADM admin levels +#' @keywords internal constants +allowed_admin_levels <- as.character(seq(0, 3)) diff --git a/R/functions.R b/R/functions.R deleted file mode 100644 index 5cf731a..0000000 --- a/R/functions.R +++ /dev/null @@ -1,10 +0,0 @@ -#' Dummy function -#' -#' @description -#' A dummy function for illustrative purposes. -#' -#' @param x A vector of numbers. -#' @export -get_manual_mean <- function(x) { - sum(x) / length(x) -} diff --git a/R/get_vimc_climate.R b/R/get_vimc_climate.R new file mode 100644 index 0000000..4ce7912 --- /dev/null +++ b/R/get_vimc_climate.R @@ -0,0 +1,60 @@ +#' Get climate data prepared for VIMC and stored locally +#' +#' @description +#' Load climate data prepared for VIMC from a local directory. +#' +#' +#' @param country A string for the country name, or for the country ISO 2- or 3- +#' character code. E.g. one of "Canada", "CA", or "CAN". Input is checked +#' against names and codes in \pkg{countrycode}. +#' +#' @param date_range A two element vector of ``s, giving the interval for +#' which to get data. +#' +#' @param data_location A location relative to the current working directory +#' to search for the data. Data for `country` are expected to live in +#' `data_location/XYZ` as Parquet files, where `XYZ` is the ISO 3-character code +#' for `country`. Defaults to the working directory. +#' +#' @param data_source A string giving the climate data to search for. Names must +#' match exactly. +#' +#' @param admin_level A numeric giving the GADM admin level for which to get +#' data. Only one unit may be passed at a time. +#' +#' @return A `` of climate data. +#' +#' @keywords data_access +#' +#' @export +load_local_vimc_climate <- function( + country, + date_range, + data_location, + data_source = NULL, + admin_level = c(0, 1, 2, 3) +) { + country <- validate_country(country) + date_range <- validate_date_range(date_range) + data_location <- validate_data_location(data_location) + data_source <- match_value(data_source, names(data_source_names)) + admin_level <- validate_admin_level(admin_level) + + target_file <- locate_parquet_file( + data_location, + country, + admin_level, + data_source + ) + + # read files and return data.frame as being of familiar format + data <- arrow::read_parquet(target_file) + data <- as.data.frame(data) + + # filter on date, assume timezone is UTC + data$Date <- lubridate::as_date(data$Date) + + data[ + data$Date >= min(date_range) & data$Date <= max(date_range), + ] +} diff --git a/R/import-date-assert.R b/R/import-date-assert.R new file mode 100644 index 0000000..cbe0e92 --- /dev/null +++ b/R/import-date-assert.R @@ -0,0 +1,31 @@ +# NOTE: temporary home for these functions before they move to {reside.utils} +assert_date <- function( + x, + name = deparse(substitute(x)), + arg = name, + call = parent.frame() +) { + if (!lubridate::is.Date(x)) { + cli::cli_abort( + "Expected '{name}' to be a Date", + call = call, + arg = arg + ) + } + invisible(x) +} + +assert_scalar_date <- function( + x, + name = deparse(substitute(x)), + allow_null = FALSE, + arg = name, + call = parent.frame() +) { + if (allow_null && is.null(x)) { + return(invisible(x)) + } + assert_scalar(x, name, arg = arg, call = call) + assert_date(x, name, arg = arg, call = call) + assert_nonmissing(x, name, arg = arg, call = call) +} diff --git a/R/import-standalone-utils-assert-path.R b/R/import-standalone-utils-assert-path.R new file mode 100644 index 0000000..8aad030 --- /dev/null +++ b/R/import-standalone-utils-assert-path.R @@ -0,0 +1,167 @@ +# Standalone file: do not edit by hand +# Source: https://github.com/reside-ic/reside.utils/blob/HEAD/R/standalone-utils-assert-path.R +# Generated by: usethis::use_standalone("reside-ic/reside.utils", "utils-assert-path") +# ---------------------------------------------------------------------- +# +# --- +# repo: reside/reside.utils +# file: standalone-utils-assert-path.R +# dependencies: standalone-utils-assert.R +# imports: [cli, fs] +# --- +assert_file_exists <- function(files, name = "File", call = parent.frame(), + arg = NULL) { + err <- !file.exists(files) + ## TODO: throughout this file it would be nice to use cli's '.file' + ## class and ector contraction, *but* it renders poorly on default + ## black backgfrounds (dark blue) and makes testing a bit harder + ## because the rendering depends on cli options. + ## + ## TODO: add a canonical case check, as for the relative path bit. + if (any(err)) { + ## Because we interpolate both 'name' and the file list, we need + ## to disambiguate the quantity. + n <- cli::qty(sum(err)) + cli::cli_abort( + "{name}{n}{?s} {?does/do} not exist: {format_file_list(files[err])}", + call = call, arg = arg + ) + } +} + + +assert_file_exists_relative <- function(files, workdir, name, + call = parent.frame(), + arg = NULL) { + assert_relative_path(files, name, workdir, call) + + assert_character(files, name, call = call) + err <- !file_exists(files, workdir = workdir) + if (any(err)) { + n <- cli::qty(sum(err)) + cli::cli_abort( + c("{name}{n}{?s} {?does/do} not exist: {format_file_list(files[err])}", + i = "Looked within directory '{workdir}'" + ), + call = call + ) + } + + files_canonical <- file_canonical_case(files, workdir) + err <- is.na(files_canonical) | fs::path(files) != files_canonical + if (any(err)) { + i <- err & !is.na(files_canonical) + hint_case <- sprintf( + "For '%s', did you mean '%s'?", + files[i], files_canonical[i] + ) + names(hint_case) <- rep("i", length(hint_case)) + n <- cli::qty(sum(err)) + cli::cli_abort( + c("{name}{n}{?s} {?does/do} not exist: {format_file_list(files[err])}", + hint_case, + i = paste( + "If you don't use the canonical case for a file, your code", + "is not portable across different platforms" + ), + i = "Looked within directory '{workdir}'" + ), + call = call + ) + } +} + + +assert_is_directory <- function(path, name = "Directory", call = parent.frame(), + arg = NULL) { + assert_scalar_character(path, arg = arg, call = call) + assert_file_exists(path, name = name, arg = arg, call = call) + if (!fs::is_dir(path)) { + cli::cli_abort("Path exists but is not a directory: {path}", + call = call, arg = arg + ) + } +} + + +assert_relative_path <- function(files, name, workdir, call = parent.frame(), + arg = NULL) { + err <- fs::is_absolute_path(files) + if (any(err)) { + n <- cli::qty(sum(err)) + files_err <- files[err] + names(files_err) <- rep("x", length(files_err)) + cli::cli_abort( + c("{name}{n}{?s} must be {?a/} relative path{?s}", + files_err, + i = "Path was relative to directory '{workdir}'" + ), + call = call, arg = arg + ) + } + + err <- vapply(fs::path_split(files), function(x) any(x == ".."), TRUE) + if (any(err)) { + n <- cli::qty(sum(err)) + files_err <- files[err] + names(files_err) <- rep("x", length(files_err)) + cli::cli_abort( + c("{name}{n}{?s} must not contain '..' (parent directory) components", + files_err, + i = "Path was relative to directory '{workdir}'" + ), + call = call, arg = arg + ) + } +} + + +assert_directory_does_not_exist <- function(x, name = "Directory", arg = NULL, + call = parent.frame()) { + ok <- !fs::dir_exists(x) + if (!all(ok)) { + cli::cli_abort("{name}{?s} already exists: {format_file_list(x[!ok])}", + call = call, arg = arg + ) + } + invisible(x) +} + + +file_canonical_case <- function(path, workdir) { + if (length(path) != 1) { + return(vapply(path, file_canonical_case, "", workdir, USE.NAMES = FALSE)) + } + stopifnot(!fs::is_absolute_path(path)) + path_split <- tolower(fs::path_split(path)[[1]]) + base <- workdir + ret <- character(length(path_split)) + for (i in seq_along(path_split)) { + pos <- dir(base) + j <- which(path_split[[i]] == tolower(pos)) + if (length(j) != 1) { + return(NA_character_) + } + ret[[i]] <- pos[[j]] + base <- file.path(base, pos[[j]]) + } + paste(ret, collapse = "/") +} + + +file_exists <- function(..., workdir = NULL) { + files <- c(...) + if (!is.null(workdir)) { + assert_scalar_character(workdir) + owd <- setwd(workdir) # nolint + on.exit(setwd(owd)) # nolint + } + fs::file_exists(files) +} + + +format_file_list <- function(x) { + cli::cli_vec(sprintf("'%s'", x), + style = list("vec-sep2" = ", ", "vec-last" = ", ") + ) +} diff --git a/R/import-standalone-utils-assert.R b/R/import-standalone-utils-assert.R new file mode 100644 index 0000000..441503d --- /dev/null +++ b/R/import-standalone-utils-assert.R @@ -0,0 +1,251 @@ +# Standalone file: do not edit by hand +# Source: https://github.com/reside-ic/reside.utils/blob/HEAD/R/standalone-utils-assert.R +# Generated by: usethis::use_standalone("reside-ic/reside.utils", "utils-assert") +# ---------------------------------------------------------------------- +# +# --- +# repo: reside/reside.utils +# file: standalone-utils-assert.R +# imports: cli +# --- +assert_scalar <- function(x, name = deparse(substitute(x)), arg = name, + call = parent.frame()) { + if (length(x) != 1) { + cli::cli_abort( + c("'{name}' must be a scalar", + i = "{name} has length {length(x)}"), + call = call, arg = arg) + } + invisible(x) +} + + +assert_character <- function(x, name = deparse(substitute(x)), + arg = name, call = parent.frame()) { + if (!is.character(x)) { + cli::cli_abort("Expected '{name}' to be character", call = call, arg = arg) + } + invisible(x) +} + + +assert_numeric <- function(x, name = deparse(substitute(x)), + arg = name, call = parent.frame()) { + if (!is.numeric(x)) { + cli::cli_abort("Expected '{name}' to be numeric", call = call, arg = arg) + } + invisible(x) +} + + +assert_integer <- function(x, name = deparse(substitute(x)), + tolerance = NULL, arg = name, + call = parent.frame()) { + if (is.numeric(x)) { + rx <- round(x) + if (is.null(tolerance)) { + tolerance <- sqrt(.Machine$double.eps) + } + if (!isTRUE(all.equal(x, rx, tolerance = tolerance))) { + cli::cli_abort( + c("Expected '{name}' to be integer", + i = paste("{cli::qty(length(x))}The provided", + "{?value was/values were} numeric, but not very close", + "to integer values")), + arg = arg, call = call) + } + x <- as.integer(rx) + } else { + cli::cli_abort("Expected '{name}' to be integer", call = call, arg = arg) + } + invisible(x) +} + + +assert_logical <- function(x, name = deparse(substitute(x)), + arg = name, call = parent.frame()) { + if (!is.logical(x)) { + cli::cli_abort("Expected '{name}' to be logical", arg = arg, call = call) + } + invisible(x) +} + + +assert_nonmissing <- function(x, name = deparse(substitute(x)), + arg = name, call = parent.frame()) { + if (anyNA(x)) { + cli::cli_abort("Expected '{name}' to be non-NA", arg = arg, call = call) + } + invisible(x) +} + + +assert_scalar_character <- function(x, name = deparse(substitute(x)), + allow_null = FALSE, + arg = name, call = parent.frame()) { + if (allow_null && is.null(x)) { + return(invisible(x)) + } + assert_scalar(x, name, arg = arg, call = call) + assert_character(x, name, arg = arg, call = call) + assert_nonmissing(x, name, arg = arg, call = call) +} + + +assert_scalar_numeric <- function(x, name = deparse(substitute(x)), + allow_null = FALSE, + arg = name, call = parent.frame()) { + if (allow_null && is.null(x)) { + return(invisible(x)) + } + assert_scalar(x, name, arg = arg, call = call) + assert_numeric(x, name, arg = arg, call = call) + assert_nonmissing(x, name, arg = arg, call = call) +} + + +assert_scalar_integer <- function(x, name = deparse(substitute(x)), + tolerance = NULL, allow_null = FALSE, + arg = name, call = parent.frame()) { + if (allow_null && is.null(x)) { + return(invisible(x)) + } + assert_scalar(x, name, arg = arg, call = call) + assert_integer(x, name, tolerance = tolerance, arg = arg, call = call) + assert_nonmissing(x, name, arg = arg, call = call) +} + + +assert_scalar_logical <- function(x, name = deparse(substitute(x)), + allow_null = FALSE, + arg = name, call = parent.frame()) { + if (allow_null && is.null(x)) { + return(invisible(x)) + } + assert_scalar(x, name, arg = arg, call = call) + assert_logical(x, name, arg = arg, call = call) + assert_nonmissing(x, name, arg = arg, call = call) +} + + +assert_scalar_size <- function(x, allow_zero = TRUE, allow_null = FALSE, + name = deparse(substitute(x)), + arg = name, call = parent.frame()) { + if (allow_null && is.null(x)) { + return(invisible(x)) + } + assert_scalar_integer(x, name = name, arg = arg, call = call) + assert_nonmissing(x, name, arg = arg, call = call) + min <- if (allow_zero) 0 else 1 + if (x < min) { + cli::cli_abort("'{name}' must be at least {min}", arg = arg, call = call) + } + invisible(x) +} + + +assert_length <- function(x, len, name = deparse(substitute(x)), arg = name, + call = parent.frame()) { + if (length(x) != len) { + cli::cli_abort( + "Expected '{name}' to have length {len}, but was length {length(x)}", + arg = arg, call = call) + } + invisible(x) +} + + +assert_is <- function(x, what, name = deparse(substitute(x)), arg = name, + call = parent.frame()) { + if (!inherits(x, what)) { + cli::cli_abort("Expected '{name}' to be a '{what}' object", + arg = arg, call = call) + } + invisible(x) +} + + +assert_list <- function(x, name = deparse(substitute(x)), arg = name, + call = parent.frame()) { + if (!is.list(x)) { + cli::cli_abort("Expected '{name}' to be a list", + arg = arg, call = call) + } + invisible(x) +} + + +assert_scalar_positive_numeric <- function(x, allow_zero = TRUE, + name = deparse(substitute(x)), + arg = name, call = parent.frame()) { + assert_scalar_numeric(x, name = name, call = call) + if (allow_zero) { + if (x < 0) { + cli::cli_abort("'{name}' must be at least 0", arg = arg, call = call) + } + } else { + if (x <= 0) { + cli::cli_abort("'{name}' must be greater than 0", arg = arg, call = call) + } + } + invisible(x) +} + + +assert_scalar_positive_integer <- function(x, allow_zero = TRUE, + name = deparse(substitute(x)), + tolerance = NULL, arg = name, + call = parent.frame()) { + assert_scalar_integer(x, name, tolerance = tolerance, arg = arg, call = call) + min <- if (allow_zero) 0 else 1 + if (x < min) { + cli::cli_abort("'{name}' must be at least {min}", arg = arg, call = call) + } + invisible(x) +} + + +assert_raw <- function(x, len = NULL, name = deparse(substitute(x)), + arg = name, call = parent.frame()) { + if (!is.raw(x)) { + cli::cli_abort("'{name}' must be a raw vector", arg = arg, call = call) + } + if (!is.null(len)) { + assert_length(x, len, name = name, call = call) + } + invisible(x) +} + + +assert_named <- function(x, unique = FALSE, name = deparse(substitute(x)), + arg = name, call = parent.frame()) { + nms <- names(x) + if (is.null(nms)) { + cli::cli_abort("'{name}' must be named", call = call, arg = arg) + } + if (anyNA(nms) || any(nms == "")) { + cli::cli_abort("All elements of '{name}' must be named", + call = call, arg = arg) + } + if (unique && anyDuplicated(names(x))) { + dups <- sprintf("'%s'", unique(names(x)[duplicated(names(x))])) + cli::cli_abort( + c("'{name}' must have unique names", + i = "Found {length(dups)} duplicate{?s}: {dups}"), + call = call, arg = arg) + } + invisible(x) +} + + +match_value <- function(x, choices, name = deparse(substitute(x)), arg = name, + call = parent.frame()) { + assert_scalar_character(x, call = call, name = name, arg = arg) + if (!(x %in% choices)) { + choices_str <- paste(sprintf("'%s'", choices), collapse = ", ") + cli::cli_abort(c("'{name}' must be one of {choices_str}", + i = "Instead we were given '{x}'"), call = call, + arg = arg) + } + x +} diff --git a/R/locate_data.R b/R/locate_data.R new file mode 100644 index 0000000..26a080f --- /dev/null +++ b/R/locate_data.R @@ -0,0 +1,46 @@ +#' Locate local data files +#' +#' @inheritParams load_local_vimc_climate +#' +#' @param country_iso3c Country ISO 3 character code. Passed from top-level +#' function [load_local_vimc_climate()] after a call to [validate_country()]. +#' +#' @keywords internal data_locator +#' +#' @return The location of a local data Parquet file. Has a number of +#' side-effects to inform users when `data_location`, the county data directory +#' within `data_location`, or the file corresponding to the data requested are +#' not found. +locate_parquet_file <- function( + data_location, + country_iso3c, + admin_level, + data_source +) { + data_location <- file.path(data_location, country_iso3c) + assert_is_directory(data_location) + + data_source_id <- data_source_names[[data_source]] + search_pattern <- sprintf( + "%s_admin_%s.parquet", + data_source_id, + admin_level + ) + + # NOTE: we expect only a single file to be returned + files <- list.files( + data_location, + pattern = search_pattern, + full.names = TRUE + ) + + # using explicit check for more informative messages + if (length(files) == 0L) { + cli::cli_abort( + "File '{search_pattern}' not found; please check that data are present in + '{data_location}'" + ) + } + + files +} diff --git a/R/validate_inputs.R b/R/validate_inputs.R new file mode 100644 index 0000000..1e436ca --- /dev/null +++ b/R/validate_inputs.R @@ -0,0 +1,96 @@ +#' @title Return checked inputs or print informative errors +#' +#' @name input_validators +#' @rdname input_validators +#' +#' @inheritParams load_local_vimc_climate +#' +#' @keywords internal validator +#' +#' @return +#' A checked and in some cases processed input. Most functions also have +#' side-effects. +#' +#' - `validate_country()`: A country ISO 3 character code. Has the side-effect +#' of erroring when `country` is either not a string, or when the country code +#' cannot be found from `country`. +#' +#' - `validate_date_range()`: Returns `date_range` after checking that it is +#' a two-element `` vector. +#' +#' - `validate_admin_level()`: Returns `admin_level` after checking it is an +#' integer-like number in the range `[0, 3]`. +validate_country <- function(country) { + # convert country to ISO 3166-1 3C country code + # note `nomatch = NULL` is preferable but is a special case + # in pkg countrycode + assert_scalar_character(country) + nchar_country <- nchar(country) + checkmate::assert_integerish( + nchar_country, + lower = 2, + any.missing = FALSE + ) + + if (nchar_country > 3L) { + country_iso3c <- countrycode::countryname( + country, + "iso3c", + warn = FALSE, + nomatch = NA + ) + } else if (nchar_country %in% c(2L, 3L)) { + country_iso3c <- countrycode::countrycode( + country, + sprintf("iso%ic", nchar_country), + "iso3c", + warn = FALSE, + nomatch = NA + ) + } + + if (is.na(country_iso3c)) { + cli::cli_abort( + "Could not convert `country` '{country}' to an ISO 3 character \\ + country code; please check `country`." + ) + } + + country_iso3c +} + +#' @name input_validators +#' +#' @inheritParams date_range +#' +#' @keywords internal validator +validate_date_range <- function(date_range) { + assert_length(date_range, 2) + assert_date(date_range) +} + +#' @name input_validators +#' +#' @inheritParams load_local_vimc_climate +#' +#' @keywords internal validator +validate_admin_level <- function(admin_level) { + checkmate::assert_integerish( + admin_level, + lower = 0, + upper = 3, + len = 1, + any.missing = FALSE + ) +} + +#' @name input_validators +#' +#' @inheritParams load_local_vimc_climate +#' +#' @keywords internal validator +validate_data_location <- function(data_location) { + assert_scalar(data_location) + assert_is_directory(data_location) + invisible(data_location) # assert_is_directory() has no return +} diff --git a/R/ji.rpkg.template-package.R b/R/vimclimate.R similarity index 100% rename from R/ji.rpkg.template-package.R rename to R/vimclimate.R diff --git a/README.Rmd b/README.Rmd index b4eac9a..75f73a5 100644 --- a/README.Rmd +++ b/README.Rmd @@ -15,58 +15,35 @@ knitr::opts_chunk$set( ) ``` -# ji.rpkg.template: TAGLINE +# vimclimate: Access climate data time-series from the Vaccine Impact Modelling Consortium -[![Project Status: Concept – Minimal or no implementation has been done yet, or the repository is only intended to be a limited example, demo, or proof-of-concept.](https://www.repostatus.org/badges/latest/concept.svg)](https://www.repostatus.org/#concept) -[![R build status](https://github.com/jameel-institute/ji.rpkg.template/workflows/R-CMD-check/badge.svg)](https://github.com/jameel-institute/ji.rpkg.template/actions/workflows/R-CMD-check.yaml) -[![Codecov test coverage](https://codecov.io/gh/jameel-institute/ji.rpkg.template/branch/main/graph/badge.svg)](https://app.codecov.io/gh/jameel-institute/ji.rpkg.template?branch=main) -[![CRAN status](https://www.r-pkg.org/badges/version/ji.rpkg.template)](https://CRAN.R-project.org/package=ji.rpkg.template) +[![Project Status: Concept - Minimal or no implementation has been done yet, or the repository is only intended to be a limited example, demo, or proof-of-concept.](https://www.repostatus.org/badges/latest/concept.svg)](https://www.repostatus.org/#concept) +[![R build status](https://github.com/vimc/vimclimate/workflows/R-CMD-check/badge.svg)](https://github.com/vimc/vimclimate/actions/workflows/R-CMD-check.yaml) +[![Codecov test coverage](https://codecov.io/gh/vimc/vimclimate/branch/main/graph/badge.svg)](https://app.codecov.io/gh/vimc/vimclimate?branch=main) +[![CRAN status](https://www.r-pkg.org/badges/version/vimclimate)](https://CRAN.R-project.org/package=vimclimate) -_ji.rpkg.template_ is a template package and repository on which future Jameel Institute packages are based. - -To use this template, select _ji.rpkg.template_ from the drop-down menu under **Repository template** when creating a new repository in the Jameel Institute organisation. -Replace all instances of "ji.rpkg.template" with your package name. Make sure to also: - -1. Edit the `DESCRIPTION` as appropriate with the correct package information; - -2. Edit the files in `R/`, `tests/`, and `vignettes/` to suit your package; - -3. Remove these instructions from `README.Rmd`, and re-render the `.md` file using `devtools::render_readme()`. +_vimclimate_ is an R package that helps access pre-made climatic variable time-series data for use in modelling. ## Installation -**NOTE:** Remove or comment out installation sources as appropriate. - -You can install the development version of ji.rpkg.template from the Jameel Institute R-universe with: +You can install the development version of _vimclimate_ from the [VIMC R-universe](https://vimc.r-universe.dev/) with: ```r # installation from R-universe -# install.packages( -# "ji.rpkg.template", -# repos = c( -# "https://jameel-institute.r-universe.dev", "https://cloud.r-project.org" -# ) -# ) -``` - -or from GitHub [GitHub](https://github.com/) with: - -``` r -# install.packages("pak") -# pak::pak("jameel-institute/ji.rpkg.template") +install.packages( + "vimclimate", + repos = c( + "https://vimc.r-universe.dev", "https://cloud.r-project.org" + ) +) ``` ## Quick start -Add a simple example of using the package's main feature(s) here, with a minimum amount of code. -If preparatory or plotting steps are needed, prefer to hide them to keep focus on the package functionality. +WIP. ## Related projects -Add information and links to related projects, such as research papers or packages, here. - -## References - -Space for references: REMOVE this text. +- [_clim2parquet_](https://vimc.github.io/clim2parquet/): Used to prepare climate data in Parquet format; this is the data accessed by _vimclimate_. diff --git a/README.md b/README.md index 8c4134e..0ad9fa7 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,46 @@ -# ji.rpkg.template: TAGLINE +# vimclimate: Access climate data time-series from the Vaccine Impact Modelling Consortium -[![Project Status: Concept – Minimal or no implementation has been done +[![Project Status: Concept - Minimal or no implementation has been done yet, or the repository is only intended to be a limited example, demo, or proof-of-concept.](https://www.repostatus.org/badges/latest/concept.svg)](https://www.repostatus.org/#concept) [![R build -status](https://github.com/jameel-institute/ji.rpkg.template/workflows/R-CMD-check/badge.svg)](https://github.com/jameel-institute/ji.rpkg.template/actions/workflows/R-CMD-check.yaml) +status](https://github.com/vimc/vimclimate/workflows/R-CMD-check/badge.svg)](https://github.com/vimc/vimclimate/actions/workflows/R-CMD-check.yaml) [![Codecov test -coverage](https://codecov.io/gh/jameel-institute/ji.rpkg.template/branch/main/graph/badge.svg)](https://app.codecov.io/gh/jameel-institute/ji.rpkg.template?branch=main) +coverage](https://codecov.io/gh/vimc/vimclimate/branch/main/graph/badge.svg)](https://app.codecov.io/gh/vimc/vimclimate?branch=main) [![CRAN -status](https://www.r-pkg.org/badges/version/ji.rpkg.template)](https://CRAN.R-project.org/package=ji.rpkg.template) +status](https://www.r-pkg.org/badges/version/vimclimate)](https://CRAN.R-project.org/package=vimclimate) -*ji.rpkg.template* is a template package and repository on which future -Jameel Institute packages are based. - -To use this template, select *ji.rpkg.template* from the drop-down menu -under **Repository template** when creating a new repository in the -Jameel Institute organisation. Replace all instances of -“ji.rpkg.template” with your package name. Make sure to also: - -1. Edit the `DESCRIPTION` as appropriate with the correct package - information; - -2. Edit the files in `R/`, `tests/`, and `vignettes/` to suit your - package; - -3. Remove these instructions from `README.Rmd`, and re-render the `.md` - file using `devtools::render_readme()`. +*vimclimate* is an R package that helps access pre-made climatic +variable time-series data for use in modelling. ## Installation -**NOTE:** Remove or comment out installation sources as appropriate. - -You can install the development version of ji.rpkg.template from the -Jameel Institute R-universe with: +You can install the development version of *vimclimate* from the [VIMC +R-universe](https://vimc.r-universe.dev/) with: ``` r # installation from R-universe -# install.packages( -# "ji.rpkg.template", -# repos = c( -# "https://jameel-institute.r-universe.dev", "https://cloud.r-project.org" -# ) -# ) -``` - -or from GitHub [GitHub](https://github.com/) with: - -``` r -# install.packages("pak") -# pak::pak("jameel-institute/ji.rpkg.template") +install.packages( + "vimclimate", + repos = c( + "https://vimc.r-universe.dev", "https://cloud.r-project.org" + ) +) ``` ## Quick start -Add a simple example of using the package’s main feature(s) here, with a -minimum amount of code. If preparatory or plotting steps are needed, -prefer to hide them to keep focus on the package functionality. +WIP. ## Related projects -Add information and links to related projects, such as research papers -or packages, here. - -## References - -Space for references: REMOVE this text. +- [*clim2parquet*](https://vimc.github.io/clim2parquet/): Used to + prepare climate data in Parquet format; this is the data accessed by + *vimclimate*. diff --git a/_pkgdown.yml b/_pkgdown.yml index 1d4fe01..35743dc 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,6 +1,20 @@ # NOTE: Update the `url` field as needed -# e.g. "https://jameel-institute.github.io/daedalus/" -url: ~ +# e.g. "https://vimc.github.io/vimclimate/" +url: https://vimc.github.io/vimclimate/ template: bootstrap: 5 - package: jameelinst.rpkg.theme + +reference: + - title: Data access functions + desc: Load data from a specified data location + contents: + - has_keyword("data_access") + - title: Package constants + desc: Small package data used in functions + contents: + - has_keyword("constants") + - title: Internal helper functions + desc: Helpers to validate inputs and locate files + contents: + - has_keyword("locator") + - has_keyword("validator") diff --git a/air.toml b/air.toml new file mode 100644 index 0000000..814835d --- /dev/null +++ b/air.toml @@ -0,0 +1,5 @@ +[format] +exclude = [ + "import-standalone-utils-assert.R", + "import-standalone-utils-assert-path.R" +] diff --git a/inst/WORDLIST b/inst/WORDLIST index e91f4b5..caeb1d4 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -1,10 +1,9 @@ Codecov -Jameel +GADM ORCID -TAGLINE -Un -doi -ji +VIMC +WIP +clim +erroring +pak pkgdown -rpkg -zenodo diff --git a/man/allowed_admin_levels.Rd b/man/allowed_admin_levels.Rd new file mode 100644 index 0000000..fa69ad1 --- /dev/null +++ b/man/allowed_admin_levels.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/constants.R +\docType{data} +\name{allowed_admin_levels} +\alias{allowed_admin_levels} +\title{Allowed GADM admin levels} +\format{ +An object of class \code{character} of length 4. +} +\usage{ +allowed_admin_levels +} +\description{ +Allowed GADM admin levels +} +\keyword{constants} +\keyword{internal} diff --git a/man/data_source_names.Rd b/man/data_source_names.Rd new file mode 100644 index 0000000..987e7d3 --- /dev/null +++ b/man/data_source_names.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/constants.R +\docType{data} +\name{data_source_names} +\alias{data_source_names} +\title{Climate data source names} +\format{ +An object of class \code{character} of length 7. +} +\usage{ +data_source_names +} +\description{ +Climate data source names +} +\keyword{constants} +\keyword{internal} diff --git a/man/get_manual_mean.Rd b/man/get_manual_mean.Rd deleted file mode 100644 index 05b3db4..0000000 --- a/man/get_manual_mean.Rd +++ /dev/null @@ -1,14 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/functions.R -\name{get_manual_mean} -\alias{get_manual_mean} -\title{Dummy function} -\usage{ -get_manual_mean(x) -} -\arguments{ -\item{x}{A vector of numbers.} -} -\description{ -A dummy function for illustrative purposes. -} diff --git a/man/input_validators.Rd b/man/input_validators.Rd new file mode 100644 index 0000000..5a54e77 --- /dev/null +++ b/man/input_validators.Rd @@ -0,0 +1,52 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/validate_inputs.R +\name{input_validators} +\alias{input_validators} +\alias{validate_country} +\alias{validate_date_range} +\alias{validate_admin_level} +\alias{validate_data_location} +\title{Return checked inputs or print informative errors} +\usage{ +validate_country(country) + +validate_date_range(date_range) + +validate_admin_level(admin_level) + +validate_data_location(data_location) +} +\arguments{ +\item{country}{A string for the country name, or for the country ISO 2- or 3- +character code. E.g. one of "Canada", "CA", or "CAN". Input is checked +against names and codes in \pkg{countrycode}.} + +\item{date_range}{A two element vector of \verb{}s, giving the interval for +which to get data.} + +\item{admin_level}{A numeric giving the GADM admin level for which to get +data. Only one unit may be passed at a time.} + +\item{data_location}{A location relative to the current working directory +to search for the data. Data for \code{country} are expected to live in +\code{data_location/XYZ} as Parquet files, where \code{XYZ} is the ISO 3-character code +for \code{country}. Defaults to the working directory.} +} +\value{ +A checked and in some cases processed input. Most functions also have +side-effects. +\itemize{ +\item \code{validate_country()}: A country ISO 3 character code. Has the side-effect +of erroring when \code{country} is either not a string, or when the country code +cannot be found from \code{country}. +\item \code{validate_date_range()}: Returns \code{date_range} after checking that it is +a two-element \verb{} vector. +\item \code{validate_admin_level()}: Returns \code{admin_level} after checking it is an +integer-like number in the range \verb{[0, 3]}. +} +} +\description{ +Return checked inputs or print informative errors +} +\keyword{internal} +\keyword{validator} diff --git a/man/ji.rpkg.template-package.Rd b/man/ji.rpkg.template-package.Rd deleted file mode 100644 index 6711019..0000000 --- a/man/ji.rpkg.template-package.Rd +++ /dev/null @@ -1,21 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ji.rpkg.template-package.R -\docType{package} -\name{ji.rpkg.template-package} -\alias{ji.rpkg.template} -\alias{ji.rpkg.template-package} -\title{ji.rpkg.template: Your Package Title in Title Case} -\description{ -Your package description. It must end with a period (".") and include relevant bibliographical references if applicable, using the following format: Author et al. (2023) \doi{10.5281/zenodo.6619350}. -} -\author{ -\strong{Maintainer}: Pratik Gupte \email{pratik.gupte@lshtm.ac.uk} (\href{https://orcid.org/0000-0001-5294-7819}{ORCID}) - -Other contributors: -\itemize{ - \item Abdul Latif Jameel Institute for Disease and Emergency Analytics [funder] - \item Imperial College of Science, Technology and Medicine [copyright holder, funder] -} - -} -\keyword{internal} diff --git a/man/load_local_vimc_climate.Rd b/man/load_local_vimc_climate.Rd new file mode 100644 index 0000000..934f0f2 --- /dev/null +++ b/man/load_local_vimc_climate.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/get_vimc_climate.R +\name{load_local_vimc_climate} +\alias{load_local_vimc_climate} +\title{Get climate data prepared for VIMC and stored locally} +\usage{ +load_local_vimc_climate( + country, + date_range, + data_location, + data_source = NULL, + admin_level = c(0, 1, 2, 3) +) +} +\arguments{ +\item{country}{A string for the country name, or for the country ISO 2- or 3- +character code. E.g. one of "Canada", "CA", or "CAN". Input is checked +against names and codes in \pkg{countrycode}.} + +\item{date_range}{A two element vector of \verb{}s, giving the interval for +which to get data.} + +\item{data_location}{A location relative to the current working directory +to search for the data. Data for \code{country} are expected to live in +\code{data_location/XYZ} as Parquet files, where \code{XYZ} is the ISO 3-character code +for \code{country}. Defaults to the working directory.} + +\item{data_source}{A string giving the climate data to search for. Names must +match exactly.} + +\item{admin_level}{A numeric giving the GADM admin level for which to get +data. Only one unit may be passed at a time.} +} +\value{ +A \verb{} of climate data. +} +\description{ +Load climate data prepared for VIMC from a local directory. +} +\keyword{data_access} diff --git a/man/locate_parquet_file.Rd b/man/locate_parquet_file.Rd new file mode 100644 index 0000000..1610a84 --- /dev/null +++ b/man/locate_parquet_file.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/locate_data.R +\name{locate_parquet_file} +\alias{locate_parquet_file} +\title{Locate local data files} +\usage{ +locate_parquet_file(data_location, country_iso3c, admin_level, data_source) +} +\arguments{ +\item{data_location}{A location relative to the current working directory +to search for the data. Data for \code{country} are expected to live in +\code{data_location/XYZ} as Parquet files, where \code{XYZ} is the ISO 3-character code +for \code{country}. Defaults to the working directory.} + +\item{country_iso3c}{Country ISO 3 character code. Passed from top-level +function \code{\link[=load_local_vimc_climate]{load_local_vimc_climate()}} after a call to \code{\link[=validate_country]{validate_country()}}.} + +\item{admin_level}{A numeric giving the GADM admin level for which to get +data. Only one unit may be passed at a time.} + +\item{data_source}{A string giving the climate data to search for. Names must +match exactly.} +} +\value{ +The location of a local data Parquet file. Has a number of +side-effects to inform users when \code{data_location}, the county data directory +within \code{data_location}, or the file corresponding to the data requested are +not found. +} +\description{ +Locate local data files +} +\keyword{data_locator} +\keyword{internal} diff --git a/man/vimclimate-package.Rd b/man/vimclimate-package.Rd new file mode 100644 index 0000000..8eaae00 --- /dev/null +++ b/man/vimclimate-package.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/vimclimate.R +\docType{package} +\name{vimclimate-package} +\alias{vimclimate} +\alias{vimclimate-package} +\title{vimclimate: Access Climate Data Time-series from the Vaccine Impact Modelling Consortium} +\description{ +Access pre-made climate data time-series. +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/vimc/vimclimate} + \item \url{https://vimc.github.io/vimclimate} +} + +} +\author{ +\strong{Maintainer}: Pratik Gupte \email{pratik.gupte@lshtm.ac.uk} (\href{https://orcid.org/0000-0001-5294-7819}{ORCID}) + +} +\keyword{internal} diff --git a/tests/spelling.R b/tests/spelling.R index 13f77d9..d60e024 100644 --- a/tests/spelling.R +++ b/tests/spelling.R @@ -1,6 +1,7 @@ if (requireNamespace("spelling", quietly = TRUE)) { spelling::spell_check_test( - vignettes = TRUE, error = FALSE, + vignettes = TRUE, + error = FALSE, skip_on_cran = TRUE ) } diff --git a/tests/testthat.R b/tests/testthat.R index 3320784..2e3658d 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -7,6 +7,6 @@ # * https://testthat.r-lib.org/articles/special-files.html library(testthat) -library(ji.rpkg.template) +library(vimclimate) -test_check("ji.rpkg.template") +test_check("vimclimate") diff --git a/tests/testthat/helper-state.R b/tests/testthat/helper-state.R index 513ecdb..db07f2c 100644 --- a/tests/testthat/helper-state.R +++ b/tests/testthat/helper-state.R @@ -14,22 +14,48 @@ get_pars_toreset <- function() { pars <- pars[!names(pars) %in% c("usr", "xaxp", "yaxp")] } +# check whether running on Windows +# NOTE: if on Windows, {lubridate} will create an explicit TZDIR env variable +# and {arrow} will set an option for multi-threading (IMO): `arrow.use_threads`. +# Changes in these are not tested in the global state checker. + +sys_info <- Sys.info() +os_name <- sys_info["sysname"] +windows <- "windows" +on_windows <- grepl(windows, os_name, TRUE) + if (getRversion() >= "4.0.0") { - testthat::set_state_inspector(function() { - list( - attached = search(), - connections = getAllConnections(), - cwd = getwd(), - envvars = Sys.getenv(), - handlers = globalCallingHandlers(), - libpaths = .libPaths(), - locale = Sys.getlocale(), - options = options(), - par = get_pars_toreset(), - packages = .packages(all.available = TRUE), - sink = sink.number(), - timezone = Sys.timezone(), - NULL - ) - }) + if (on_windows) { + testthat::set_state_inspector(function() { + list( + attached = search(), + connections = getAllConnections(), + cwd = getwd(), + handlers = globalCallingHandlers(), + libpaths = .libPaths(), + locale = Sys.getlocale(), + packages = .packages(all.available = TRUE), + sink = sink.number(), + timezone = Sys.timezone(), + NULL + ) + }) + } else { + testthat::set_state_inspector(function() { + list( + attached = search(), + connections = getAllConnections(), + cwd = getwd(), + envvars = Sys.getenv(), + handlers = globalCallingHandlers(), + libpaths = .libPaths(), + locale = Sys.getlocale(), + options = options(), + packages = .packages(all.available = TRUE), + sink = sink.number(), + timezone = Sys.timezone(), + NULL + ) + }) + } } diff --git a/tests/testthat/test-functions.R b/tests/testthat/test-functions.R deleted file mode 100644 index 11d5eca..0000000 --- a/tests/testthat/test-functions.R +++ /dev/null @@ -1,7 +0,0 @@ -test_that("function works", { - x <- c(2, 3) - expect_equal( - get_manual_mean(x), - mean(x) - ) -}) diff --git a/tests/testthat/test-get_vimc_climate.R b/tests/testthat/test-get_vimc_climate.R new file mode 100644 index 0000000..f7ffbba --- /dev/null +++ b/tests/testthat/test-get_vimc_climate.R @@ -0,0 +1,117 @@ +test_that("Acessing local Parquet files works", { + country <- "Malawi" # only supported country at present + daterange <- lubridate::as_date(c("1990-01-01", "1990-01-10")) + admin_level <- 0 + + data <- load_local_vimc_climate( + country, + daterange, + test_path("testdata"), + "CHIRPS", + admin_level + ) + checkmate::expect_data_frame(data) + expect_identical( + unique(data$admin_unit_0), + as.character(admin_level) + ) + + # for admin level 1 + admin_level <- 1 + data <- load_local_vimc_climate( + country, + daterange, + test_path("testdata"), + "ERA5_mean", + admin_level + ) + checkmate::expect_data_frame(data) + + # expect dataframe list for all climate data sources + admin_level <- 0 + checkmate::expect_list( + lapply( + names(data_source_names), + load_local_vimc_climate, + country = country, + date_range = daterange, + data_location = test_path("testdata"), + admin_level = admin_level + ), + "data.frame" + ) +}) + +# Errors and warnings +test_that("vimclimate generates expected errors and warnings", { + daterange <- as.Date(c("1990-01-01", "1990-01-10")) + admin_level <- 0 + # badly formed country name + expect_error( + load_local_vimc_climate( + country = "MLWI", + daterange, + test_path("testdata"), + "CHIRPS", + admin_level + ), + "Could not convert `country`" + ) + + # data source not included + expect_error( + load_local_vimc_climate( + country = "MWI", + daterange, + test_path("testdata"), + "BIOCLIM", + admin_level + ), + "'data_source' must be one of" + ) + + # date ranges are bad + expect_error( + load_local_vimc_climate( + country = "MWI", + date_range = c(as.POSIXct("1990-01-01"), as.POSIXct("1990-01-10")), + test_path("testdata"), + "PERSIANN", + admin_level + ), + "Expected 'date_range' to be a Date" + ) + expect_error( + load_local_vimc_climate( + country = "MWI", + date_range = as.Date("1990-01-01"), + test_path("testdata"), + "PERSIANN", + admin_level + ), + "Expected 'date_range' to have length 2" + ) + + # data directory or file is not available + expect_error( + load_local_vimc_climate( + country = "MWI", + daterange, + test_path("testdata", "dummy"), + "PERSIANN", + admin_level + ), + "Directory does not exist" + ) + + expect_error( + load_local_vimc_climate( + country = "MWI", + daterange, + test_path("testdata"), + "PERSIANN", + admin_level = 1 + ), + "(File)*(not found); please check that data are present" + ) +}) diff --git a/tests/testthat/testdata/MWI/chirps_admin_0.parquet b/tests/testthat/testdata/MWI/chirps_admin_0.parquet new file mode 100644 index 0000000..7aff21d Binary files /dev/null and b/tests/testthat/testdata/MWI/chirps_admin_0.parquet differ diff --git a/tests/testthat/testdata/MWI/era5max_admin_0.parquet b/tests/testthat/testdata/MWI/era5max_admin_0.parquet new file mode 100644 index 0000000..20b61ff Binary files /dev/null and b/tests/testthat/testdata/MWI/era5max_admin_0.parquet differ diff --git a/tests/testthat/testdata/MWI/era5mean_admin_0.parquet b/tests/testthat/testdata/MWI/era5mean_admin_0.parquet new file mode 100644 index 0000000..7490366 Binary files /dev/null and b/tests/testthat/testdata/MWI/era5mean_admin_0.parquet differ diff --git a/tests/testthat/testdata/MWI/era5mean_admin_1.parquet b/tests/testthat/testdata/MWI/era5mean_admin_1.parquet new file mode 100644 index 0000000..53f0eac Binary files /dev/null and b/tests/testthat/testdata/MWI/era5mean_admin_1.parquet differ diff --git a/tests/testthat/testdata/MWI/era5min_admin_0.parquet b/tests/testthat/testdata/MWI/era5min_admin_0.parquet new file mode 100644 index 0000000..05589b1 Binary files /dev/null and b/tests/testthat/testdata/MWI/era5min_admin_0.parquet differ diff --git a/tests/testthat/testdata/MWI/era5rh_admin_0.parquet b/tests/testthat/testdata/MWI/era5rh_admin_0.parquet new file mode 100644 index 0000000..cb4f039 Binary files /dev/null and b/tests/testthat/testdata/MWI/era5rh_admin_0.parquet differ diff --git a/tests/testthat/testdata/MWI/era5sh_admin_0.parquet b/tests/testthat/testdata/MWI/era5sh_admin_0.parquet new file mode 100644 index 0000000..7b9ef36 Binary files /dev/null and b/tests/testthat/testdata/MWI/era5sh_admin_0.parquet differ diff --git a/tests/testthat/testdata/MWI/persiann_admin_0.parquet b/tests/testthat/testdata/MWI/persiann_admin_0.parquet new file mode 100644 index 0000000..76c9b7c Binary files /dev/null and b/tests/testthat/testdata/MWI/persiann_admin_0.parquet differ diff --git a/vignettes/ji-rpkg-template.Rmd b/vignettes/vimclimate.Rmd similarity index 83% rename from vignettes/ji-rpkg-template.Rmd rename to vignettes/vimclimate.Rmd index ad95a26..21b1f70 100644 --- a/vignettes/ji-rpkg-template.Rmd +++ b/vignettes/vimclimate.Rmd @@ -1,8 +1,8 @@ --- -title: "ji-rpkg-template" +title: "Getting started with vimclimate" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{ji-rpkg-template} + %\VignetteIndexEntry{Getting started with vimclimate} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -15,7 +15,7 @@ knitr::opts_chunk$set( ``` ```{r setup} -library(ji.rpkg.template) +library(vimclimate) ``` This is a special vignette, which shares the same name as the package. diff --git a/ji.rpkg.template.Rproj b/vimclimate.Rproj similarity index 58% rename from ji.rpkg.template.Rproj rename to vimclimate.Rproj index 8e3c2eb..adb5f37 100644 --- a/ji.rpkg.template.Rproj +++ b/vimclimate.Rproj @@ -1,4 +1,5 @@ Version: 1.0 +ProjectId: cba34698-ee26-4c23-80aa-f454188fb5b2 RestoreWorkspace: Default SaveWorkspace: Default @@ -11,3 +12,7 @@ Encoding: UTF-8 RnwWeave: Sweave LaTeX: pdfLaTeX + +BuildType: Package +PackageUseDevtools: Yes +PackageInstallArgs: --no-multiarch --with-keep.source