diff --git a/DESCRIPTION b/DESCRIPTION index 0c717bf..780e596 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -37,6 +37,9 @@ Imports: cli (>= 3.6.2) Suggests: crew (>= 0.9.2), + ncmeta, + sf, + stars, terra (>= 1.7.71), testthat (>= 3.0.0), withr (>= 3.0.0) diff --git a/NAMESPACE b/NAMESPACE index 063312a..807ca5c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,6 +2,8 @@ export(geotargets_option_get) export(geotargets_option_set) +export(tar_stars) +export(tar_stars_proxy) export(tar_terra_rast) export(tar_terra_sprc) export(tar_terra_vect) diff --git a/NEWS.md b/NEWS.md index 513a262..f7985cd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # geotargets (development version) +* Created `tar_stars()` and `tar_stars_proxy()` that create `stars` and `stars_proxy` objects, respectively. + # geotargets 0.1.0 (14 May 2024) * Created `tar_terra_rast()` and `tar_terra_vect()` for targets that create `SpatRaster` and `SpatVector` objects, respectively diff --git a/R/geotargets-option.R b/R/geotargets-option.R index ea0e89f..b02635c 100644 --- a/R/geotargets-option.R +++ b/R/geotargets-option.R @@ -30,7 +30,6 @@ #' @return Specific options, such as "gdal.raster.driver". See "Details" for #' more information. #' -#' #' @rdname geotargets-options #' @export #' @examples @@ -59,7 +58,6 @@ geotargets_option_set <- function( gdal_vector_driver = NULL, gdal_vector_creation_options = NULL ) { - # TODO do this programmatically with formals() or something? `options()` also accepts a named list options( "geotargets.gdal.raster.driver" = gdal_raster_driver %||% diff --git a/R/geotargets-package.R b/R/geotargets-package.R index b20dd73..878833d 100644 --- a/R/geotargets-package.R +++ b/R/geotargets-package.R @@ -7,6 +7,7 @@ NULL # clear CRAN checks spotting floating global variables #' @importFrom utils globalVariables +#' @importFrom rlang %||% utils::globalVariables( c( "packages" diff --git a/R/tar-stars.R b/R/tar-stars.R new file mode 100644 index 0000000..ad89856 --- /dev/null +++ b/R/tar-stars.R @@ -0,0 +1,283 @@ +#' Create a stars _stars_ Target +#' +#' Provides a target format for stars objects. +#' +#' @param driver character. File format expressed as GDAL driver names passed to [stars::write_stars()]. See [sf::st_drivers()]. +#' @param options character. GDAL driver specific datasource creation options passed to [stars::write_stars()] +#' @param proxy logical. Passed to [stars::read_stars()]. If `TRUE` the target will be read as an object of class `stars_proxy`. Otherwise, the object is class `stars`. +#' @param mdim logical. Use the [Multidimensional Raster Data Model](https://gdal.org/user/multidim_raster_data_model.html) via [stars::write_mdim()]? Default: `FALSE`. Only supported for some drivers, e.g. `"netCDF"` or `"Zarr"`. +#' @param ncdf logical. Use the NetCDF library directly to read data via [stars::read_ncdf()]? Default: `FALSE`. Only supported for `driver="netCDF"`. +#' @param ... Additional arguments not yet used +#' +#' @inheritParams targets::tar_target +#' @seealso [targets::tar_target_raw()] +#' @export +#' @examplesIf rlang::is_installed("stars") +#' if (Sys.getenv("TAR_LONG_EXAMPLES") == "true") { +#' targets::tar_dir({ # tar_dir() runs code from a temporary directory. +#' library(geotargets) +#' targets::tar_script({ +#' list( +#' geotargets::tar_stars( +#' stars_example, +#' stars::read_stars(system.file("tif", "olinda_dem_utm25s.tif", package = "stars")) +#' ) +#' ) +#' }) +#' targets::tar_make() +#' x <- targets::tar_read(stars_example) +#' }) +#'} +tar_stars <- function(name, + command, + pattern = NULL, + proxy = FALSE, + mdim = FALSE, + ncdf = FALSE, + driver = geotargets_option_get("gdal.raster.driver"), + options = geotargets_option_get("gdal.raster.creation.options"), + ..., + tidy_eval = targets::tar_option_get("tidy_eval"), + packages = targets::tar_option_get("packages"), + library = targets::tar_option_get("library"), + repository = targets::tar_option_get("repository"), + iteration = targets::tar_option_get("iteration"), + error = targets::tar_option_get("error"), + memory = targets::tar_option_get("memory"), + garbage_collection = targets::tar_option_get("garbage_collection"), + deployment = targets::tar_option_get("deployment"), + priority = targets::tar_option_get("priority"), + resources = targets::tar_option_get("resources"), + storage = targets::tar_option_get("storage"), + retrieval = targets::tar_option_get("retrieval"), + cue = targets::tar_option_get("cue")) { + + check_pkg_installed("stars") + + name <- targets::tar_deparse_language(substitute(name)) + + envir <- targets::tar_option_get("envir") + + command <- targets::tar_tidy_eval( + expr = as.expression(substitute(command)), + envir = envir, + tidy_eval = tidy_eval + ) + + pattern <- targets::tar_tidy_eval( + expr = as.expression(substitute(pattern)), + envir = envir, + tidy_eval = tidy_eval + ) + + tar_stars_raw( + name = name, + command = command, + pattern = pattern, + proxy = proxy, + mdim = mdim, + ncdf = ncdf, + driver = driver, + options = options, + packages = packages, + library = library, + repository = repository, + iteration = iteration, + error = error, + memory = memory, + garbage_collection = garbage_collection, + deployment = deployment, + priority = priority, + resources = resources, + storage = storage, + retrieval = retrieval, + cue = cue + ) +} + +#' @export +#' @rdname tar_stars +tar_stars_proxy <- function(name, + command, + pattern = NULL, + mdim = FALSE, + ncdf = FALSE, + driver = geotargets_option_get("gdal.raster.driver"), + options = geotargets_option_get("gdal.raster.creation.options"), + ..., + tidy_eval = targets::tar_option_get("tidy_eval"), + packages = targets::tar_option_get("packages"), + library = targets::tar_option_get("library"), + repository = targets::tar_option_get("repository"), + iteration = targets::tar_option_get("iteration"), + error = targets::tar_option_get("error"), + memory = targets::tar_option_get("memory"), + garbage_collection = targets::tar_option_get("garbage_collection"), + deployment = targets::tar_option_get("deployment"), + priority = targets::tar_option_get("priority"), + resources = targets::tar_option_get("resources"), + storage = targets::tar_option_get("storage"), + retrieval = targets::tar_option_get("retrieval"), + cue = targets::tar_option_get("cue")) { + + check_pkg_installed("stars") + + name <- targets::tar_deparse_language(substitute(name)) + + envir <- targets::tar_option_get("envir") + + command <- targets::tar_tidy_eval( + expr = as.expression(substitute(command)), + envir = envir, + tidy_eval = tidy_eval + ) + + pattern <- targets::tar_tidy_eval( + expr = as.expression(substitute(pattern)), + envir = envir, + tidy_eval = tidy_eval + ) + + tar_stars_raw( + name = name, + command = command, + pattern = pattern, + proxy = TRUE, + mdim = mdim, + ncdf = ncdf, + driver = driver, + options = options, + ..., + packages = packages, + library = library, + repository = repository, + iteration = iteration, + error = error, + memory = memory, + garbage_collection = garbage_collection, + deployment = deployment, + priority = priority, + resources = resources, + storage = storage, + retrieval = retrieval, + cue = cue + ) +} + + +#' tar_stars method with no tidy eval etc. +#' @noRd +tar_stars_raw <- function(name, + command, + pattern = NULL, + proxy, + mdim = FALSE, + ncdf = FALSE, + driver = geotargets_option_get("gdal.raster.driver"), + options = geotargets_option_get("gdal.raster.creation.options"), + ..., + tidy_eval = targets::tar_option_get("tidy_eval"), + packages = targets::tar_option_get("packages"), + library = targets::tar_option_get("library"), + repository = targets::tar_option_get("repository"), + iteration = targets::tar_option_get("iteration"), + error = targets::tar_option_get("error"), + memory = targets::tar_option_get("memory"), + garbage_collection = targets::tar_option_get("garbage_collection"), + deployment = targets::tar_option_get("deployment"), + priority = targets::tar_option_get("priority"), + resources = targets::tar_option_get("resources"), + storage = targets::tar_option_get("storage"), + retrieval = targets::tar_option_get("retrieval"), + cue = targets::tar_option_get("cue")) { + + driver <- driver %||% "GTiff" + options <- options %||% character(0) + + # get drivers available for writing (depends on user's GDAL build) + drv <- sf::st_drivers(what = "raster") + drv <- drv[drv$write, ] + + driver <- rlang::arg_match0(driver, drv$name) + + .read_stars <- eval(substitute( + function(path) { + + ## TODO: it appears envvar custom resources do not work in read function? + READ_FUN <- stars::read_stars + # mdim <- as.logical(Sys.getenv("GEOTARGETS_GDAL_RASTER_MDIM", unset = FALSE)) + if (mdim) { + READ_FUN <- stars::read_mdim + } + + # ncdf <- as.logical(Sys.getenv("GEOTARGETS_USE_NCMETA", unset = FALSE)) + if (ncdf && requireNamespace("ncmeta")) { + READ_FUN <- stars::read_ncdf + } + + # proxy <- as.logical(Sys.getenv("GEOTARGETS_PROXY", unset = FALSE)) + READ_FUN(path, proxy = proxy) + + }, list(ncdf = ncdf, mdim = mdim, proxy = proxy))) + + # TODO: should multidimensional array use the same `options` as 2D? + .write_stars <- function(object, path) { + + WRITE_FUN <- stars::write_stars + + mdim <- as.logical(Sys.getenv("GEOTARGETS_GDAL_RASTER_MDIM", + unset = FALSE)) + if (mdim) { + WRITE_FUN <- stars::write_mdim + } + + dr <- Sys.getenv("GEOTARGETS_GDAL_RASTER_DRIVER") + + # stars requires character(0), not "", for no options set + co <- Sys.getenv("GEOTARGETS_GDAL_RASTER_CREATION_OPTIONS") + co2 <- strsplit(co, ";")[[1]] + + WRITE_FUN( + object, + path, + overwrite = TRUE, + driver = dr, + options = co + ) + } + + targets::tar_target_raw( + name = name, + command = command, + pattern = pattern, + packages = packages, + library = library, + format = targets::tar_format( + read = .read_stars, + write = .write_stars, + marshal = function(object) object, # Not currently used + unmarshal = function(object) object + ), + repository = repository, + iteration = iteration, + error = error, + memory = memory, + garbage_collection = garbage_collection, + deployment = deployment, + priority = priority, + resources = utils::modifyList(targets::tar_resources( + custom_format = targets::tar_resources_custom_format( + #these envvars are used in read and write functions of format + envvars = c("GEOTARGETS_GDAL_RASTER_DRIVER" = driver, + "GEOTARGETS_GDAL_RASTER_CREATION_OPTIONS" = + paste0(options, collapse = ";"), + "GEOTARGETS_GDAL_RASTER_MDIM" = mdim, + "GEOTARGETS_PROXY" = proxy, + "GEOTARGETS_USE_NCMETA" = ncdf) + ) + ), resources), + storage = storage, + retrieval = retrieval, + cue = cue + ) +} diff --git a/README.Rmd b/README.Rmd index 1fd67e5..8840963 100644 --- a/README.Rmd +++ b/README.Rmd @@ -60,6 +60,7 @@ We currently provide support for the `terra` package with `targets`. Below we sh - `tar_terra_rast()` - `tar_terra_vect()` - `tar_terra_sprc()` +- `tar_stars()` You would use these in place of `tar_target()` in your targets pipeline, when you are doing work with `terra` raster, vector, or raster collection data. @@ -69,19 +70,24 @@ If you would like to see and download working examples for yourself, see the rep ```{r} #| label: tar-terra-rast -#| eval: false library(targets) + tar_dir({ # tar_dir() runs code from a temporary directory. tar_script({ - library(targets) library(geotargets) + + get_elev <- function() { + terra::rast(system.file("ex", "elev.tif", package = "terra")) + } + list( tar_terra_rast( terra_rast_example, - system.file("ex/elev.tif", package = "terra") |> terra::rast() + get_elev() ) ) }) + tar_make() x <- tar_read(terra_rast_example) x @@ -93,18 +99,16 @@ tar_dir({ # tar_dir() runs code from a temporary directory. ```{r} #| label: tar-terra-vect -#| eval: false tar_dir({ # tar_dir() runs code from a temporary directory. tar_script({ library(geotargets) + lux_area <- function(projection = "EPSG:4326") { - terra::project( - terra::vect(system.file("ex", "lux.shp", - package = "terra" - )), - projection - ) + terra::project(terra::vect(system.file("ex", "lux.shp", + package = "terra")), + projection) } + list( tar_terra_vect( terra_vect_example, @@ -112,6 +116,7 @@ tar_dir({ # tar_dir() runs code from a temporary directory. ) ) }) + tar_make() x <- tar_read(terra_vect_example) x @@ -123,21 +128,23 @@ tar_dir({ # tar_dir() runs code from a temporary directory. ```{r} #| label: tar-terra-sprc -#| eval: false -targets::tar_dir({ # tar_dir() runs code from a temporary directory. - library(geotargets) - targets::tar_script({ +tar_dir({ # tar_dir() runs code from a temporary directory. + tar_script({ + + library(geotargets) + elev_scale <- function(z = 1, projection = "EPSG:4326") { terra::project( terra::rast(system.file("ex", "elev.tif", package = "terra")) * z, projection ) } + list( tar_terra_sprc( raster_elevs, # two rasters, one unaltered, one scaled by factor of 2 and - # reprojected to interrupted good homolosine + # reprojected to interrupted goode homolosine command = terra::sprc(list( elev_scale(1), elev_scale(2, "+proj=igh") @@ -145,11 +152,38 @@ targets::tar_dir({ # tar_dir() runs code from a temporary directory. ) ) }) - targets::tar_make() - x <- targets::tar_read(raster_elevs) + + tar_make() + x <- tar_read(raster_elevs) + x }) ``` + + +## `tar_stars()`: targets with stars objects + +```{r} +#| label: tar-stars +tar_dir({ # tar_dir() runs code from a temporary directory. + tar_script({ + library(geotargets) + + list( + tar_stars( + test_stars, + stars::read_stars(system.file("tif", "olinda_dem_utm25s.tif", package = "stars")) + ) + ) + }) + + tar_make() + x <- tar_read(test_stars) + x +}) +``` + + ## Code of Conduct Please note that the geotargets project is released with a [Contributor Code of Conduct](https://contributor-covenant.org/version/2/1/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. diff --git a/README.md b/README.md index f527180..23c6552 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Below we show three examples of target factories: - `tar_terra_rast()` - `tar_terra_vect()` - `tar_terra_sprc()` +- `tar_stars()` You would use these in place of `tar_target()` in your targets pipeline, when you are doing work with `terra` raster, vector, or raster @@ -77,21 +78,39 @@ the repo, ``` r library(targets) + tar_dir({ # tar_dir() runs code from a temporary directory. tar_script({ - library(targets) library(geotargets) + + get_elev <- function() { + terra::rast(system.file("ex", "elev.tif", package = "terra")) + } + list( tar_terra_rast( terra_rast_example, - system.file("ex/elev.tif", package = "terra") |> terra::rast() + get_elev() ) ) }) + tar_make() x <- tar_read(terra_rast_example) x }) +#> ▶ dispatched target terra_rast_example +#> ● completed target terra_rast_example [0.019 seconds] +#> ▶ ended pipeline [0.185 seconds] +#> class : SpatRaster +#> dimensions : 90, 95, 1 (nrow, ncol, nlyr) +#> resolution : 0.008333333, 0.008333333 (x, y) +#> extent : 5.741667, 6.533333, 49.44167, 50.19167 (xmin, xmax, ymin, ymax) +#> coord. ref. : lon/lat WGS 84 (EPSG:4326) +#> source : terra_rast_example +#> name : elevation +#> min value : 141 +#> max value : 547 ``` ## `tar_terra_vect()`: targets with terra vectors @@ -100,14 +119,13 @@ tar_dir({ # tar_dir() runs code from a temporary directory. tar_dir({ # tar_dir() runs code from a temporary directory. tar_script({ library(geotargets) + lux_area <- function(projection = "EPSG:4326") { - terra::project( - terra::vect(system.file("ex", "lux.shp", - package = "terra" - )), - projection - ) + terra::project(terra::vect(system.file("ex", "lux.shp", + package = "terra")), + projection) } + list( tar_terra_vect( terra_vect_example, @@ -115,29 +133,47 @@ tar_dir({ # tar_dir() runs code from a temporary directory. ) ) }) + tar_make() x <- tar_read(terra_vect_example) x }) +#> ▶ dispatched target terra_vect_example +#> ● completed target terra_vect_example [0.034 seconds] +#> ▶ ended pipeline [0.173 seconds] +#> class : SpatVector +#> geometry : polygons +#> dimensions : 12, 6 (geometries, attributes) +#> extent : 5.74414, 6.528252, 49.44781, 50.18162 (xmin, xmax, ymin, ymax) +#> source : terra_vect_example +#> coord. ref. : lon/lat WGS 84 (EPSG:4326) +#> names : ID_1 NAME_1 ID_2 NAME_2 AREA POP +#> type : +#> values : 1 Diekirch 1 Clervaux 312 18081 +#> 1 Diekirch 2 Diekirch 218 32543 +#> 1 Diekirch 3 Redange 259 18664 ``` ## `tar_terra_sprc()`: targets with terra raster collections ``` r -targets::tar_dir({ # tar_dir() runs code from a temporary directory. - library(geotargets) - targets::tar_script({ +tar_dir({ # tar_dir() runs code from a temporary directory. + tar_script({ + + library(geotargets) + elev_scale <- function(z = 1, projection = "EPSG:4326") { terra::project( terra::rast(system.file("ex", "elev.tif", package = "terra")) * z, projection ) } + list( tar_terra_sprc( raster_elevs, # two rasters, one unaltered, one scaled by factor of 2 and - # reprojected to interrupted good homolosine + # reprojected to interrupted goode homolosine command = terra::sprc(list( elev_scale(1), elev_scale(2, "+proj=igh") @@ -145,9 +181,60 @@ targets::tar_dir({ # tar_dir() runs code from a temporary directory. ) ) }) - targets::tar_make() - x <- targets::tar_read(raster_elevs) + + tar_make() + x <- tar_read(raster_elevs) + x +}) +#> ▶ dispatched target raster_elevs +#> ● completed target raster_elevs [0.112 seconds] +#> ▶ ended pipeline [0.266 seconds] +#> Warning message: +#> [rast] skipped sub-datasets (see 'describe(sds=TRUE)'): +#> /private/var/folders/wr/by_lst2d2fngf67mknmgf4340000gn/T/Rtmpr9sjXA/targets_1085a12a40d0c/_targets/scratch/raster_elevs +#> class : SpatRasterCollection +#> length : 2 +#> nrow : 90, 115 +#> ncol : 95, 114 +#> nlyr : 1, 1 +#> extent : 5.741667, 1558890, 49.44167, 5556741 (xmin, xmax, ymin, ymax) +#> crs (first) : lon/lat WGS 84 (EPSG:4326) +#> names : raster_elevs, raster_elevs +``` + +## `tar_stars()`: targets with stars objects + +``` r +tar_dir({ # tar_dir() runs code from a temporary directory. + tar_script({ + library(geotargets) + + list( + tar_stars( + test_stars, + stars::read_stars(system.file("tif", "olinda_dem_utm25s.tif", package = "stars")) + ) + ) + }) + + tar_make() + x <- tar_read(test_stars) + x }) +#> ▶ dispatched target test_stars +#> ● completed target test_stars [0.053 seconds] +#> ▶ ended pipeline [0.17 seconds] +#> Warning message: +#> In CPL_write_gdal(mat, file, driver, options, type, dims, from, : +#> GDAL Message 6: creation option '' is not formatted with the key=value format +#> stars object with 2 dimensions and 1 attribute +#> attribute(s): +#> Min. 1st Qu. Median Mean 3rd Qu. Max. +#> test_stars -1 6 12 21.66521 35 88 +#> dimension(s): +#> from to offset delta refsys point x/y +#> x 1 111 288776 89.99 UTM Zone 25, Southern Hem... FALSE [x] +#> y 1 111 9120761 -89.99 UTM Zone 25, Southern Hem... FALSE [y] ``` ## Code of Conduct diff --git a/man/tar_stars.Rd b/man/tar_stars.Rd new file mode 100644 index 0000000..cab7958 --- /dev/null +++ b/man/tar_stars.Rd @@ -0,0 +1,277 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tar-stars.R +\name{tar_stars} +\alias{tar_stars} +\alias{tar_stars_proxy} +\title{Create a stars \emph{stars} Target} +\usage{ +tar_stars( + name, + command, + pattern = NULL, + proxy = FALSE, + mdim = FALSE, + ncdf = FALSE, + driver = geotargets_option_get("gdal.raster.driver"), + options = geotargets_option_get("gdal.raster.creation.options"), + ..., + tidy_eval = targets::tar_option_get("tidy_eval"), + packages = targets::tar_option_get("packages"), + library = targets::tar_option_get("library"), + repository = targets::tar_option_get("repository"), + iteration = targets::tar_option_get("iteration"), + error = targets::tar_option_get("error"), + memory = targets::tar_option_get("memory"), + garbage_collection = targets::tar_option_get("garbage_collection"), + deployment = targets::tar_option_get("deployment"), + priority = targets::tar_option_get("priority"), + resources = targets::tar_option_get("resources"), + storage = targets::tar_option_get("storage"), + retrieval = targets::tar_option_get("retrieval"), + cue = targets::tar_option_get("cue") +) + +tar_stars_proxy( + name, + command, + pattern = NULL, + mdim = FALSE, + ncdf = FALSE, + driver = geotargets_option_get("gdal.raster.driver"), + options = geotargets_option_get("gdal.raster.creation.options"), + ..., + tidy_eval = targets::tar_option_get("tidy_eval"), + packages = targets::tar_option_get("packages"), + library = targets::tar_option_get("library"), + repository = targets::tar_option_get("repository"), + iteration = targets::tar_option_get("iteration"), + error = targets::tar_option_get("error"), + memory = targets::tar_option_get("memory"), + garbage_collection = targets::tar_option_get("garbage_collection"), + deployment = targets::tar_option_get("deployment"), + priority = targets::tar_option_get("priority"), + resources = targets::tar_option_get("resources"), + storage = targets::tar_option_get("storage"), + retrieval = targets::tar_option_get("retrieval"), + cue = targets::tar_option_get("cue") +) +} +\arguments{ +\item{name}{Symbol, name of the target. A target +name must be a valid name for a symbol in R, and it +must not start with a dot. Subsequent targets +can refer to this name symbolically to induce a dependency relationship: +e.g. \code{tar_target(downstream_target, f(upstream_target))} is a +target named \code{downstream_target} which depends on a target +\code{upstream_target} and a function \code{f()}. In addition, a target's +name determines its random number generator seed. In this way, +each target runs with a reproducible seed so someone else +running the same pipeline should get the same results, +and no two targets in the same pipeline share the same seed. +(Even dynamic branches have different names and thus different seeds.) +You can recover the seed of a completed target +with \code{tar_meta(your_target, seed)} and run \code{\link[targets:tar_seed_set]{tar_seed_set()}} +on the result to locally recreate the target's initial RNG state.} + +\item{command}{R code to run the target.} + +\item{pattern}{Language to define branching for a target. +For example, in a pipeline with numeric vector targets \code{x} and \code{y}, +\code{tar_target(z, x + y, pattern = map(x, y))} implicitly defines +branches of \code{z} that each compute \code{x[1] + y[1]}, \code{x[2] + y[2]}, +and so on. See the user manual for details.} + +\item{proxy}{logical. Passed to \code{\link[stars:read_stars]{stars::read_stars()}}. If \code{TRUE} the target will be read as an object of class \code{stars_proxy}. Otherwise, the object is class \code{stars}.} + +\item{mdim}{logical. Use the \href{https://gdal.org/user/multidim_raster_data_model.html}{Multidimensional Raster Data Model} via \code{\link[stars:mdim]{stars::write_mdim()}}? Default: \code{FALSE}. Only supported for some drivers, e.g. \code{"netCDF"} or \code{"Zarr"}.} + +\item{ncdf}{logical. Use the NetCDF library directly to read data via \code{\link[stars:read_ncdf]{stars::read_ncdf()}}? Default: \code{FALSE}. Only supported for \code{driver="netCDF"}.} + +\item{driver}{character. File format expressed as GDAL driver names passed to \code{\link[stars:write_stars]{stars::write_stars()}}. See \code{\link[sf:st_drivers]{sf::st_drivers()}}.} + +\item{options}{character. GDAL driver specific datasource creation options passed to \code{\link[stars:write_stars]{stars::write_stars()}}} + +\item{...}{Additional arguments not yet used} + +\item{tidy_eval}{Logical, whether to enable tidy evaluation +when interpreting \code{command} and \code{pattern}. If \code{TRUE}, you can use the +"bang-bang" operator \verb{!!} to programmatically insert +the values of global objects.} + +\item{packages}{Character vector of packages to load right before +the target runs or the output data is reloaded for +downstream targets. Use \code{tar_option_set()} to set packages +globally for all subsequent targets you define.} + +\item{library}{Character vector of library paths to try +when loading \code{packages}.} + +\item{repository}{Character of length 1, remote repository for target +storage. Choices: +\itemize{ +\item \code{"local"}: file system of the local machine. +\item \code{"aws"}: Amazon Web Services (AWS) S3 bucket. Can be configured +with a non-AWS S3 bucket using the \code{endpoint} argument of +\code{\link[targets:tar_resources_aws]{tar_resources_aws()}}, but versioning capabilities may be lost +in doing so. +See the cloud storage section of +\url{https://books.ropensci.org/targets/data.html} +for details for instructions. +\item \code{"gcp"}: Google Cloud Platform storage bucket. +See the cloud storage section of +\url{https://books.ropensci.org/targets/data.html} +for details for instructions. +} + +Note: if \code{repository} is not \code{"local"} and \code{format} is \code{"file"} +then the target should create a single output file. +That output file is uploaded to the cloud and tracked for changes +where it exists in the cloud. The local file is deleted after +the target runs.} + +\item{iteration}{Character of length 1, name of the iteration mode +of the target. Choices: +\itemize{ +\item \code{"vector"}: branching happens with \code{vctrs::vec_slice()} and +aggregation happens with \code{vctrs::vec_c()}. +\item \code{"list"}, branching happens with \verb{[[]]} and aggregation happens with +\code{list()}. +\item \code{"group"}: \code{dplyr::group_by()}-like functionality to branch over +subsets of a non-dynamic data frame. +For \code{iteration = "group"}, the target must not by dynamic +(the \code{pattern} argument of \code{\link[targets:tar_target]{tar_target()}} must be left \code{NULL}). +The target's return value must be a data +frame with a special \code{tar_group} column of consecutive integers +from 1 through the number of groups. Each integer designates a group, +and a branch is created for each collection of rows in a group. +See the \code{\link[targets:tar_group]{tar_group()}} function to see how you can +create the special \code{tar_group} column with \code{dplyr::group_by()}. +}} + +\item{error}{Character of length 1, what to do if the target +stops and throws an error. Options: +\itemize{ +\item \code{"stop"}: the whole pipeline stops and throws an error. +\item \code{"continue"}: the whole pipeline keeps going. +\item \code{"abridge"}: any currently running targets keep running, +but no new targets launch after that. +(Visit \url{https://books.ropensci.org/targets/debugging.html} +to learn how to debug targets using saved workspaces.) +\item \code{"null"}: The errored target continues and returns \code{NULL}. +The data hash is deliberately wrong so the target is not +up to date for the next run of the pipeline. +}} + +\item{memory}{Character of length 1, memory strategy. +If \code{"persistent"}, the target stays in memory +until the end of the pipeline (unless \code{storage} is \code{"worker"}, +in which case \code{targets} unloads the value from memory +right after storing it in order to avoid sending +copious data over a network). +If \code{"transient"}, the target gets unloaded +after every new target completes. +Either way, the target gets automatically loaded into memory +whenever another target needs the value. +For cloud-based dynamic files +(e.g. \code{format = "file"} with \code{repository = "aws"}), +this memory strategy applies to the +temporary local copy of the file: +\code{"persistent"} means it remains until the end of the pipeline +and is then deleted, +and \code{"transient"} means it gets deleted as soon as possible. +The former conserves bandwidth, +and the latter conserves local storage.} + +\item{garbage_collection}{Logical, whether to run \code{base::gc()} +just before the target runs.} + +\item{deployment}{Character of length 1. If \code{deployment} is +\code{"main"}, then the target will run on the central controlling R process. +Otherwise, if \code{deployment} is \code{"worker"} and you set up the pipeline +with distributed/parallel computing, then +the target runs on a parallel worker. For more on distributed/parallel +computing in \code{targets}, please visit +\url{https://books.ropensci.org/targets/crew.html}.} + +\item{priority}{Numeric of length 1 between 0 and 1. Controls which +targets get deployed first when multiple competing targets are ready +simultaneously. Targets with priorities closer to 1 get dispatched earlier +(and polled earlier in \code{\link[targets:tar_make_future]{tar_make_future()}}).} + +\item{resources}{Object returned by \code{tar_resources()} +with optional settings for high-performance computing +functionality, alternative data storage formats, +and other optional capabilities of \code{targets}. +See \code{tar_resources()} for details.} + +\item{storage}{Character of length 1, only relevant to +\code{\link[targets:tar_make_clustermq]{tar_make_clustermq()}} and \code{\link[targets:tar_make_future]{tar_make_future()}}. +Must be one of the following values: +\itemize{ +\item \code{"main"}: the target's return value is sent back to the +host machine and saved/uploaded locally. +\item \code{"worker"}: the worker saves/uploads the value. +\item \code{"none"}: almost never recommended. It is only for +niche situations, e.g. the data needs to be loaded +explicitly from another language. If you do use it, +then the return value of the target is totally ignored +when the target ends, but +each downstream target still attempts to load the data file +(except when \code{retrieval = "none"}). + +If you select \code{storage = "none"}, then +the return value of the target's command is ignored, +and the data is not saved automatically. +As with dynamic files (\code{format = "file"}) it is the +responsibility of the user to write to +the data store from inside the target. + +The distinguishing feature of \code{storage = "none"} +(as opposed to \code{format = "file"}) +is that in the general case, +downstream targets will automatically try to load the data +from the data store as a dependency. As a corollary, \code{storage = "none"} +is completely unnecessary if \code{format} is \code{"file"}. +}} + +\item{retrieval}{Character of length 1, only relevant to +\code{\link[targets:tar_make_clustermq]{tar_make_clustermq()}} and \code{\link[targets:tar_make_future]{tar_make_future()}}. +Must be one of the following values: +\itemize{ +\item \code{"main"}: the target's dependencies are loaded on the host machine +and sent to the worker before the target runs. +\item \code{"worker"}: the worker loads the targets dependencies. +\item \code{"none"}: the dependencies are not loaded at all. +This choice is almost never recommended. It is only for +niche situations, e.g. the data needs to be loaded +explicitly from another language. +}} + +\item{cue}{An optional object from \code{tar_cue()} to customize the +rules that decide whether the target is up to date.} +} +\description{ +Provides a target format for stars objects. +} +\examples{ +\dontshow{if (rlang::is_installed("stars")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} +if (Sys.getenv("TAR_LONG_EXAMPLES") == "true") { + targets::tar_dir({ # tar_dir() runs code from a temporary directory. + library(geotargets) + targets::tar_script({ + list( + geotargets::tar_stars( + stars_example, + stars::read_stars(system.file("tif", "olinda_dem_utm25s.tif", package = "stars")) + ) + ) + }) + targets::tar_make() + x <- targets::tar_read(stars_example) + }) +} +\dontshow{\}) # examplesIf} +} +\seealso{ +\code{\link[targets:tar_target_raw]{targets::tar_target_raw()}} +} diff --git a/tests/testthat/_snaps/tar-stars.md b/tests/testthat/_snaps/tar-stars.md new file mode 100644 index 0000000..c0ccff9 --- /dev/null +++ b/tests/testthat/_snaps/tar-stars.md @@ -0,0 +1,56 @@ +# tar_stars() works + + Code + x + Output + stars object with 2 dimensions and 1 attribute + attribute(s): + Min. 1st Qu. Median Mean 3rd Qu. Max. + test_stars -1 6 12 21.66521 35 88 + dimension(s): + from to offset delta refsys point x/y + x 1 111 288776 89.99 UTM Zone 25, Southern Hem... FALSE [x] + y 1 111 9120761 -89.99 UTM Zone 25, Southern Hem... FALSE [y] + +# tar_stars_proxy() works + + Code + x + Output + stars_proxy object with 1 attribute in 1 file(s): + $test_stars_proxy + [1] "[...]/test_stars_proxy" + + dimension(s): + from to offset delta refsys point x/y + x 1 111 288776 89.99 UTM Zone 25, Southern Hem... FALSE [x] + y 1 111 9120761 -89.99 UTM Zone 25, Southern Hem... FALSE [y] + +# tar_stars(mdim=TRUE) works + + Code + x + Output + stars object with 2 dimensions and 1 attribute + attribute(s): + Min. 1st Qu. Median Mean 3rd Qu. Max. + Precipitation 0.03524588 0.3224987 0.3772574 0.4289465 0.511113 0.9204841 + dimension(s): + from to offset delta refsys point values + stations 1 2 NA NA NA TRUE POINT (0 1), POINT (3 5) + time 1 5 2022-05-02 1 days Date NA NULL + +# tar_stars(mdim=TRUE, ncdf=TRUE) works + + Code + x + Output + stars object with 2 dimensions and 1 attribute + attribute(s): + Min. 1st Qu. Median Mean 3rd Qu. Max. + Precipitation 0.03524588 0.3224987 0.3772574 0.4289465 0.511113 0.9204841 + dimension(s): + from to offset delta x/y + stations 1 2 0.5 1 [x] + time 1 5 2022-05-02 UTC 1 days [y] + diff --git a/tests/testthat/test-tar-stars.R b/tests/testthat/test-tar-stars.R new file mode 100644 index 0000000..266d58f --- /dev/null +++ b/tests/testthat/test-tar-stars.R @@ -0,0 +1,80 @@ +# test_that() #Included to make RStudio recognize this file as a test + +skip_if_not_installed("stars") + +targets::tar_test("tar_stars() works", { + geotargets::geotargets_option_set(gdal_raster_creation_options = c("COMPRESS=DEFLATE", "TFW=YES")) + targets::tar_script({ + list(geotargets::tar_stars( + test_stars, + stars::read_stars(system.file("tif", "olinda_dem_utm25s.tif", package = "stars")) + )) + }) + targets::tar_make() + x <- targets::tar_read(test_stars) + expect_s3_class(x, "stars") + expect_snapshot( + x + ) +}) + +targets::tar_test("tar_stars_proxy() works", { + geotargets::geotargets_option_set(gdal_raster_creation_options = c("COMPRESS=DEFLATE", "TFW=YES")) + targets::tar_script({ + list(geotargets::tar_stars_proxy( + test_stars_proxy, + stars::read_stars(system.file("tif", "olinda_dem_utm25s.tif", package = "stars")) + )) + }) + targets::tar_make() + x <- targets::tar_read(test_stars_proxy) + expect_s3_class(x, "stars_proxy") + expect_snapshot( + x + ) +}) + + +targets::tar_test("tar_stars(mdim=TRUE) works", { + targets::tar_script({ + geotargets::geotargets_option_set(gdal_raster_driver = "netCDF") + list(geotargets::tar_stars(test_stars_mdim, { + set.seed(135) + m <- matrix(runif(10), 2, 5) + names(dim(m)) <- c("stations", "time") + times <- as.Date("2022-05-01") + 1:5 + pts <- sf::st_as_sfc(c("POINT(0 1)", "POINT(3 5)")) + s <- stars::st_as_stars(list(Precipitation = m)) |> + stars::st_set_dimensions(1, values = pts) |> + stars::st_set_dimensions(2, values = times) + }, mdim = TRUE)) + }) + + targets::tar_make() + x <- targets::tar_read(test_stars_mdim) + expect_s3_class(x, "stars") + expect_snapshot(x) +}) + + +targets::tar_test("tar_stars(mdim=TRUE, ncdf=TRUE) works", { + targets::tar_script({ + list(geotargets::tar_stars(test_stars_mdim_ncdf, { + set.seed(135) + m <- matrix(runif(10), 2, 5) + names(dim(m)) <- c("stations", "time") + times <- as.Date("2022-05-01") + 1:5 + pts <- sf::st_as_sfc(c("POINT(0 1)", "POINT(3 5)")) + s <- stars::st_as_stars(list(Precipitation = m)) |> + stars::st_set_dimensions(1, values = pts) |> + stars::st_set_dimensions(2, values = times) + s + }, driver = "netCDF", mdim = TRUE, ncdf = TRUE)) + }) + + targets::tar_make() + # warnings related to no CRS + suppressWarnings({x <- targets::tar_read(test_stars_mdim_ncdf)}) + expect_s3_class(x, "stars") + expect_snapshot(x) +}) diff --git a/tests/testthat/test-tar-terra.R b/tests/testthat/test-tar-terra.R index 7328906..55dfb5f 100644 --- a/tests/testthat/test-tar-terra.R +++ b/tests/testthat/test-tar-terra.R @@ -1,7 +1,6 @@ # test_that() #Included to make RStudio recognize this file as a test library(targets) targets::tar_test("tar_terra_rast() works", { - # geotargets::geotargets_option_set(gdal_raster_creation_options = c("COMPRESS=DEFLATE", "TFW=YES")) targets::tar_script({ list( geotargets::tar_terra_rast(