From b933e4b1c90f63002e4130a638f3313ad9ec582f Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Fri, 26 Sep 2025 17:24:48 -0700 Subject: [PATCH 01/29] chore: update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 357de0bd..0877d137 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ whiteboxR.Rproj *.shx *.prj *.dbf +*.cpg *.tif settings.json __MACOSX From 4f1b2e58c453280d0439886de59cdc35349d520e Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Thu, 9 Oct 2025 17:08:34 -0700 Subject: [PATCH 02/29] fix: tempfiles in `wbt_source()` should be relative to tempdir not working directory --- R/wbt_source.R | 41 ++++++++++++++++++++++++----------------- man/wbt_source.Rd | 8 +++++++- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index f2b18642..a4a9d57e 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -1,11 +1,13 @@ #' Initialize an R object containing spatial data for use by WhiteboxTools #' -#' @param x A terra SpatVector or sf object, or a path to a file that can be read as a SpatVectorProxy +#' @param x A terra SpatVector or sf object, or a path to a file that can be read as a SpatVectorProxy. Or a SpatRaster object that exists only in memory, or references a source file. #' @param dsn Data source path / file name #' @param layer Data layer +#' @param tmpdir Directory to write temporary ESRI Shapefiles for vector input in memory or otherwise not already in shapefile. Default: `tempdir()` +#' @param pattern Character vector giving the initial part of the temporary file name #' @param force Force write of vector data to file? Default: FALSE (only write if file does not exist) -#' @param ... Additional arguments passed to `terra::writeVector()` or `sf::st_write()` #' @param verbose Print information about data source and contents? +#' @param ... Additional arguments passed to `terra::writeVector()` or `sf::st_write()` #' @return An R object with attributes `wbt_dsn` and `wbt_layer` set as needed to support reading and writing R objects from file by WhiteboxTools. #' @keywords General #' @export @@ -13,6 +15,8 @@ wbt_source <- function(x, dsn = NULL, layer = NULL, force = FALSE, + tmpdir = tempdir(), + pattern = "wbt", verbose = wbt_verbose(), ...) { @@ -24,8 +28,8 @@ wbt_source <- function(x, if (file.exists(x)) { # convert to shapefile if needed if (!grepl("\\.shp$", x)) { - xp <- paste0(basename(x), "_", basename(tempfile()), ".shp") - fp <- file.path(tempdir(), xp) + xp <- paste0(basename(x), "_", basename(tempfile(pattern = pattern)), ".shp") + fp <- file.path(tmpdir, xp) if (!requireNamespace("terra")) { stop("package `terra` is required to convert non-Shapefile vector sources to Shapefile") @@ -47,6 +51,19 @@ wbt_source <- function(x, } } + ext <- ".shp" + if (inherits(x, c('SpatRaster', 'RasterLayer', + 'RasterStack', 'RasterBrick'))) { + if (!inherits(x, 'SpatRaster')) { + x <- terra::rast(x) + } + ext <- ".tif" + src <- terra::sources(x) + if (src != "") { + dsn <- src + } + } + # NULL dsn (TODO: GDAL-supported dsn not supported by WBT) if (is.null(dsn)) { # if (gpkg) { @@ -57,19 +74,9 @@ wbt_source <- function(x, # only supported vector format is the ESRI Shapefile. # TODO: dbf limitations? use alternate wbt/gdal common format? if (!is.null(layer)) { - bn <- layer - } else bn <- "file" - wd <- wbt_wd() - if (wd == "") - wd <- getwd() - ext <- ".shp" - if (inherits(x, 'SpatRaster') || - inherits(x, 'RasterLayer') || - inherits(x, 'RasterStack') || - inherits(x, 'RasterBrick')) { - ext <- ".tif" - } - dsn <- tempfile(pattern = bn, tmpdir = wd, fileext = ext) + bn <- paste(pattern, layer, sep = "_") + } else bn <- pattern + dsn <- tempfile(pattern = bn, fileext = ext) # } } diff --git a/man/wbt_source.Rd b/man/wbt_source.Rd index ff376b27..57ccb5bd 100644 --- a/man/wbt_source.Rd +++ b/man/wbt_source.Rd @@ -9,12 +9,14 @@ wbt_source( dsn = NULL, layer = NULL, force = FALSE, + tmpdir = tempdir(), + pattern = "wbt", verbose = wbt_verbose(), ... ) } \arguments{ -\item{x}{A terra SpatVector or sf object, or a path to a file that can be read as a SpatVectorProxy} +\item{x}{A terra SpatVector or sf object, or a path to a file that can be read as a SpatVectorProxy. Or a SpatRaster object that exists only in memory, or references a source file.} \item{dsn}{Data source path / file name} @@ -22,6 +24,10 @@ wbt_source( \item{force}{Force write of vector data to file? Default: FALSE (only write if file does not exist)} +\item{tmpdir}{Directory to write temporary ESRI Shapefiles for vector input in memory or otherwise not already in shapefile. Default: \code{tempdir()}} + +\item{pattern}{Character vector giving the initial part of the temporary file name} + \item{verbose}{Print information about data source and contents?} \item{...}{Additional arguments passed to \code{terra::writeVector()} or \code{sf::st_write()}} From 28724e2ca1d8b0e0491d656a7d12bd90a87bee05 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Thu, 9 Oct 2025 17:49:43 -0700 Subject: [PATCH 03/29] version bump --- DESCRIPTION | 6 +++--- NEWS.md | 14 ++++++++++++++ inst/CITATION | 6 +++--- man/whitebox-package.Rd | 2 +- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 98cd46f9..5ca18ae1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,16 +1,16 @@ Package: whitebox Type: Package Title: 'WhiteboxTools' R Frontend -Version: 2.4.1 +Version: 2.4.2 Description: An R frontend for the 'WhiteboxTools' library, which is an advanced geospatial data analysis platform developed by Prof. John Lindsay at the University of Guelph's Geomorphometry and Hydrogeomatics Research Group. 'WhiteboxTools' can be used to perform common geographical information systems (GIS) analysis operations, such as cost-distance analysis, distance buffering, and raster reclassification. Remote sensing and image processing tasks include image enhancement (e.g. panchromatic sharpening, contrast adjustments), image mosaicing, numerous filtering operations, simple classification (k-means), and common image transformations. 'WhiteboxTools' also contains advanced tooling for spatial hydrological analysis (e.g. flow-accumulation, watershed delineation, stream network analysis, sink removal), terrain analysis (e.g. common terrain indices such as slope, curvatures, wetness index, hillshading; hypsometric analysis; multi-scale topographic position analysis), and LiDAR data processing. Suggested citation: Lindsay (2016) . Authors@R: c(person("Qiusheng", "Wu", email = "giswqs@gmail.com", role = c("aut")), - person("Andrew", "Brown", email = "brown.andrewg@gmail.com", role = c("ctb", "cre"))) + person("Andrew", "Brown", email = "brown.andrewg@gmail.com", role = c("aut", "cre"), comment=c(ORCID="0000-0002-4565-533X"))) Maintainer: Andrew Brown License: MIT + file LICENSE SystemRequirements: WhiteboxTools (https://github.com/jblindsay/whitebox-tools/releases/latest) Encoding: UTF-8 Language: en-US -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 Roxygen: list(markdown = TRUE) URL: https://whiteboxr.gishub.org/, https://github.com/opengeos/whiteboxR BugReports: https://github.com/opengeos/whiteboxR/issues diff --git a/NEWS.md b/NEWS.md index 86fdf56e..aa3a8e46 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,17 @@ +# whitebox 2.4.2 + + * `wbt_source()`: now accepts `tmpdir` argument which defaults to `tempdir()` (not `getwd()` or `wbt_wd()`) that is used for storing the intermediate shapefiles needed for WhiteboxTools + + * Also, the pattern for temporary file names is now customizable via `pattern` argument + + * Bug fixes for `wbt_source()`: + + * No longer writes temporary intermediate shapefiles to the working directory when passed a non-shapefile vector data source. + + * The temporary directory is used by default, unless new `tmpdir` argument is specified. This could be a breaking change if you were relying on the temporary files to be present in the WhiteboxTools working directory. Specify `wd = getwd()` or equivalent for old behavior. + + * Properly uses `layer` argument for data sources (e.g. GPKG) that may contain multiple vector layers of interest (thanks to @mps9506 for reporting; #132) + # whitebox 2.4.1 * Rebuilt `wbttools` and `wbttoolparameters` with WhiteboxTools v2.4.0 diff --git a/inst/CITATION b/inst/CITATION index 7fc37e86..a7a821b1 100644 --- a/inst/CITATION +++ b/inst/CITATION @@ -4,10 +4,10 @@ bibentry( bibtype = "Manual", title = "'whitebox': 'WhiteboxTools' R Frontend", author = "Qiusheng Wu, Andrew Brown", - note = "R package version 2.2.0", + note = "R package version 2.4.2", url = "https://CRAN.R-project.org/package=whitebox", - year = "2022", - textVersion = "Wu, Q., Brown, A. (2022). whitebox: 'WhiteboxTools' R Frontend. R package version 2.2.0. " + year = "2025", + textVersion = "Wu, Q., Brown, A. (2025). whitebox: 'WhiteboxTools' R Frontend. R package version 2.2.0. " ) bibentry( diff --git a/man/whitebox-package.Rd b/man/whitebox-package.Rd index c675daa0..0eae16de 100644 --- a/man/whitebox-package.Rd +++ b/man/whitebox-package.Rd @@ -26,7 +26,7 @@ The package options can be overridden with system environment variables: \code{R \code{\link[=wbt_init]{wbt_init()}}, \code{\link[=wbt_options]{wbt_options()}}, \code{\link[=install_whitebox]{install_whitebox()}} } \author{ -\strong{Maintainer}: Andrew Brown \email{brown.andrewg@gmail.com} [contributor] +\strong{Maintainer}: Andrew Brown \email{brown.andrewg@gmail.com} (\href{https://orcid.org/0000-0002-4565-533X}{ORCID}) Authors: \itemize{ From 9f576b0a5252d9b314234670db52f82364249ebf Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Thu, 9 Oct 2025 18:06:21 -0700 Subject: [PATCH 04/29] Update NEWS.md --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index aa3a8e46..81b57587 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,7 +8,7 @@ * No longer writes temporary intermediate shapefiles to the working directory when passed a non-shapefile vector data source. - * The temporary directory is used by default, unless new `tmpdir` argument is specified. This could be a breaking change if you were relying on the temporary files to be present in the WhiteboxTools working directory. Specify `wd = getwd()` or equivalent for old behavior. + * The temporary directory is used by default, unless new `tmpdir` argument is specified. This could be a breaking change if you were relying on the temporary files to be present in the WhiteboxTools working directory. Specify `tmpdir` in call to `wbt_source()` to make old behavior explicit. * Properly uses `layer` argument for data sources (e.g. GPKG) that may contain multiple vector layers of interest (thanks to @mps9506 for reporting; #132) From 53f9df042e527df3336d2448e0801d4d9355aa24 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Thu, 9 Oct 2025 18:09:28 -0700 Subject: [PATCH 05/29] Update inst/CITATION --- inst/CITATION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/CITATION b/inst/CITATION index a7a821b1..088755a5 100644 --- a/inst/CITATION +++ b/inst/CITATION @@ -7,7 +7,7 @@ bibentry( note = "R package version 2.4.2", url = "https://CRAN.R-project.org/package=whitebox", year = "2025", - textVersion = "Wu, Q., Brown, A. (2025). whitebox: 'WhiteboxTools' R Frontend. R package version 2.2.0. " + textVersion = "Wu, Q., Brown, A. (2025). whitebox: 'WhiteboxTools' R Frontend. R package version 2.4.2. " ) bibentry( From 8a85456ad0cc3d9a0d4819029afef16baa243ec5 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Thu, 9 Oct 2025 18:09:40 -0700 Subject: [PATCH 06/29] fix: `wbt_source()` pass `tmpdir` for `dsn` construction --- R/wbt_source.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index a4a9d57e..2e680334 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -76,7 +76,7 @@ wbt_source <- function(x, if (!is.null(layer)) { bn <- paste(pattern, layer, sep = "_") } else bn <- pattern - dsn <- tempfile(pattern = bn, fileext = ext) + dsn <- tempfile(pattern = bn, tmpdir = tmpdir, fileext = ext) # } } From f481a1c19f5ad95974d8367093e414087677cfed Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Thu, 9 Oct 2025 18:32:44 -0700 Subject: [PATCH 07/29] fix: `wbt_source()` handle terra::sources output --- R/wbt_source.R | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index 2e680334..a8c387bc 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -59,8 +59,11 @@ wbt_source <- function(x, } ext <- ".tif" src <- terra::sources(x) - if (src != "") { - dsn <- src + if (length(src) > 0 && any(nzchar(src))) { + if (length(src) > 1) { + message("Object 'x' has multiple source files; using first non-empty source path") + } + dsn <- src[which(nzchar(src))[1]] } } @@ -74,8 +77,10 @@ wbt_source <- function(x, # only supported vector format is the ESRI Shapefile. # TODO: dbf limitations? use alternate wbt/gdal common format? if (!is.null(layer)) { - bn <- paste(pattern, layer, sep = "_") - } else bn <- pattern + bn <- paste(pattern, "_", layer) + } else { + bn <- pattern + } dsn <- tempfile(pattern = bn, tmpdir = tmpdir, fileext = ext) # } } From 03048905fb37bf59fdeba74aade199b05051ac3c Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Thu, 9 Oct 2025 18:36:06 -0700 Subject: [PATCH 08/29] fix: `wbt_source()` handle terra::sources output (2) --- R/wbt_source.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index a8c387bc..63c5e267 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -77,7 +77,7 @@ wbt_source <- function(x, # only supported vector format is the ESRI Shapefile. # TODO: dbf limitations? use alternate wbt/gdal common format? if (!is.null(layer)) { - bn <- paste(pattern, "_", layer) + bn <- paste0(pattern, "_", layer) } else { bn <- pattern } From 95f8af51c8b7aa179a5efb0e5e7487b454ff7ee9 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Thu, 9 Oct 2025 18:56:05 -0700 Subject: [PATCH 09/29] spellcheck --- inst/WORDLIST | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/inst/WORDLIST b/inst/WORDLIST index d51eb887..d03374de 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -8,11 +8,9 @@ BACKTRACE BreachDepressions Breakline CMD -CRS CamelCase Ceil Centre -Centroid Christoph ClassificationError Colour @@ -52,6 +50,7 @@ François Frontend GAT GDAL +GPKG GeoKey GeoPackage GeoTIFF @@ -77,7 +76,6 @@ InPlaceAdd InPlaceSubtract InverseMultiQuadric Isobasins -JSON JandR Jens Jenson @@ -108,6 +106,7 @@ NDI NoData Northness Num +ORCID OSAVI OptionList POLYLINE @@ -136,7 +135,6 @@ Rasterizes Reclass Reinitializes RemoveSpurs -Rescale Rgb Robinne Rosenfeld @@ -206,7 +204,6 @@ cageo centerlines centred centres -centroid cls codecov colour @@ -219,7 +216,6 @@ darboux decorrelation depressionless dev -differencing dinf directionality doi @@ -282,7 +278,6 @@ lengthed lidar liu lq -macOS magrittr medoid meso @@ -303,12 +298,10 @@ neighbouring neighbours nn nodata -normals num nw olympic parallelepiped -parallelize parsable pearson planchon @@ -318,13 +311,10 @@ pre pts quant quartic -quartile ransac raster's -rasters rbf reclass -repo rgb rgdal sca @@ -332,7 +322,6 @@ scattergram se shapetype sibson -sigmoid sigmoidal silverman sinh @@ -358,7 +347,6 @@ vals viewshed viewsheds viridi -viridis wang watershedding wb From 26be95acb55f7f516b399c7b693f8c39699c124e Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Fri, 10 Oct 2025 09:57:11 -0700 Subject: [PATCH 10/29] fix: handling of various object input types - fix branching with sf-only dependencies - ensure all supported objects pass thru correctly --- R/wbt_source.R | 112 +++++++++++++++++++++++++++++++++------------- man/wbt_source.Rd | 20 ++++++--- 2 files changed, 96 insertions(+), 36 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index 63c5e267..600dbe49 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -1,14 +1,22 @@ #' Initialize an R object containing spatial data for use by WhiteboxTools #' -#' @param x A terra SpatVector or sf object, or a path to a file that can be read as a SpatVectorProxy. Or a SpatRaster object that exists only in memory, or references a source file. +#' @param x A terra SpatVector or sf object (in memory) or a path to a file that +#' can be read as a SpatVectorProxy. Or a memory or file-based SpatRaster. +#' SpatRaster objects with multiple #' @param dsn Data source path / file name #' @param layer Data layer -#' @param tmpdir Directory to write temporary ESRI Shapefiles for vector input in memory or otherwise not already in shapefile. Default: `tempdir()` -#' @param pattern Character vector giving the initial part of the temporary file name -#' @param force Force write of vector data to file? Default: FALSE (only write if file does not exist) +#' @param tmpdir Directory to write temporary ESRI Shapefiles for vector input +#' in memory or otherwise not already in shapefile. Default: `tempdir()` +#' @param pattern Character vector giving the initial part of the temporary file +#' name +#' @param force Force write of vector data to file? Default: FALSE (only write +#' if file does not exist and new file is needed) #' @param verbose Print information about data source and contents? -#' @param ... Additional arguments passed to `terra::writeVector()` or `sf::st_write()` -#' @return An R object with attributes `wbt_dsn` and `wbt_layer` set as needed to support reading and writing R objects from file by WhiteboxTools. +#' @param ... Additional arguments passed to `terra::writeVector()` or +#' `sf::st_write()` +#' @return An R object (SpatRaster, SpatVector, SpatVectorProxy, sf) with +#' attributes `wbt_dsn` and `wbt_layer` set as needed to support reading and +#' writing R objects from file by WhiteboxTools. #' @keywords General #' @export wbt_source <- function(x, @@ -20,31 +28,62 @@ wbt_source <- function(x, verbose = wbt_verbose(), ...) { - if (!requireNamespace("terra")) { - stop("package `terra` is required to convert vector sources to `wbt()`-compatible SpatVectorProxy", call. = FALSE) + if (length(layer) > 1) { + stop("argument `layer` must have length 1 or 0 (NULL)", call. = FALSE) + } + + .check_pkg_ns <- function(pkg) { + if (!requireNamespace(pkg)) { + stop("package `", pkg, "` is required to convert to `wbt()`-compatible data sources", call. = FALSE) + } } if (is.character(x)) { if (file.exists(x)) { - # convert to shapefile if needed - if (!grepl("\\.shp$", x)) { - xp <- paste0(basename(x), "_", basename(tempfile(pattern = pattern)), ".shp") - fp <- file.path(tmpdir, xp) + .check_pkg_ns("terra") - if (!requireNamespace("terra")) { - stop("package `terra` is required to convert non-Shapefile vector sources to Shapefile") - } + # convert to shapefile if needed + x2 <- try(terra::vect(x, layer = ifelse(is.null(layer), "", layer), proxy = TRUE), silent = TRUE) + fp <- file.path(tmpdir, paste0(basename(x), "_", basename(tempfile(pattern = pattern)))) + if (!inherits(x2, 'try-error') && !grepl("\\.shp$", x)) { + fp <- paste0(fp, ".shp") - x2 <- terra::vect(x, layer = ifelse(is.null(layer), "", layer)) - if (terra::writeVector(x2, fp)) { + if (terra::writeVector(terra::query(x2), fp)) { x <- fp } else { stop("Failed to convert `x` (", x, ") to Shapefile.") } + } else if (inherits(x2, 'try-error')) { + if (!grepl("\\.tiff?$", x) || length(layer) > 0) { + # try reading a raster file and writing to geotiff + fp <- paste0(fp, ".tif") + if (length(layer) > 0) { + x2 <- terra::rast(x, lyrs = layer[1]) + } else { + x2 <- terra::rast(x) + } + if (terra::writeRaster(x2, fp)) { + x <- fp + } else { + stop("Failed to convert `x` (", x, ") to GeoTIFF") + } + } + x <- terra::rast(x) + } + + if (!inherits(x, 'SpatRaster')) { + # a SpatVectorProxy allows us to get some basic info without loading the whole file + x <- terra::vect(x, proxy = TRUE) + } + + if (is.character(x) && !file.exists(x)) { + stop("File (", x, ") does not exist") + } + + if (!inherits(x, c("SpatRaster", "SpatVectorProxy"))) { + stop("Unhandled input object type") } - # a SpatVectorProxy allows us to get some basic info without loading the whole file - x <- terra::vect(x, proxy = TRUE) attr(x, 'wbt_dsn') <- terra::sources(x) attr(x, 'wbt_layer') <- layer return(x) @@ -54,6 +93,7 @@ wbt_source <- function(x, ext <- ".shp" if (inherits(x, c('SpatRaster', 'RasterLayer', 'RasterStack', 'RasterBrick'))) { + .check_pkg_ns("terra") if (!inherits(x, 'SpatRaster')) { x <- terra::rast(x) } @@ -86,18 +126,30 @@ wbt_source <- function(x, } if (!file.exists(dsn) || force) { - # convert less common types to core types - if (inherits(x, 'sfc') || inherits(x, 'Spatial')) { - x <- sf::st_as_sf(x) - } - # write to file/db - if (inherits(x, 'SpatVector')) { - terra::writeVector(x, filename = dsn, layer = layer, ...) - } else if (inherits(x, 'sf')) { - sf::st_write(x, dsn = dsn, layer = layer, quiet = !verbose, ...) - } else if (inherits(x, 'SpatRaster')) { - terra::writeRaster(x, filename = dsn) + # write to file/db + if (inherits(x, c('SpatVector', 'SpatVectorProxy', 'SpatRaster'))) { + .check_pkg_ns("terra") + if (inherits(x, 'SpatVectorProxy')) { + x <- terra::query(x) + } + if (inherits(x, 'SpatVector')) { + terra::writeVector(x, filename = dsn, layer = layer, ...) + } else if (inherits(x, 'SpatRaster')) { + terra::writeRaster(x, filename = dsn, ...) + } + } else { + + .check_pkg_ns("sf") + + # convert less common types to core types + if (inherits(x, 'sfc') || inherits(x, 'Spatial')) { + x <- sf::st_as_sf(x) + } + + if (inherits(x, 'sf')) { + sf::st_write(x, dsn = dsn, layer = layer, quiet = !verbose, ...) + } } } diff --git a/man/wbt_source.Rd b/man/wbt_source.Rd index 57ccb5bd..8745c148 100644 --- a/man/wbt_source.Rd +++ b/man/wbt_source.Rd @@ -16,24 +16,32 @@ wbt_source( ) } \arguments{ -\item{x}{A terra SpatVector or sf object, or a path to a file that can be read as a SpatVectorProxy. Or a SpatRaster object that exists only in memory, or references a source file.} +\item{x}{A terra SpatVector or sf object (in memory) or a path to a file that +can be read as a SpatVectorProxy. Or a memory or file-based SpatRaster. +SpatRaster objects with multiple} \item{dsn}{Data source path / file name} \item{layer}{Data layer} -\item{force}{Force write of vector data to file? Default: FALSE (only write if file does not exist)} +\item{force}{Force write of vector data to file? Default: FALSE (only write +if file does not exist and new file is needed)} -\item{tmpdir}{Directory to write temporary ESRI Shapefiles for vector input in memory or otherwise not already in shapefile. Default: \code{tempdir()}} +\item{tmpdir}{Directory to write temporary ESRI Shapefiles for vector input +in memory or otherwise not already in shapefile. Default: \code{tempdir()}} -\item{pattern}{Character vector giving the initial part of the temporary file name} +\item{pattern}{Character vector giving the initial part of the temporary file +name} \item{verbose}{Print information about data source and contents?} -\item{...}{Additional arguments passed to \code{terra::writeVector()} or \code{sf::st_write()}} +\item{...}{Additional arguments passed to \code{terra::writeVector()} or +\code{sf::st_write()}} } \value{ -An R object with attributes \code{wbt_dsn} and \code{wbt_layer} set as needed to support reading and writing R objects from file by WhiteboxTools. +An R object (SpatRaster, SpatVector, SpatVectorProxy, sf) with +attributes \code{wbt_dsn} and \code{wbt_layer} set as needed to support reading and +writing R objects from file by WhiteboxTools. } \description{ Initialize an R object containing spatial data for use by WhiteboxTools From 0c71c8b3e2aedca991602418c7279da11c7f014c Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Fri, 10 Oct 2025 10:19:49 -0700 Subject: [PATCH 11/29] for code review --- R/wbt_source.R | 32 +++++++++++++++++++++++--------- man/wbt_source.Rd | 10 +++++++--- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index 600dbe49..e83d2392 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -2,9 +2,13 @@ #' #' @param x A terra SpatVector or sf object (in memory) or a path to a file that #' can be read as a SpatVectorProxy. Or a memory or file-based SpatRaster. -#' SpatRaster objects with multiple +#' SpatRaster object. When `x` has multiple layers/bands, the first layer is +#' used by default; use the \code{layer} argument to select a specific +#' layer/band. #' @param dsn Data source path / file name -#' @param layer Data layer +#' @param layer Data layer. For vectors, `layer` is interpreted as a layer +#' name (character); for rasters, `layer` is interpreted as a band index or +#' name (integer OR character) #' @param tmpdir Directory to write temporary ESRI Shapefiles for vector input #' in memory or otherwise not already in shapefile. Default: `tempdir()` #' @param pattern Character vector giving the initial part of the temporary file @@ -13,7 +17,7 @@ #' if file does not exist and new file is needed) #' @param verbose Print information about data source and contents? #' @param ... Additional arguments passed to `terra::writeVector()` or -#' `sf::st_write()` +#' `sf::st_write()`, or `terra::writeRaster` (for rasters). #' @return An R object (SpatRaster, SpatVector, SpatVectorProxy, sf) with #' attributes `wbt_dsn` and `wbt_layer` set as needed to support reading and #' writing R objects from file by WhiteboxTools. @@ -45,7 +49,7 @@ wbt_source <- function(x, # convert to shapefile if needed x2 <- try(terra::vect(x, layer = ifelse(is.null(layer), "", layer), proxy = TRUE), silent = TRUE) fp <- file.path(tmpdir, paste0(basename(x), "_", basename(tempfile(pattern = pattern)))) - if (!inherits(x2, 'try-error') && !grepl("\\.shp$", x)) { + if (!inherits(x2, 'try-error') && !grepl("\\.shp$", x, ignore.case = TRUE)) { fp <- paste0(fp, ".shp") if (terra::writeVector(terra::query(x2), fp)) { @@ -54,7 +58,7 @@ wbt_source <- function(x, stop("Failed to convert `x` (", x, ") to Shapefile.") } } else if (inherits(x2, 'try-error')) { - if (!grepl("\\.tiff?$", x) || length(layer) > 0) { + if (!grepl("\\.tiff?$", x, ignore.case = TRUE) || length(layer) > 0) { # try reading a raster file and writing to geotiff fp <- paste0(fp, ".tif") if (length(layer) > 0) { @@ -134,12 +138,15 @@ wbt_source <- function(x, x <- terra::query(x) } if (inherits(x, 'SpatVector')) { - terra::writeVector(x, filename = dsn, layer = layer, ...) + terra::writeVector(x, + filename = dsn, + layer = layer, + overwrite = force, + ...) } else if (inherits(x, 'SpatRaster')) { - terra::writeRaster(x, filename = dsn, ...) + terra::writeRaster(x, filename = dsn, overwrite = force, ...) } } else { - .check_pkg_ns("sf") # convert less common types to core types @@ -148,7 +155,14 @@ wbt_source <- function(x, } if (inherits(x, 'sf')) { - sf::st_write(x, dsn = dsn, layer = layer, quiet = !verbose, ...) + sf::st_write( + x, + dsn = dsn, + layer = layer, + quiet = !verbose, + delete_dsn = force, + ... + ) } } } diff --git a/man/wbt_source.Rd b/man/wbt_source.Rd index 8745c148..72981b71 100644 --- a/man/wbt_source.Rd +++ b/man/wbt_source.Rd @@ -18,11 +18,15 @@ wbt_source( \arguments{ \item{x}{A terra SpatVector or sf object (in memory) or a path to a file that can be read as a SpatVectorProxy. Or a memory or file-based SpatRaster. -SpatRaster objects with multiple} +SpatRaster object. When \code{x} has multiple layers/bands, the first layer is +used by default; use the \code{layer} argument to select a specific +layer/band.} \item{dsn}{Data source path / file name} -\item{layer}{Data layer} +\item{layer}{Data layer. For vectors, \code{layer} is interpreted as a layer +name (character); for rasters, \code{layer} is interpreted as a band index or +name (integer OR character)} \item{force}{Force write of vector data to file? Default: FALSE (only write if file does not exist and new file is needed)} @@ -36,7 +40,7 @@ name} \item{verbose}{Print information about data source and contents?} \item{...}{Additional arguments passed to \code{terra::writeVector()} or -\code{sf::st_write()}} +\code{sf::st_write()}, or \code{terra::writeRaster} (for rasters).} } \value{ An R object (SpatRaster, SpatVector, SpatVectorProxy, sf) with From 1561b08946e3e8564614969ecf10ed248a71f06d Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Fri, 10 Oct 2025 11:31:02 -0700 Subject: [PATCH 12/29] wbt_source: be explicit about use of first source --- R/wbt_source.R | 32 +++++++++++++++++++++----------- man/wbt_source.Rd | 5 ++--- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index e83d2392..2afa2bdc 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -2,9 +2,8 @@ #' #' @param x A terra SpatVector or sf object (in memory) or a path to a file that #' can be read as a SpatVectorProxy. Or a memory or file-based SpatRaster. -#' SpatRaster object. When `x` has multiple layers/bands, the first layer is -#' used by default; use the \code{layer} argument to select a specific -#' layer/band. +#' When `x` has multiple layers/bands, the first layer is used by default; use +#' the \code{layer} argument to select a specific layer/band. #' @param dsn Data source path / file name #' @param layer Data layer. For vectors, `layer` is interpreted as a layer #' name (character); for rasters, `layer` is interpreted as a band index or @@ -42,6 +41,17 @@ wbt_source <- function(x, } } + .first_source <- function(x) { + src <- terra::sources(x) + if (length(src) > 0 && any(nzchar(src))) { + if (length(src) > 1) { + message("Object 'x' has multiple source files; using first non-empty source path") + } + src <- src[which(nzchar(src))[1]] + } + src + } + if (is.character(x)) { if (file.exists(x)) { .check_pkg_ns("terra") @@ -88,9 +98,11 @@ wbt_source <- function(x, stop("Unhandled input object type") } - attr(x, 'wbt_dsn') <- terra::sources(x) + attr(x, 'wbt_dsn') <- .first_source(x) attr(x, 'wbt_layer') <- layer return(x) + } else { + stop("File (", x, ") does not exist") } } @@ -102,13 +114,8 @@ wbt_source <- function(x, x <- terra::rast(x) } ext <- ".tif" - src <- terra::sources(x) - if (length(src) > 0 && any(nzchar(src))) { - if (length(src) > 1) { - message("Object 'x' has multiple source files; using first non-empty source path") - } - dsn <- src[which(nzchar(src))[1]] - } + + dsn <- .first_source(x) } # NULL dsn (TODO: GDAL-supported dsn not supported by WBT) @@ -144,6 +151,9 @@ wbt_source <- function(x, overwrite = force, ...) } else if (inherits(x, 'SpatRaster')) { + if (is.null(layer) && terra::nlyr(x) > 1) { + x <- x[[1]] + } terra::writeRaster(x, filename = dsn, overwrite = force, ...) } } else { diff --git a/man/wbt_source.Rd b/man/wbt_source.Rd index 72981b71..29f92e1e 100644 --- a/man/wbt_source.Rd +++ b/man/wbt_source.Rd @@ -18,9 +18,8 @@ wbt_source( \arguments{ \item{x}{A terra SpatVector or sf object (in memory) or a path to a file that can be read as a SpatVectorProxy. Or a memory or file-based SpatRaster. -SpatRaster object. When \code{x} has multiple layers/bands, the first layer is -used by default; use the \code{layer} argument to select a specific -layer/band.} +When \code{x} has multiple layers/bands, the first layer is used by default; use +the \code{layer} argument to select a specific layer/band.} \item{dsn}{Data source path / file name} From 940288fcf91e114a08d04751c88d1d135215818f Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Fri, 10 Oct 2025 17:39:12 -0700 Subject: [PATCH 13/29] fix: wbt_source: raster source with user-specified `dsn` or `layer` --- R/wbt_source.R | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index 2afa2bdc..524a1b25 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -95,7 +95,7 @@ wbt_source <- function(x, } if (!inherits(x, c("SpatRaster", "SpatVectorProxy"))) { - stop("Unhandled input object type") + stop("Unhandled input object type: ", paste(class(x), collapse = ", ")) } attr(x, 'wbt_dsn') <- .first_source(x) @@ -115,7 +115,9 @@ wbt_source <- function(x, } ext <- ".tif" - dsn <- .first_source(x) + if (is.null(dsn)) { + dsn <- .first_source(x) + } } # NULL dsn (TODO: GDAL-supported dsn not supported by WBT) @@ -151,7 +153,9 @@ wbt_source <- function(x, overwrite = force, ...) } else if (inherits(x, 'SpatRaster')) { - if (is.null(layer) && terra::nlyr(x) > 1) { + if (!is.null(layer)) { + x <- x[[layer[1]]] + } else if (terra::nlyr(x) > 1) { x <- x[[1]] } terra::writeRaster(x, filename = dsn, overwrite = force, ...) From 11b27a0c16ef00d69e1c02f9e9ce44558675bcca Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Fri, 10 Oct 2025 17:44:46 -0700 Subject: [PATCH 14/29] fix: wbt_source: verbosity of multiple source files message --- R/wbt_source.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index 524a1b25..e42bb3d0 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -45,7 +45,9 @@ wbt_source <- function(x, src <- terra::sources(x) if (length(src) > 0 && any(nzchar(src))) { if (length(src) > 1) { - message("Object 'x' has multiple source files; using first non-empty source path") + if (verbose) { + message("object 'x' has multiple source files; using first non-empty source path") + } } src <- src[which(nzchar(src))[1]] } From a5ac1025202970d4195c7c495a80c383983d01d3 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Fri, 10 Oct 2025 18:47:54 -0700 Subject: [PATCH 15/29] feat: add STATSGO2 shapefile dataset for DEM.tif extent and `sample_soils_data()` --- NAMESPACE | 1 + R/wbt.R | 144 ++++++++------------- R/whitebox-package.R | 49 +++++++ data-raw/STATSGO_shapefile.R | 18 +++ inst/extdata/STATSGO2.cpg | 1 + inst/extdata/STATSGO2.dbf | Bin 0 -> 1107 bytes inst/extdata/STATSGO2.prj | 1 + inst/extdata/STATSGO2.shp | Bin 0 -> 21116 bytes inst/extdata/STATSGO2.shx | Bin 0 -> 172 bytes man/{sample_dem_data.Rd => extdata-gis.Rd} | 9 +- 10 files changed, 127 insertions(+), 96 deletions(-) create mode 100644 data-raw/STATSGO_shapefile.R create mode 100644 inst/extdata/STATSGO2.cpg create mode 100644 inst/extdata/STATSGO2.dbf create mode 100644 inst/extdata/STATSGO2.prj create mode 100644 inst/extdata/STATSGO2.shp create mode 100644 inst/extdata/STATSGO2.shx rename man/{sample_dem_data.Rd => extdata-gis.Rd} (70%) diff --git a/NAMESPACE b/NAMESPACE index 0cb2aaa3..22a0ca1e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -10,6 +10,7 @@ S3method(wbt_result,wbt_result) export(check_whitebox_binary) export(install_whitebox) export(sample_dem_data) +export(sample_soils_data) export(wbt) export(wbt_absolute_value) export(wbt_accumulation_curvature) diff --git a/R/wbt.R b/R/wbt.R index dad56449..c4924749 100644 --- a/R/wbt.R +++ b/R/wbt.R @@ -1,5 +1,5 @@ #' Initialize 'WhiteboxTools' -#' +#' #' `wbt_init()`: Check if a suitable 'WhiteboxTools' executable is present. Search default path in package directory or set it manually with `exe_path`. #' #' @param exe_path Default `exe_path` is result of `wbt_exe_path()` which checks a few user-settable options before defaulting to the package installation directory sub-directory "WBT". May be overridden if a custom path is needed. @@ -40,11 +40,11 @@ wbt_init <- function(exe_path = wbt_exe_path(shell_quote = FALSE), !is.null(wd) || !is.null(verbose) || !is.null(compress_rasters)) { - + if (!is.null(wd) && length(wd) > 0 && (is.na(wd) || wd == "")) { .wbt_wd_unset() } - + # set the path with wbt_options wbt_options(exe_path = exe_path, ...) } @@ -61,7 +61,7 @@ wbt_init <- function(exe_path = wbt_exe_path(shell_quote = FALSE), if (wbt_verbose()) { message("WhiteboxTools Executable Path (whitebox.exe_path) reverted to:\n\t", new_exe_path) } - } + } if (check_version) { # check version info, provide ONE message per session if mismatched exv <- try(wbt_version(extract = TRUE), silent = TRUE) @@ -81,7 +81,7 @@ wbt_init <- function(exe_path = wbt_exe_path(shell_quote = FALSE), warned <- FALSE } if (wbt_verbose() && isFALSE(warned)) { - message("NOTE: Installed WhiteboxTools version (", exv, + message("NOTE: Installed WhiteboxTools version (", exv, ") is ", ifelse(exv > pkv, "newer", "older"), " than the package data (", pkv, ").") try(assign("whitebox.warned_version_difference", @@ -101,7 +101,7 @@ wbt_init <- function(exe_path = wbt_exe_path(shell_quote = FALSE), #' #' - **`whitebox.wd`** - character. Path to WhiteboxTools working directory. Used as `--wd` argument for tools that support it when `wd` is not specified elsewhere. #' -#' - **`whitebox.verbose`** - logical. Should standard output from calls to executable be `cat()` out for readability? When `whitebox.verbose=FALSE` no output is produced. Set the value of `whitebox.verbose` with `wbt_verbose()` `verbose` argument. Default is result of `interactive()` if R package options are unset. +#' - **`whitebox.verbose`** - logical. Should standard output from calls to executable be `cat()` out for readability? When `whitebox.verbose=FALSE` no output is produced. Set the value of `whitebox.verbose` with `wbt_verbose()` `verbose` argument. Default is result of `interactive()` if R package options are unset. #' #' - **`whitebox.compress_rasters`** - logical. Should raster output from WhiteboxTools be compressed? Default: `NULL` uses existing WhiteboxTools settings. Set the value of `whitebox.compress_rasters` with `wbt_compress_rasters()` `compress_rasters` argument. #' @@ -302,10 +302,10 @@ wbt_data_dir <- function() { #' \dontrun{ #' #' ## wbt_wd(): -#' +#' #' # no working directory set #' wbt_wd(wd = "") -#' +#' #' # set WBT working directory to R working directory #' wbt_wd(wd = getwd()) #' } @@ -325,7 +325,7 @@ wbt_wd <- function(wd = NULL) { if (nchar(syswd) > 0 && dir.exists(syswd)) { return(syswd) } - + # package option checked next; if missing default is getwd() (unspecified should be same as getwd()) res <- getOption("whitebox.wd") @@ -547,7 +547,7 @@ wbt_install <- function(pkg_dir = wbt_data_dir(), platform = NULL, force = FALSE if (.Machine$sizeof.pointer != 8) { return(invisible(.unsupported())) } - + if (missing(platform) || is.null(platform)) { if (os == "Linux") { url <- "https://www.whiteboxgeo.com/WBT_Linux/WhiteboxTools_linux_amd64.zip" @@ -563,11 +563,11 @@ wbt_install <- function(pkg_dir = wbt_data_dir(), platform = NULL, force = FALSE return(invisible(.unsupported())) } } else { - # supports alternative platforms/filenames + # supports alternative platforms/filenames # e.g. linux_musl, darwin_m_series url <- paste0("https://www.whiteboxgeo.com/WBT_", os, "/WhiteboxTools_", - platform, ".zip") + platform, ".zip") } filename <- basename(url) @@ -609,7 +609,7 @@ wbt_install <- function(pkg_dir = wbt_data_dir(), platform = NULL, force = FALSE ex_dir <- file.path(pkg_dir, gsub("\\.zip$", "", basename(exe_zip))) file.copy(file.path(ex_dir, "WBT"), pkg_dir, recursive = TRUE) file.remove(list.files(ex_dir, recursive = TRUE, full.names = TRUE)) - + # subfolder WBT/whitebox_tools exe_path_out <- file.path(pkg_dir, "WBT", basename(exe_path)) Sys.chmod(exe_path_out, '755') @@ -646,11 +646,11 @@ wbt_install <- function(pkg_dir = wbt_data_dir(), platform = NULL, force = FALSE # many packages provide an "install_*" method; alias wbt_install mirrors the wbt_ prefix for most operations. Documentation refers to install_whitebox() #' Download and Install 'WhiteboxTools' -#' +#' #' This function downloads the 'WhiteboxTools' binary if needed. Pre-compiled binaries are #' only available for download for 64-bit Linux (default compiled with glibc on Ubuntu 22.04; #' use `platform="linux_musl"` for musl/earlier versions of glibc), Windows and Mac OS (ARM and -#' Intel) platforms. If you need WhiteboxTools for another platform follow the instructions to +#' Intel) platforms. If you need WhiteboxTools for another platform follow the instructions to #' build from source: \url{https://github.com/jblindsay/whitebox-tools} #' #' 'WhiteboxTools' and all of its extensions can be uninstalled by passing the `remove=TRUE` argument. @@ -703,13 +703,13 @@ wbt_install_extension <- function(extension = c( "MacOS_Intel")) } else { # non-default options include: linux_musl, MacOS_ARM - sufx <- platform + sufx <- platform } - + if (sn == "Darwin" && Sys.info()["machine"] == "arm64") { suffix <- "MacOS_ARM" } - + # GTE if ("GeneralToolsetExtension" %in% extension) { url <- sprintf("https://www.whiteboxgeo.com/GTE_%s/%s_%s.zip", sn, "GeneralToolsetExtension", sufx) @@ -726,7 +726,7 @@ wbt_install_extension <- function(extension = c( } #' Activate 'WhiteboxTools' Extensions -#' +#' #' @param email Email Address #' @param activation_key Activation Key #' @param seat Seat Number (Default `1`) @@ -744,7 +744,7 @@ wbt_activate <- function(email, activation_key, seat = 1, } #' Help description for 'WhiteboxTools' -#' +#' #' @return Returns the help description for 'WhiteboxTools' as an R character vector. #' @export #' @keywords General @@ -763,7 +763,7 @@ wbt_help <- function() { #' License information for 'WhiteboxTools' -#' +#' #' @return Returns the license information for WhiteboxTools as an R character vector. #' @export #' @keywords General @@ -804,7 +804,7 @@ wbt_version <- function(extract = FALSE) { } #' All available tools in 'WhiteboxTools' -#' +#' #' @param keywords Keywords may be used to search available tools. Default `"''"` returns all available tools. #' #' @return Return all available tools in WhiteboxTools that contain the keywords. @@ -826,7 +826,7 @@ wbt_list_tools <- function(keywords = "''") { #' The toolbox for a specific tool in WhiteboxTools -#' +#' #' Retrieve the toolbox for a specific tool. #' #' @param tool_name The name of the tool. @@ -857,7 +857,7 @@ wbt_toolbox <- function(tool_name = NULL) { #' Help description for a specific tool in 'WhiteboxTools' -#' +#' #' Retrieves the help description for a specific tool. #' #' @param tool_name The name of the tool. @@ -893,7 +893,7 @@ wbt_tool_help <- function(tool_name = NULL) { #' #' @return Returns the tool parameter descriptions for a specific tool. #' @export -#' @keywords General +#' @keywords General #' #' @examples #' \dontrun{ @@ -914,8 +914,8 @@ wbt_tool_parameters <- function(tool_name, quiet = FALSE) { #' @param tool_name Name of the tool. #' @param viewer Show source code in browser? default: `TRUE` #' @return Returns a GitHub URL to view the source code of the tool. -#' @export -#' @keywords General +#' @export +#' @keywords General #' #' @examples #' \dontrun{ @@ -943,7 +943,7 @@ wbt_view_code <- function(tool_name, viewer = FALSE) { #' @param command_only Return command that would be run with `system()`? Default: `FALSE` #' #' @return Returns the (character) output of the tool. -#' @export +#' @export #' @keywords General #' @seealso \link{wbt_list_tools} #' @examples @@ -1011,16 +1011,16 @@ wbt_internal_tool_name <- function(tool_name) { } wbt_match_tool_name <- function(tool_name, result = c('tool_name', 'function_name')) { - + wbttools <- NULL load(system.file("data/wbttools.rda", package = "whitebox")) - + result <- match.arg(result, choices = c('tool_name', 'function_name'), several.ok = TRUE) - + idx <- match(tolower(wbttools$tool_name), tolower(gsub("[ _]", "", tool_name))) - + wbttools[idx[which(!is.na(idx))], result, drop = FALSE] - + } #' Wrapper method for `system()` calls of `whitebox_tools` @@ -1039,7 +1039,7 @@ wbt_system_call <- function(argstring, command_only = FALSE, ignore.stderr = FALSE, shell_quote = TRUE, - check_version = TRUE, + check_version = TRUE, ...) { wbt_init(..., check_version = check_version) @@ -1125,13 +1125,13 @@ wbt_system_call <- function(argstring, # support for path expansion in input/output file arguments #' Prepare File Paths for WhiteboxTools Commands -#' -#' Performs path expansion with `path.expand()` and shell quotes with `shQuote()` the input paths. -#' -#' @details If an input vector contains `";"` or `","` this is considered, path expansion is performed on the substrings. If the input vector has length greater than `1`, the vector is concatenated with `","` or `";"` to create a single output string. -#' +#' +#' Performs path expansion with `path.expand()` and shell quotes with `shQuote()` the input paths. +#' +#' @details If an input vector contains `";"` or `","` this is considered, path expansion is performed on the substrings. If the input vector has length greater than `1`, the vector is concatenated with `","` or `";"` to create a single output string. +#' #' @param x character or `terra` object. Vector of file paths or strings of file paths for passing as arguments to WhiteboxTools. If the object is of class `SpatRaster`, `SpatRasterCollection`, `SpatVector` or `SpatVectorProxy` the sources are extracted with `terra::sources()` -#' +#' #' @param shell_quote logical. Shell quotes around result? Default: `TRUE` #' @param delimiter character. Either `","` (default) or `";"` allowed by WhiteboxTools. #' @param check_exists logical. Check if file(s) in x exist? Useful for input values. Default: `FALSE` @@ -1142,27 +1142,27 @@ wbt_system_call <- function(argstring, #' @keywords General #' #' @examples -#' +#' #' wbt_file_path("./abc.tif") -#' +#' #' wbt_file_path("./abc.tif;./def.tif") -#' +#' #' wbt_file_path("./abc.tif,./def.tif") -#' +#' #' wbt_file_path(c("./abc.tif", "./def.tif")) -#' +#' #' wbt_file_path("~/abc.tif", shell_quote = FALSE) -#' +#' #' wbt_file_path(c("~/abc.tif", "~/def.tif")) -#' +#' wbt_file_path <- function(x, shell_quote = TRUE, delimiter = ",", check_exists = FALSE) { if (inherits(x, c("RasterLayer", "RasterStack"))) { if (requireNamespace("terra")) { x <- terra::rast(x) } } - - if (inherits(x, c('SpatRaster','SpatRasterCollection', + + if (inherits(x, c('SpatRaster','SpatRasterCollection', 'SpatVector', 'SpatVectorProxy'))) { if (requireNamespace("terra")) { x2 <- paste0(terra::sources(x), collapse = delimiter) @@ -1172,7 +1172,7 @@ wbt_file_path <- function(x, shell_quote = TRUE, delimiter = ",", check_exists = x <- x2 } } - + delimiter <- match.arg(trimws(delimiter), c(",", ";")) x <- path.expand(strsplit( paste0(as.character(x), collapse = ","), ";|," @@ -1180,7 +1180,7 @@ wbt_file_path <- function(x, shell_quote = TRUE, delimiter = ",", check_exists = if (check_exists) { y <- !file.exists(x) if (any(y)) { - stop(sprintf("File%s not found: %s", + stop(sprintf("File%s not found: %s", ifelse(sum(y) > 1, "s",""), paste0(x[y], collapse = ", ")), call. = FALSE) @@ -1190,48 +1190,6 @@ wbt_file_path <- function(x, shell_quote = TRUE, delimiter = ",", check_exists = if (shell_quote) shQuote(x) else x } -#' Convenience method for path to sample DEM -#' -#' Get a file path to DEM.tif stored in extdata subfolder of whitebox package installation directory. If needed, download the TIFF file from GitHub. -#' -#' @param destfile Path to target location of sample data. Will be downloaded if does not exist. Defaults to file path of extdata subfolder of whitebox package installation directory. -#' @param ... additional arguments to download.file() -#' -#' @return character. -#' @export -#' @keywords General datasets -#' -#' @examples -#' -#' if (check_whitebox_binary()) { -#' wbt_slope(sample_dem_data(), output = "slope.tif") -#' } -#' unlink(c('slope.tif', 'settings.json')) -#' @importFrom utils download.file -sample_dem_data <- function(destfile = file.path(system.file('extdata', package="whitebox"), 'DEM.tif'), ...) { - if (missing(destfile)) { - fp <- system.file("extdata/DEM.tif", package = "whitebox")[1] - } else { - if (!file.exists(destfile)) { - fp <- "" - } else { - fp <- destfile - } - } - if (fp == "") { - try(download.file("https://github.com/opengeos/whiteboxR/raw/master/inst/extdata/DEM.tif", - destfile = destfile, - mode = "wb", ...)) - if (missing(destfile)) { - fp <- system.file("extdata/DEM.tif", package = "whitebox")[1] - } else { - if (file.exists(destfile)) { - fp <- destfile - } - } - } - fp -} #' Convenience method for setting RUST_BACKTRACE options for debugging #' diff --git a/R/whitebox-package.R b/R/whitebox-package.R index a909043a..350b5d94 100644 --- a/R/whitebox-package.R +++ b/R/whitebox-package.R @@ -67,6 +67,55 @@ whitebox.env <- new.env() #' @keywords datasets "wbttoolparameters" +#' Convenience method for path to sample DEM and soils data +#' +#' Get a file path to DEM.tif or STATSGO2.shp stored in extdata subfolder of whitebox package installation directory. +#' +#' @param destfile Path to target location of sample data. Will be downloaded if does not exist. Defaults to file path of extdata subfolder of whitebox package installation directory. +#' @param ... additional arguments to download.file() +#' +#' @return character. +#' @export +#' @keywords General datasets +#' @rdname extdata-gis +#' @examples +#' +#' if (check_whitebox_binary()) { +#' wbt_slope(sample_dem_data(), output = "slope.tif") +#' } +#' unlink(c('slope.tif', 'settings.json')) +#' @importFrom utils download.file +sample_dem_data <- function(destfile = file.path(system.file('extdata', package="whitebox"), 'DEM.tif'), ...) { + if (missing(destfile)) { + fp <- system.file("extdata/DEM.tif", package = "whitebox")[1] + } else { + if (!file.exists(destfile)) { + fp <- "" + } else { + fp <- destfile + } + } + if (fp == "") { + try(download.file("https://github.com/opengeos/whiteboxR/raw/master/inst/extdata/DEM.tif", + destfile = destfile, + mode = "wb", ...)) + if (missing(destfile)) { + fp <- system.file("extdata/DEM.tif", package = "whitebox")[1] + } else { + if (file.exists(destfile)) { + fp <- destfile + } + } + } + fp +} + +#' @export +#' @rdname extdata-gis +sample_soils_data <- function() { + system.file("extdata", "STATSGO2.shp", package = "whitebox")[1] +} + # The following block is used by usethis to automatically manage # roxygen namespace tags. Modify with care! ## usethis namespace: start diff --git a/data-raw/STATSGO_shapefile.R b/data-raw/STATSGO_shapefile.R new file mode 100644 index 00000000..e27bba4a --- /dev/null +++ b/data-raw/STATSGO_shapefile.R @@ -0,0 +1,18 @@ +# generate inst/extdata/STATSGO2.shp and sidecar files +# +# Digital General Soil Map of the United States or STATSGO2 is a broad-based +# inventory of soils and non-soil areas that occur in a repeatable pattern on +# the landscape and that can be cartographically shown at the scale mapped of +# 1:250,000 for most of U.S +# +# https://www.nrcs.usda.gov/resources/data-and-reports/description-of-statsgo2-database +# +dem <- terra::rast(whitebox::sample_dem_data()) +shp <- soilDB::SDA_spatialQuery( + dem, + what = "mupolygon", + db = "statsgo", + addFields = c("mapunit.musym", "mapunit.muname") +) +statsgo <- terra::crop(terra::project(shp, dem), dem) +terra::writeVector(statsgo, "inst/extdata/STATSGO2.shp") diff --git a/inst/extdata/STATSGO2.cpg b/inst/extdata/STATSGO2.cpg new file mode 100644 index 00000000..3ad133c0 --- /dev/null +++ b/inst/extdata/STATSGO2.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/inst/extdata/STATSGO2.dbf b/inst/extdata/STATSGO2.dbf new file mode 100644 index 0000000000000000000000000000000000000000..6b9cde50893c057b863f509ecb367eb8e8516fbd GIT binary patch literal 1107 zcmcJOO>fjN5QbOcL=oazamo=6j%<%V4;<)%)WeoTi{Oa78?%izv5}KN_s}21KV|ID zvRlNBT9KX1*zU%So~bHIR8ERY3KK|`9ogv-ow#P!@i#l%eS|1GM4iZGM1A5kZc_Y4R{P!svWlU>$EUPE)^pa;79Eu_ zw59+`S};JF)k;4K$Z|$&C6okZgj5<)rTV2t7Bdn&bE}IOuo=kvu505s4s%z$Yj3`` zzH7)bb}{&lyj>^PmplYN?gwQUwKW)v(oqno-GOw5W)Kw6$0@8++id-Bx$YTfKJA9< zHu*U|9LFzb^CT<nvrINW|(v-+KBf~OCl+B-AI}Y>puUyw-ax2%zHhA&}Io)6p zXP$V-;{sE_W&qAW;y;7UpjeKaK{jV3=Zrr2RPLQsO0ErL>DF;1XVYfaxzLpG@?Ysx U6+;lHS~9=}mx5WVnPo430TinRAOHXW literal 0 HcmV?d00001 diff --git a/inst/extdata/STATSGO2.prj b/inst/extdata/STATSGO2.prj new file mode 100644 index 00000000..e5d6720a --- /dev/null +++ b/inst/extdata/STATSGO2.prj @@ -0,0 +1 @@ +PROJCS["NAD_1983_UTM_Zone_18N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-75.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/inst/extdata/STATSGO2.shp b/inst/extdata/STATSGO2.shp new file mode 100644 index 0000000000000000000000000000000000000000..816a480891a7a08fe8e3f01cbf2a18199e131db1 GIT binary patch literal 21116 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 Date: Fri, 10 Oct 2025 18:48:26 -0700 Subject: [PATCH 16/29] test: wbt_source: basic behaviors for vector and raster data sources --- tests/testthat/test-wbt_source.R | 66 ++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 tests/testthat/test-wbt_source.R diff --git a/tests/testthat/test-wbt_source.R b/tests/testthat/test-wbt_source.R new file mode 100644 index 00000000..8911e78e --- /dev/null +++ b/tests/testthat/test-wbt_source.R @@ -0,0 +1,66 @@ +test_that("wbt_source (raster) works", { + + skip_if_not_installed("terra") + + f <- sample_dem_data() + src <- wbt_source(f) + + x <- attr(src, "wbt_dsn") + + expect_true(grepl(".tif$", x)) + expect_true(file.exists(x)) + + dem <- terra::rast(f) + + src <- wbt_source(f) + + x <- attr(src, "wbt_dsn") + + expect_true(grepl(".tif$", x)) + expect_true(file.exists(x)) + + tf <- tempfile(fileext = ".grd") + terra::writeRaster(dem, tf) + + src <- wbt_source(tf) + + x <- attr(src, "wbt_dsn") + + expect_true(grepl(".tif$", x)) + expect_true(file.exists(x)) + + unlink(tf) +}) + +test_that("wbt_source (vector) works", { + + skip_if_not_installed("terra") + + f <- sample_soils_data() + src <- wbt_source(f) + + x <- attr(src, "wbt_dsn") + + expect_true(grepl(".shp$", x)) + expect_true(file.exists(x)) + + dem <- terra::vect(f) + src <- wbt_source(dem) + + x <- attr(src, "wbt_dsn") + + expect_true(grepl(".shp$", x)) + expect_true(file.exists(x)) + + tf <- tempfile(fileext = ".geojson") + terra::writeVector(dem, tf) + + src <- wbt_source(tf) + + x <- attr(src, "wbt_dsn") + + expect_true(grepl(".shp$", x)) + expect_true(file.exists(x)) + + unlink(tf) +}) From c51bf216383206414c62926919760cceb4923a61 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Fri, 10 Oct 2025 18:50:22 -0700 Subject: [PATCH 17/29] fix: wbt_source: writing to shapefile or geotiff when data source type change needed --- R/wbt_source.R | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index e42bb3d0..92fffea0 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -63,11 +63,11 @@ wbt_source <- function(x, fp <- file.path(tmpdir, paste0(basename(x), "_", basename(tempfile(pattern = pattern)))) if (!inherits(x2, 'try-error') && !grepl("\\.shp$", x, ignore.case = TRUE)) { fp <- paste0(fp, ".shp") - - if (terra::writeVector(terra::query(x2), fp)) { + res <- try(terra::writeVector(terra::query(x2), fp), silent = !verbose) + if (!inherits(res, 'try-error') && file.exists(fp)) { x <- fp } else { - stop("Failed to convert `x` (", x, ") to Shapefile.") + stop("Failed to write `x` (", x, ") to Shapefile: ", fp, ".") } } else if (inherits(x2, 'try-error')) { if (!grepl("\\.tiff?$", x, ignore.case = TRUE) || length(layer) > 0) { @@ -78,10 +78,11 @@ wbt_source <- function(x, } else { x2 <- terra::rast(x) } - if (terra::writeRaster(x2, fp)) { + res <- try(terra::writeRaster(x2, fp), silent = !verbose) + if (!inherits(res, 'try-error') && file.exists(fp)) { x <- fp } else { - stop("Failed to convert `x` (", x, ") to GeoTIFF") + stop("Failed to convert `x` (", x, ") to GeoTIFF: ", fp) } } x <- terra::rast(x) From f33368b8546cef6448027bc69a864ca4d4458ad3 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Fri, 10 Oct 2025 18:52:33 -0700 Subject: [PATCH 18/29] fix: wbt_source: nzchar source --- R/wbt_source.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index 92fffea0..515c9d29 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -119,7 +119,10 @@ wbt_source <- function(x, ext <- ".tif" if (is.null(dsn)) { - dsn <- .first_source(x) + src <- .first_source(x) + if (nzchar(src)) { + dsn <- src + } } } From 9f810c06fd7726e163e0d3c84a34973b29d803c5 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 15:18:24 -0700 Subject: [PATCH 19/29] fix: wbt_source: quiet namespace check --- R/wbt_source.R | 8 ++++---- tests/testthat/test-wbt_source.R | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index 515c9d29..9c35c9b3 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -36,7 +36,7 @@ wbt_source <- function(x, } .check_pkg_ns <- function(pkg) { - if (!requireNamespace(pkg)) { + if (!requireNamespace(pkg, quietly = TRUE)) { stop("package `", pkg, "` is required to convert to `wbt()`-compatible data sources", call. = FALSE) } } @@ -67,7 +67,7 @@ wbt_source <- function(x, if (!inherits(res, 'try-error') && file.exists(fp)) { x <- fp } else { - stop("Failed to write `x` (", x, ") to Shapefile: ", fp, ".") + stop("Failed to write `x` (", x, ") to Shapefile: ", fp, "\n", res[1], call. = FALSE) } } else if (inherits(x2, 'try-error')) { if (!grepl("\\.tiff?$", x, ignore.case = TRUE) || length(layer) > 0) { @@ -78,11 +78,11 @@ wbt_source <- function(x, } else { x2 <- terra::rast(x) } - res <- try(terra::writeRaster(x2, fp), silent = !verbose) + res <- try(terra::writeRaster(x2, fp), silent = TRUE) if (!inherits(res, 'try-error') && file.exists(fp)) { x <- fp } else { - stop("Failed to convert `x` (", x, ") to GeoTIFF: ", fp) + stop("Failed to write `x` (", x, ") to GeoTIFF: ", fp, "\n", res, call. = FALSE) } } x <- terra::rast(x) diff --git a/tests/testthat/test-wbt_source.R b/tests/testthat/test-wbt_source.R index 8911e78e..691e8aee 100644 --- a/tests/testthat/test-wbt_source.R +++ b/tests/testthat/test-wbt_source.R @@ -7,7 +7,7 @@ test_that("wbt_source (raster) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl(".tif$", x)) + expect_true(grepl("\.tif$", x)) expect_true(file.exists(x)) dem <- terra::rast(f) @@ -16,7 +16,7 @@ test_that("wbt_source (raster) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl(".tif$", x)) + expect_true(grepl("\.tif$", x)) expect_true(file.exists(x)) tf <- tempfile(fileext = ".grd") @@ -26,7 +26,7 @@ test_that("wbt_source (raster) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl(".tif$", x)) + expect_true(grepl("\.tif$", x)) expect_true(file.exists(x)) unlink(tf) @@ -41,7 +41,7 @@ test_that("wbt_source (vector) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl(".shp$", x)) + expect_true(grepl("\.shp$", x)) expect_true(file.exists(x)) dem <- terra::vect(f) @@ -49,7 +49,7 @@ test_that("wbt_source (vector) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl(".shp$", x)) + expect_true(grepl("\.shp$", x)) expect_true(file.exists(x)) tf <- tempfile(fileext = ".geojson") @@ -59,7 +59,7 @@ test_that("wbt_source (vector) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl(".shp$", x)) + expect_true(grepl("\.shp$", x)) expect_true(file.exists(x)) unlink(tf) From cd54dbbb32665fa45172545318e8cb67a49ecb80 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 15:18:48 -0700 Subject: [PATCH 20/29] test: wbt_source: regex extension pattern --- tests/testthat/test-wbt_source.R | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/testthat/test-wbt_source.R b/tests/testthat/test-wbt_source.R index 691e8aee..bce52dbd 100644 --- a/tests/testthat/test-wbt_source.R +++ b/tests/testthat/test-wbt_source.R @@ -7,7 +7,7 @@ test_that("wbt_source (raster) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl("\.tif$", x)) + expect_true(grepl("\\.tif$", x)) expect_true(file.exists(x)) dem <- terra::rast(f) @@ -16,7 +16,7 @@ test_that("wbt_source (raster) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl("\.tif$", x)) + expect_true(grepl("\\.tif$", x)) expect_true(file.exists(x)) tf <- tempfile(fileext = ".grd") @@ -26,7 +26,7 @@ test_that("wbt_source (raster) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl("\.tif$", x)) + expect_true(grepl("\\.tif$", x)) expect_true(file.exists(x)) unlink(tf) @@ -41,7 +41,7 @@ test_that("wbt_source (vector) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl("\.shp$", x)) + expect_true(grepl("\\.shp$", x)) expect_true(file.exists(x)) dem <- terra::vect(f) @@ -49,7 +49,7 @@ test_that("wbt_source (vector) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl("\.shp$", x)) + expect_true(grepl("\\.shp$", x)) expect_true(file.exists(x)) tf <- tempfile(fileext = ".geojson") @@ -59,7 +59,7 @@ test_that("wbt_source (vector) works", { x <- attr(src, "wbt_dsn") - expect_true(grepl("\.shp$", x)) + expect_true(grepl("\\.shp$", x)) expect_true(file.exists(x)) unlink(tf) From 4471edbdc8fa06951cc01e4c9f9a586fa650ddeb Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 15:32:31 -0700 Subject: [PATCH 21/29] test: wbt_source: raster in memory and spatvectorproxy --- tests/testthat/test-wbt_source.R | 37 ++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/tests/testthat/test-wbt_source.R b/tests/testthat/test-wbt_source.R index bce52dbd..961c9950 100644 --- a/tests/testthat/test-wbt_source.R +++ b/tests/testthat/test-wbt_source.R @@ -3,6 +3,8 @@ test_that("wbt_source (raster) works", { skip_if_not_installed("terra") f <- sample_dem_data() + + # raster source from geotiff path src <- wbt_source(f) x <- attr(src, "wbt_dsn") @@ -12,7 +14,18 @@ test_that("wbt_source (raster) works", { dem <- terra::rast(f) - src <- wbt_source(f) + # raster source from spatraster (with source file) + src <- wbt_source(dem) + + x <- attr(src, "wbt_dsn") + + expect_true(grepl("\\.tif$", x)) + expect_true(file.exists(x)) + + dem2 <- dem*2 + + # raster source from spatraster (in memory) + src <- wbt_source(dem) x <- attr(src, "wbt_dsn") @@ -22,6 +35,7 @@ test_that("wbt_source (raster) works", { tf <- tempfile(fileext = ".grd") terra::writeRaster(dem, tf) + # raster source from non-geotiff src <- wbt_source(tf) x <- attr(src, "wbt_dsn") @@ -37,6 +51,8 @@ test_that("wbt_source (vector) works", { skip_if_not_installed("terra") f <- sample_soils_data() + + # vector source from shapefile src <- wbt_source(f) x <- attr(src, "wbt_dsn") @@ -44,8 +60,20 @@ test_that("wbt_source (vector) works", { expect_true(grepl("\\.shp$", x)) expect_true(file.exists(x)) - dem <- terra::vect(f) - src <- wbt_source(dem) + vf <- terra::vect(f) + + # vector source from spatvector (in memory) + src <- wbt_source(vf) + + x <- attr(src, "wbt_dsn") + + expect_true(grepl("\\.shp$", x)) + expect_true(file.exists(x)) + + vf2 <- terra::vect(f, proxy = TRUE) + + # vector source from spatvectorproxy + src <- wbt_source(vf2) x <- attr(src, "wbt_dsn") @@ -53,8 +81,9 @@ test_that("wbt_source (vector) works", { expect_true(file.exists(x)) tf <- tempfile(fileext = ".geojson") - terra::writeVector(dem, tf) + terra::writeVector(vf, tf) + # vector source from non-shapefile src <- wbt_source(tf) x <- attr(src, "wbt_dsn") From 939f9bfab7df17a8b66e0914ac45c7dd5e866af5 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 15:33:33 -0700 Subject: [PATCH 22/29] test: wbt_source: use gpkg as alternative non-wbt data source type --- tests/testthat/test-wbt_source.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-wbt_source.R b/tests/testthat/test-wbt_source.R index 961c9950..96538b1e 100644 --- a/tests/testthat/test-wbt_source.R +++ b/tests/testthat/test-wbt_source.R @@ -32,7 +32,7 @@ test_that("wbt_source (raster) works", { expect_true(grepl("\\.tif$", x)) expect_true(file.exists(x)) - tf <- tempfile(fileext = ".grd") + tf <- tempfile(fileext = ".gpkg") terra::writeRaster(dem, tf) # raster source from non-geotiff @@ -80,7 +80,7 @@ test_that("wbt_source (vector) works", { expect_true(grepl("\\.shp$", x)) expect_true(file.exists(x)) - tf <- tempfile(fileext = ".geojson") + tf <- tempfile(fileext = ".gpkg") terra::writeVector(vf, tf) # vector source from non-shapefile From 8f57a754fceb6c36d8982fc71a21615a47631f84 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 15:49:45 -0700 Subject: [PATCH 23/29] test: wbt_source: sources with multiple layers --- tests/testthat/test-wbt_source.R | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-wbt_source.R b/tests/testthat/test-wbt_source.R index 96538b1e..a69a41b2 100644 --- a/tests/testthat/test-wbt_source.R +++ b/tests/testthat/test-wbt_source.R @@ -33,7 +33,8 @@ test_that("wbt_source (raster) works", { expect_true(file.exists(x)) tf <- tempfile(fileext = ".gpkg") - terra::writeRaster(dem, tf) + terra::writeRaster(dem, tf, gdal=c("RASTER_TABLE=one")) + terra::writeRaster(dem*2, tf, gdal=c("RASTER_TABLE=two","APPEND_SUBDATASET=YES")) # raster source from non-geotiff src <- wbt_source(tf) @@ -43,6 +44,14 @@ test_that("wbt_source (raster) works", { expect_true(grepl("\\.tif$", x)) expect_true(file.exists(x)) + # raster source from non-geotiff + src <- wbt_source(tf, layer = "two") + + x <- attr(src, "wbt_dsn") + + expect_true(grepl("\\.tif$", x)) + expect_true(file.exists(x)) + unlink(tf) }) @@ -81,10 +90,20 @@ test_that("wbt_source (vector) works", { expect_true(file.exists(x)) tf <- tempfile(fileext = ".gpkg") - terra::writeVector(vf, tf) + + terra::writeVector(vf, tf, layer = "one") + terra::writeVector(vf, tf, layer = "two", insert = TRUE) # vector source from non-shapefile - src <- wbt_source(tf) + src <- expect_warning(wbt_source(tf)) + # warning for multiple layers but unspecified + + x <- attr(src, "wbt_dsn") + + expect_true(grepl("\\.shp$", x)) + expect_true(file.exists(x)) + + src <- wbt_source(tf, layer = "two") x <- attr(src, "wbt_dsn") From aea2d7510d99f51ba2d5538a3f809a8288660ee6 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 15:51:23 -0700 Subject: [PATCH 24/29] call.=F --- R/wbt_source.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index 9c35c9b3..48df531d 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -94,7 +94,7 @@ wbt_source <- function(x, } if (is.character(x) && !file.exists(x)) { - stop("File (", x, ") does not exist") + stop("File (", x, ") does not exist", call. = FALSE) } if (!inherits(x, c("SpatRaster", "SpatVectorProxy"))) { @@ -105,7 +105,7 @@ wbt_source <- function(x, attr(x, 'wbt_layer') <- layer return(x) } else { - stop("File (", x, ") does not exist") + stop("File (", x, ") does not exist", call. = FALSE) } } From 14dfd997c354bfeb97a46b5353a5b8ac688d822b Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 15:58:33 -0700 Subject: [PATCH 25/29] fix: wbt_source: no need to specify `layer` for output `dsn` --- R/wbt_source.R | 2 -- 1 file changed, 2 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index 48df531d..a19c9b8e 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -155,7 +155,6 @@ wbt_source <- function(x, if (inherits(x, 'SpatVector')) { terra::writeVector(x, filename = dsn, - layer = layer, overwrite = force, ...) } else if (inherits(x, 'SpatRaster')) { @@ -178,7 +177,6 @@ wbt_source <- function(x, sf::st_write( x, dsn = dsn, - layer = layer, quiet = !verbose, delete_dsn = force, ... From e90968b596192a82e831e411358515d0841f7362 Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 16:21:01 -0700 Subject: [PATCH 26/29] test: wbt_source: suppress upstream warnings --- tests/testthat/test-wbt_source.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-wbt_source.R b/tests/testthat/test-wbt_source.R index a69a41b2..5ec153d4 100644 --- a/tests/testthat/test-wbt_source.R +++ b/tests/testthat/test-wbt_source.R @@ -95,8 +95,8 @@ test_that("wbt_source (vector) works", { terra::writeVector(vf, tf, layer = "two", insert = TRUE) # vector source from non-shapefile - src <- expect_warning(wbt_source(tf)) - # warning for multiple layers but unspecified + src <- suppressWarnings(wbt_source(tf)) + # terra warning for multiple layers but layer unspecified x <- attr(src, "wbt_dsn") From 629da6436c9f6562db065bce1e8409168c65705b Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 16:21:35 -0700 Subject: [PATCH 27/29] test: wbt_source: use in memory spatraster --- tests/testthat/test-wbt_source.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-wbt_source.R b/tests/testthat/test-wbt_source.R index 5ec153d4..82d9df5a 100644 --- a/tests/testthat/test-wbt_source.R +++ b/tests/testthat/test-wbt_source.R @@ -25,7 +25,7 @@ test_that("wbt_source (raster) works", { dem2 <- dem*2 # raster source from spatraster (in memory) - src <- wbt_source(dem) + src <- wbt_source(dem2) x <- attr(src, "wbt_dsn") @@ -33,8 +33,8 @@ test_that("wbt_source (raster) works", { expect_true(file.exists(x)) tf <- tempfile(fileext = ".gpkg") - terra::writeRaster(dem, tf, gdal=c("RASTER_TABLE=one")) - terra::writeRaster(dem*2, tf, gdal=c("RASTER_TABLE=two","APPEND_SUBDATASET=YES")) + terra::writeRaster(dem, tf, gdal = c("RASTER_TABLE=one")) + terra::writeRaster(dem2, tf, gdal = c("RASTER_TABLE=two", "APPEND_SUBDATASET=YES")) # raster source from non-geotiff src <- wbt_source(tf) From 7578cca6c6010d6ff15560db07843860cda4d2ba Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 16:45:49 -0700 Subject: [PATCH 28/29] fix: wbt_source: short circuit for common single-layer geotiff case --- R/wbt_source.R | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/R/wbt_source.R b/R/wbt_source.R index a19c9b8e..5d8c6e56 100644 --- a/R/wbt_source.R +++ b/R/wbt_source.R @@ -70,7 +70,17 @@ wbt_source <- function(x, stop("Failed to write `x` (", x, ") to Shapefile: ", fp, "\n", res[1], call. = FALSE) } } else if (inherits(x2, 'try-error')) { - if (!grepl("\\.tiff?$", x, ignore.case = TRUE) || length(layer) > 0) { + is_geotiff <- grepl("\\.tiff?$", x, ignore.case = TRUE) + + # check if we need to write a new file + # - not a geotiff OR + # - a layer is specified that is not the first layer + write_new_file <- !is_geotiff || + (length(layer) > 0 && + layer[1] != 1 && + layer[1] != names(terra::rast(x))[1]) + + if (write_new_file) { # try reading a raster file and writing to geotiff fp <- paste0(fp, ".tif") if (length(layer) > 0) { @@ -82,7 +92,15 @@ wbt_source <- function(x, if (!inherits(res, 'try-error') && file.exists(fp)) { x <- fp } else { - stop("Failed to write `x` (", x, ") to GeoTIFF: ", fp, "\n", res, call. = FALSE) + stop( + "Failed to write `x` (", + x, + ") to GeoTIFF: ", + fp, + "\n", + res, + call. = FALSE + ) } } x <- terra::rast(x) From 58365d965222d5d96e13eeedf87cc80e4d0fcd7c Mon Sep 17 00:00:00 2001 From: Andrew Gene Brown Date: Sat, 11 Oct 2025 17:26:23 -0700 Subject: [PATCH 29/29] Update NEWS.md --- NEWS.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 81b57587..bc83e1a1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,16 +1,16 @@ # whitebox 2.4.2 * `wbt_source()`: now accepts `tmpdir` argument which defaults to `tempdir()` (not `getwd()` or `wbt_wd()`) that is used for storing the intermediate shapefiles needed for WhiteboxTools - + * Also, the pattern for temporary file names is now customizable via `pattern` argument - + * Bug fixes for `wbt_source()`: - * No longer writes temporary intermediate shapefiles to the working directory when passed a non-shapefile vector data source. + * No longer writes temporary intermediate files to the working directory when passed a non-shapefile vector or non-GeoTIFF raster data source. * The temporary directory is used by default, unless new `tmpdir` argument is specified. This could be a breaking change if you were relying on the temporary files to be present in the WhiteboxTools working directory. Specify `tmpdir` in call to `wbt_source()` to make old behavior explicit. - * Properly uses `layer` argument for data sources (e.g. GPKG) that may contain multiple vector layers of interest (thanks to @mps9506 for reporting; #132) + * Properly uses `layer` argument for data sources (e.g. GPKG) that may contain multiple vector layers or raster bands of interest (thanks to @mps9506 for reporting; #132) # whitebox 2.4.1