Skip to content

Commit

Permalink
Migrated R-spatial dependencies
Browse files Browse the repository at this point in the history
* Replaced `raster`, `rgeos`, and `sp` packages in Imports with `terra` and `sf` because of imminent package retirements
* Removed `maptools` from Suggests (replaced with new internal function `as.im.SpatRaster()`)
* Thank you, [Roger Bivand](https://github.com/rsbivand), for the notice. Relates to [ndi Issue #3](#3)
* Note: `raster` is a dependency of `RStoolbox` (at present) which is used in the vignette
* Updated test, examples, vignette, and documentation throughout
* Added GitHub R-CMD-check
  • Loading branch information
idblr committed Dec 16, 2022
1 parent f305c1a commit 8bc4025
Show file tree
Hide file tree
Showing 34 changed files with 585 additions and 492 deletions.
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
^CRAN-RELEASE$
^CRAN-SUBMISSION$
^man/figures
^\.github$
1 change: 1 addition & 0 deletions .github/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.html
49 changes: 49 additions & 0 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

name: R-CMD-check

jobs:
R-CMD-check:
runs-on: ${{ matrix.config.os }}

name: ${{ matrix.config.os }} (${{ matrix.config.r }})

strategy:
fail-fast: false
matrix:
config:
- {os: macos-latest, r: 'release'}
- {os: windows-latest, r: 'release'}
- {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
- {os: ubuntu-latest, r: 'release'}
- {os: ubuntu-latest, r: 'oldrel-1'}

env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes

steps:
- uses: actions/checkout@v3

- uses: r-lib/actions/setup-pandoc@v2

- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
http-user-agent: ${{ matrix.config.http-user-agent }}
use-public-rspm: true

- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
needs: check

- uses: r-lib/actions/check-r-package@v2
with:
upload-snapshots: true
14 changes: 6 additions & 8 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Package: envi
Type: Package
Title: Environmental Interpolation using Spatial Kernel Density Estimation
Version: 0.1.15
Date: 2022-08-30
Version: 0.1.16.9000
Date: 2022-12-16
Authors@R:
c(person(given = "Ian D.",
family = "Buller",
Expand All @@ -28,7 +28,7 @@ Description: Estimates an ecological niche using occurrence data, covariates, an
License: Apache License (>= 2.0)
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.1
RoxygenNote: 7.2.2
Depends:
R (>= 3.5.0)
Imports:
Expand All @@ -43,15 +43,13 @@ Imports:
grDevices,
iterators,
pls,
raster,
rgeos,
ROCR,
sp,
sf,
sparr,
spatstat.geom,
stats
stats,
terra
Suggests:
maptools,
R.rsp,
RStoolbox,
spatstat.data,
Expand Down
30 changes: 13 additions & 17 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,10 @@ importFrom(graphics,plot.new)
importFrom(graphics,title)
importFrom(iterators,icount)
importFrom(pls,cvsegments)
importFrom(raster,crs)
importFrom(raster,cut)
importFrom(raster,extract)
importFrom(raster,image)
importFrom(raster,projectRaster)
importFrom(raster,raster)
importFrom(raster,rasterToPoints)
importFrom(raster,reclassify)
importFrom(raster,values)
importFrom(rgeos,gBuffer)
importFrom(sp,CRS)
importFrom(sp,Polygon)
importFrom(sp,Polygons)
importFrom(sp,SpatialPolygons)
importFrom(sp,bbox)
importFrom(sp,coordinates)
importFrom(sp,gridded)
importFrom(sf,st_bbox)
importFrom(sf,st_buffer)
importFrom(sf,st_coordinates)
importFrom(sf,st_polygon)
importFrom(sparr,risk)
importFrom(spatstat.geom,as.solist)
importFrom(spatstat.geom,im.apply)
Expand All @@ -65,3 +52,12 @@ importFrom(spatstat.geom,superimpose)
importFrom(stats,median)
importFrom(stats,na.omit)
importFrom(stats,sd)
importFrom(terra,classify)
importFrom(terra,crds)
importFrom(terra,crs)
importFrom(terra,extract)
importFrom(terra,image)
importFrom(terra,project)
importFrom(terra,rast)
importFrom(terra,res)
importFrom(terra,values)
9 changes: 9 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# envi (development version)

# envi v0.1.16.9000
* Migrated R-spatial dependencies
* Replaced `raster`, `rgeos`, and `sp` packages in Imports with `terra` and `sf` because of imminent package retirements
* Removed `maptools` from Suggests (replaced with new internal function `as.im.SpatRaster()`)
* Thank you, [Roger Bivand](https://github.com/rsbivand), for the notice. Relates to [ndi Issue #3](https://github.com/lance-waller-lab/envi/issues/3)
* Note: `raster` is a dependency of `RStoolbox` (at present) which is used in the vignette
* Updated test, examples, vignette, and documentation throughout
* Added GitHub R-CMD-check

# envi v0.1.15
* Uwe Ligges suggested (2022-08-26) that some parallel cluster is not cleanly closed in the tests
* Added `future::plan(future::multisession)` in tests to remove the files in temp directory
Expand Down
18 changes: 9 additions & 9 deletions R/div_plot.R
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#' Prepare an 'im' or 'raster' object for plotting with diverging color palette
#' Prepare an 'im' or 'SpatRaster' object for plotting with diverging color palette
#'
#' Internal function to convert 'im' object or 'RasterLayer' object to values readable by \code{\link[fields]{image.plot}} function within the \code{\link{plot_obs}}, \code{\link{plot_predict}}, and \code{\link{plot_perturb}} functions.
#' Internal function to convert 'im' object or 'SpatRaster' object to values readable by \code{\link[fields]{image.plot}} function within the \code{\link{plot_obs}}, \code{\link{plot_predict}}, and \code{\link{plot_perturb}} functions.
#'
#' @param input An object of class 'im' or 'RasterLayer' from the \code{\link{lrren}} function.
#' @param input An object of class 'im' or 'SpatRaster' from the \code{\link{lrren}} function.
#' @param plot_cols Character string of length three (3) specifying the colors for plotting: 1) presence, 2) neither, and 3) absence from the \code{\link{plot_obs}} function.
#' @param midpoint Numeric. The value to center the diverging color palette.
#' @param thresh_up Numeric. The upper value to concatenate the color key. The default (NULL) uses the maximum value from \code{input}.
Expand All @@ -20,7 +20,7 @@
#' }
#'
#' @importFrom grDevices colorRampPalette
#' @importFrom raster raster
#' @importFrom terra rast
#'
#' @keywords internal

Expand All @@ -33,15 +33,15 @@ div_plot <- function(input,

# Inputs
if (inherits(input, "im")) {
out <- raster::raster(input)
out <- terra::rast(input)
} else { out <- input }

if (length(cols) != 3) {
stop("The 'cols' argument must be a vector of length 3")
}

min_raw_value <- min(out[is.finite(out)], na.rm = TRUE) # minimum absolute value of raster
max_raw_value <- max(out[is.finite(out)], na.rm = TRUE) # maximum absolute value of raster
min_raw_value <- min(out[is.finite(out)], na.rm = TRUE) # minimum absolute value of SpatRaster
max_raw_value <- max(out[is.finite(out)], na.rm = TRUE) # maximum absolute value of SpatRaster

# Restrict spurious log relative risk values
if (!is.null(thresh_low)) {
Expand All @@ -60,8 +60,8 @@ div_plot <- function(input,
# Identify ramp above and below midpoint
lowerhalf <- length(out[out < midpoint & !is.na(out)]) # values below 0
upperhalf <- length(out[out > midpoint & !is.na(out)]) # values above 0
min_absolute_value <- min(out[is.finite(out)], na.rm = TRUE) # minimum absolute value of raster
max_absolute_value <- max(out[is.finite(out)], na.rm = TRUE) # maximum absolute value of raster
min_absolute_value <- min(out[is.finite(out)], na.rm = TRUE) # minimum absolute value of SpatRaster
max_absolute_value <- max(out[is.finite(out)], na.rm = TRUE) # maximum absolute value of SpatRaster

# Color ramp parameters
## Colors
Expand Down
74 changes: 36 additions & 38 deletions R/lrren.R
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,11 @@
#' @importFrom grDevices chull
#' @importFrom iterators icount
#' @importFrom pls cvsegments
#' @importFrom raster extract raster
#' @importFrom rgeos gBuffer
#' @importFrom sp bbox coordinates Polygon Polygons SpatialPolygons
#' @importFrom sf st_bbox st_buffer st_coordinates st_polygon
#' @importFrom sparr risk
#' @importFrom spatstat.geom owin ppp
#' @importFrom stats na.omit
#' @importFrom terra extract rast values
#' @export
#'
#' @examples
Expand All @@ -89,8 +88,8 @@
#' grad <- spatstat.data::bei.extra[[2]]
#' elev$v <- scale(elev)
#' grad$v <- scale(grad)
#' elev_raster <- raster::raster(elev)
#' grad_raster <- raster::raster(grad)
#' elev_raster <- terra::rast(elev)
#' grad_raster <- terra::rast(grad)
#'
#' # Presence data
#' presence <- spatstat.data::bei
Expand All @@ -115,8 +114,10 @@
#' obs_locs <- obs_locs[ , c(6, 2, 3, 1, 4, 5)]
#'
#' # Prediction Data
#' predict_locs <- data.frame(raster::rasterToPoints(elev_raster))
#' predict_locs$layer2 <- raster::extract(grad_raster, predict_locs[, 1:2])
#' predict_xy <- terra::crds(elev_raster)
#' predict_locs <- as.data.frame(predict_xy)
#' predict_locs$elev <- terra::extract(elev_raster, predict_xy)[ , 1]
#' predict_locs$grad <- terra::extract(grad_raster, predict_xy)[ , 1]
#'
#' # Run lrren
#' test_lrren <- lrren(obs_locs = obs_locs,
Expand All @@ -138,7 +139,7 @@ lrren <- function(obs_locs,
n_core = 2,
poly_buffer = NULL,
obs_window = NULL,
verbose = FALSE,
verbose = FALSE,
...) {

if (verbose == TRUE) { message("Estimating relative risk surfaces\n") }
Expand All @@ -148,35 +149,32 @@ lrren <- function(obs_locs,
# Compute spatial windows
## Calculate inner boundary polygon (extent of presence and absence locations in environmental space)
inner_chull <- concaveman::concaveman(as.matrix(obs_locs[ , 5:6]))
inner_chull_pts <- sp::coordinates(inner_chull)
inner_chull_pts <- rbind(inner_chull_pts, inner_chull_pts[1, ])
inner_chull_poly <- sp::SpatialPolygons(list(sp::Polygons(list(sp::Polygon(inner_chull_pts)), 1)))

inner_chull_poly <- sf::st_polygon(list(inner_chull))

if (is.null(poly_buffer)) {
poly_buffer <- abs(min(diff(sp::bbox(inner_chull_poly)[1, ]), diff(sp::bbox(inner_chull_poly)[2, ])) / 100)
poly_buffer <- abs(min(diff(sf::st_bbox(inner_chull_poly)[c(1,3)]), diff(sf::st_bbox(inner_chull_poly)[c(2,4)])) / 100)
}

# add small buffer around polygon to include boundary points
inner_chull_poly_buffer <- rgeos::gBuffer(inner_chull_poly, width = poly_buffer, byid = TRUE)
inner_poly <- inner_chull_poly_buffer@polygons[[1]]@Polygons[[1]]@coords
inner_chull_poly_buffer <- sf::st_buffer(inner_chull_poly, dist = poly_buffer, byid = TRUE)
inner_poly <- sf::st_polygon(list(as.matrix(inner_chull_poly_buffer)))

if (is.null(predict_locs)) {
outer_chull_poly <- inner_chull_poly_buffer
outer_poly <- inner_poly
} else {
## Calculate outer boundary polygon (full extent of geographical extent in environmental space)
if (nrow(predict_locs) > 5000000) { # convex hull
outer_chull <- grDevices::chull(x = stats::na.omit(predict_locs)[ , 3], y = stats::na.omit(predict_locs)[ , 4])
outer_chull_pts <- predict_locs[c(outer_chull, outer_chull[1]), 3:4]
predict_locs_woNAs <- stats::na.omit(predict_locs)
outer_chull <- grDevices::chull(x = predict_locs_woNAs[ , 3], y = predict_locs_woNAs[ , 4])
outer_chull_pts <- predict_locs_woNAs[c(outer_chull, outer_chull[1]), 3:4]
} else { # concave hull
outer_chull <- concaveman::concaveman(as.matrix(stats::na.omit(predict_locs)[ , 3:4]))
outer_chull_pts <- sp::coordinates(outer_chull)
outer_chull_pts <- concaveman::concaveman(as.matrix(stats::na.omit(predict_locs[ , 3:4])))
}
outer_chull_pts <- rbind(outer_chull_pts, outer_chull_pts[1, ])
outer_chull_poly <- sp::SpatialPolygons(list(sp::Polygons(list(sp::Polygon(outer_chull_pts)), 1)))
#add small buffer around polygon to include boundary points
outer_chull_poly_buffer <- rgeos::gBuffer(outer_chull_poly, width = poly_buffer, byid = TRUE)
outer_poly <- outer_chull_poly_buffer@polygons[[1]]@Polygons[[1]]@coords #extract coordinates of new polygon
outer_chull_poly <- sf::st_polygon(list(as.matrix(outer_chull_pts)))
# add small buffer around polygon to include boundary points
outer_chull_poly_buffer <- sf::st_buffer(outer_chull_poly, dist = poly_buffer, byid = TRUE)
outer_poly <- sf::st_polygon(list(as.matrix(outer_chull_poly_buffer)))
}

if (conserve == FALSE & is.null(predict_locs)) {
Expand All @@ -185,8 +183,8 @@ lrren <- function(obs_locs,
if (conserve == TRUE) { window_poly <- inner_poly } else { window_poly <- outer_poly }

if (is.null(obs_window)) {
wind <- spatstat.geom::owin(poly = list(x = rev(window_poly[ , 1]),
y = rev(window_poly[ , 2])))
wind <- spatstat.geom::owin(poly = list(x = rev(sf::st_coordinates(window_poly)[ , 1]),
y = rev(sf::st_coordinates(window_poly)[ , 2])))
} else { wind <- obs_window }

# Input Preparation
Expand All @@ -207,7 +205,7 @@ lrren <- function(obs_locs,
obs <- sparr::risk(f = ppp_presence,
g = ppp_absence,
tolerate = TRUE,
verbose = verbose,
verbose = verbose,
...)
bandw <- obs$f$h0

Expand All @@ -228,17 +226,17 @@ lrren <- function(obs_locs,
# Project relative risk surface into geographic space
if (verbose == TRUE) { message("Predicting area of interest") }

# Convert to semi-continuous raster
rr_raster <- raster::raster(obs$rr)
# Convert to semi-continuous SpatRaster
rr_raster <- terra::rast(obs$rr)

# Convert to categorical raster
pval_raster <- raster::raster(obs$P)
# Convert to categorical SpatRaster
pval_raster <- terra::rast(obs$P)

# Prediction locations
extract_points <- cbind(predict_locs[ , 3], predict_locs[ , 4])
extract_predict <- data.frame("predict_locs" = predict_locs,
"rr" = raster::extract(rr_raster, extract_points),
"pval" = raster::extract(pval_raster, extract_points))
"rr" = terra::extract(rr_raster, extract_points)[ , 1],
"pval" = terra::extract(pval_raster, extract_points)[ , 1])

output <- list("obs" = obs,
"presence" = ppp_presence,
Expand Down Expand Up @@ -326,19 +324,19 @@ lrren <- function(obs_locs,
rand_lrr <- sparr::risk(f = ppp_presence_training,
g = ppp_absence_training,
tolerate = TRUE,
verbose = FALSE,
verbose = FALSE,
...)

##### Convert to semi-continuous raster
rr_raster <- raster::raster(rand_lrr$rr)
rr_raster[is.na(rr_raster[])] <- 0 # if NA, assigned null value (log(rr) = 0)
##### Convert to semi-continuous SpatRaster
rr_raster <- terra::rast(rand_lrr$rr)
rr_raster[is.na(terra::values(rr_raster))] <- 0 # if NA, assigned null value (log(rr) = 0)

##### Predict testing dataset
extract_testing <- testing[ , 5:6]

##### Output for each k-fold
###### Record category (semi-continuous) of testing data
cv_predictions_rr <- raster::extract(rr_raster, extract_testing)
cv_predictions_rr <- terra::extract(rr_raster, extract_testing)[ , 2]
cv_labels <- testing[ , 4] # Record labels (marks) of testing data

par_results <- list("cv_predictions_rr" = cv_predictions_rr,
Expand Down
7 changes: 3 additions & 4 deletions R/package.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#' @aliases envi-package envi
#' @docType package
#'
#' @section Dependencies: The 'envi' package relies heavily upon \code{\link{sparr}}, \code{\link{spatstat.geom}}, and \code{\link{raster}}. For a single species (presence/absence data), the spatial relative risk function uses the \code{\link[sparr]{risk}} function. Cross-validation is can be performed in parallel using the \code{\link{future}}, \code{\link{doFuture}}, \code{\link{doRNG}}, and \code{\link{foreach}} packages. Spatial perturbation is performed using the \code{\link[spatstat.geom]{rjitter}} function. Basic visualizations rely on the \code{\link[spatstat.geom]{plot.ppp}} and \code{\link[fields]{image.plot}} functions.
#' @section Dependencies: The 'envi' package relies heavily upon \code{\link{sparr}}, \code{\link{spatstat.geom}}, \code{\link{sf}}, and \code{\link{terra}}. For a single species (presence/absence data), the spatial relative risk function uses the \code{\link[sparr]{risk}} function. Cross-validation is can be performed in parallel using the \code{\link{future}}, \code{\link{doFuture}}, \code{\link{doRNG}}, and \code{\link{foreach}} packages. Spatial perturbation is performed using the \code{\link[spatstat.geom]{rjitter}} function. Basic visualizations rely on the \code{\link[spatstat.geom]{plot.ppp}} and \code{\link[fields]{image.plot}} functions.
#'
#' @author Ian D. Buller\cr \emph{Environmental Health Sciences, Emory University, Atlanta, Georgia, USA.}\cr
#'
Expand All @@ -50,10 +50,9 @@ NULL
#' @importFrom grDevices chull colorRampPalette
#' @importFrom iterators icount
#' @importFrom pls cvsegments
#' @importFrom raster crs cut extract image projectRaster raster rasterToPoints reclassify values
#' @importFrom rgeos gBuffer
#' @importFrom ROCR performance prediction
#' @importFrom sp bbox coordinates CRS gridded Polygon Polygons SpatialPolygons
#' @importFrom sf st_bbox st_buffer st_coordinates st_polygon
#' @importFrom spatstat.geom as.solist im.apply marks owin pixellate plot.ppp ppp rjitter setmarks superimpose
#' @importFrom stats median na.omit sd
#' @importFrom terra crds crs image project rast res classify values
NULL
Loading

0 comments on commit 8bc4025

Please sign in to comment.