Rapid subsetting of a rast brick - r

I have a list of polygons that I want to use to subset a terra::rast brick with. To do this, I use terra::crop together with lapply, as show below, and it's fairly slow. Is there a vectorised way of subsetting with polygons rather than lapplying through the polygons?
Example
First, I load the libraries and create a rast object.
# Load library
library(terra)
library(geohashTools)
# Create raster
r <- rast(matrix(runif(360 * 2 * 180 *2), ncol = 360 * 2))
# Set extent
ext(r) <- c(-180, 180, -90, 90)
# Examine raster
r
## class : SpatRaster
## dimensions : 360, 720, 1 (nrow, ncol, nlyr)
## resolution : 0.5, 0.5 (x, y)
## extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
## coord. ref. :
## source : memory
## name : lyr.1
## min value : 7.853378e-07
## max value : 0.9999981
Next, I create a brick of these objects.
# Create a brick
b <- c(r, r, r, r, r)
## class : SpatRaster
## dimensions : 360, 720, 5 (nrow, ncol, nlyr)
## resolution : 0.5, 0.5 (x, y)
## extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
## coord. ref. :
## sources : memory
## memory
## memory
## ... and 2 more source(s)
## names : lyr.1, lyr.1, lyr.1, lyr.1, lyr.1
## min values : 7.853378e-07, 7.853378e-07, 7.853378e-07, 7.853378e-07, 7.853378e-07
## max values : 0.9999981, 0.9999981, 0.9999981, 0.9999981, 0.9999981
Here, I'm just creating a load of spatial polygons.
# All possible coordinates
coords <- expand.grid(-180:180, -90:89)
# Get all unique geohashes for raster
geohashes <- unique(gh_encode(coords$Var2, coords$Var1, precision = 4L))
# Convert to spatial polygons
sp <- geohashTools::gh_to_sp(geohashes)
Finally, I go through each polygon and use it to crop my brick.
# Crop raster using geohash polygon
b_cropped <- lapply(seq_along(sp), function(x) terra::crop(b, sp[x]))
Q: Is there a faster way to do this last step?

Related

R terra rasterization create vertical white lines

I have a raster raster_coarse at 0.25 resolution
class : SpatRaster
dimensions : 26, 31, 1 (nrow, ncol, nlyr)
resolution : 0.25, 0.25 (x, y)
extent : -87.75, -80, 24.5, 31 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : memory
name : layer1
min value : 0.08839285
max value : 0.11517857
I have another raster raster_fine at finer resolution
class : SpatRaster
dimensions : 2377, 2758, 1 (nrow, ncol, nlyr)
resolution : 0.002777778, 0.002777778 (x, y)
extent : -87.6361, -79.97499, 24.39723, 31.00001 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : memory
name : finer_res
min value : 0
max value : 1
Here's what I am trying to do. I want to populate every pixel in raster_fine with the values from raster_coarse. The way I approached this is:
# check the resolution difference
res_drop <- res(raster_coarse)[1]/res(raster_fine)[1] # 89.99999.
# disaggregate the raster_coarse
raster_coarse <- terra::disagg(raster_coarse, fact = res_drop)
# convert to points
raster_coarse_df <- as.data.frame(raster_coarse, xy = T, na.rm = TRUE)
raster_coarse_pts <- terra::vect(raster_coarse_df, geom = c("x", "y"), crs(raster_fine))
# create a blank canvas
canvas <- terra::rast(xmin = ext(raster_fine)[1],
xmax = ext(raster_fine)[2],
ymin = ext(raster_fine)[3],
ymax = ext(raster_fine)[4],
resolution = res(raster_fine),
crs = crs(raster_fine))
# populate the blank canvas with raster_coarse_pts
raster_coarse <- terra::rasterize(x = raster_coarse_pts , y = canvas, field = "layer1", fun = max, touches = T, background = NA)
raster_coarse
class : SpatRaster
dimensions : 2377, 2758, 1 (nrow, ncol, nlyr)
resolution : 0.002777778, 0.002777778 (x, y)
extent : -87.6361, -79.97499, 24.39723, 31.00001 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : memory
name : lyr.1
min value : 0.08839285
max value : 0.11517857
plot(raster_coarse)
I am not able to understand why the vertical white lines are coming from?
Example data
library(terra)
r <- rast(nrow=26, ncol=31, ext=c(-87.75, -80, 24.5, 31))
f <- geodata::gadm("USA", level=1, path=".")
f <- f[f$NAME_1 == "Florida", ]
values(r) <- runif(ncell(r))
r <- mask(r, f)
fine <- rast(nrow=2377, ncol=2758, ext=c(-87.6361, -79.97499, 24.39723, 31.00001))
The solution is to use resample
rr <- resample(r, x, "near")
Instead of the nearest neighbor you could use, for example, bilinear interpolation:
rr <- resample(r, x)
The white lines occur because with your method there will be cells that are not covered. To better understand that you could crop out a small area and plot the points on top of the raster.

Get a unique value range of a rasterlayer

My rasterlayer has a range from 0 to 1. I just want the Pixel values from 0.2 to 0.1
I tried this Code:
R<- myraster
R[(R<=0.1) & (R>=0.2)] <- NA
This is my idea for a range of value.
For a single value I don't know.
If I use this code I get online NA or the range from.0 to 1 does not change.
Is my Code wrong or is there another option?
I also used this one only to get the value 0.1
R<- myraster
R[(R<=0.1) & (R>=0.1)] <- NA
You can do it in two steps. For instance,
library(raster)
# Simulate raster
R <- raster(ncol=10, nrow=10)
values(R) <- runif(ncell(R))
#Subset the raster in two steps
R[R >= 0.2] <- NA
R[R <= 0.1] <- NA
R
Here's the output...
> R <- raster(ncol=10, nrow=10)
> values(R) <- runif(ncell(R))
> R
class : RasterLayer
dimensions : 10, 10, 100 (nrow, ncol, ncell)
resolution : 36, 18 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : layer
values : 0.01307758, 0.9926841 (min, max)
> R[R>=0.2]<-NA
> R[R<=0.1 ]<-NA
> R
class : RasterLayer
dimensions : 10, 10, 100 (nrow, ncol, ncell)
resolution : 36, 18 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : layer
values : 0.1008731, 0.1912601 (min, max)

r raster changing extent removes data

I'm attempting to figure out why I'm getting error messages with some simple raster algebra after changing the extent. To demonstrate this I thought I'd create a toy example following some code on another stack overflow question.
library(raster)
## Create a matrix with random data
xy <- matrix(rnorm(400),20,20)
# generate two extents to apply
globeExtent <- extent(c(-180, 180, -90, 90))
smallerExtent <- extent(c(-180, 180, -59.5, 83.5))
# Turn the matrix into a raster
rast.smallextent <- raster(xy)
extent(rast.smallextent) <- smallerExtent
rast.globeExtent <- setExtent(rast.smallextent, ext = globeExtent, keepres = TRUE)
mathtest <- rast.globeExtent - rast.smallextent
The mathtest code line fails because rast.globeExtent has no values so I can't actually use this to test for the errors I was seeing elsewhere. How do I expand the extent of this raster without losing all its data?
If I interpret correctly the question, what you need to do is not to change the extent of rast.smallextent, but to expand the raster, using function expand(). Something like this:
library(raster)
#> Loading required package: sp
library(tmap)
## Create a matrix with random data
xy <- matrix(rnorm(400),20,20)
# generate two extents to apply
globeExtent <- extent(c(-180, 180, -90, 90))
smallerExtent <- extent(c(-180, 180, -20, 20))
# Turn the matrix into a raster
rast.smallextent <- raster(xy)
extent(rast.smallextent) <- smallerExtent
tmap::tm_shape(rast.smallextent) + tmap::tm_raster() + tmap::tm_grid()
# extend the raster over a wider area, while keeping the values
#
rast.globeExtent <- extend(rast.smallextent, globeExtent)
# Now rast.globeExtent is "expanded", but values are still there:
rast.globeExtent
#> class : RasterLayer
#> dimensions : 90, 20, 1800 (nrow, ncol, ncell)
#> resolution : 18, 2 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> crs : NA
#> source : memory
#> names : layer
#> values : -3.606916, 2.795636 (min, max)
tmap::tm_shape(rast.globeExtent) + tmap::tm_raster() + tmap::tm_grid()
# Math now works on the intersection, although results are "cropped" on
# the intersecting area
rast.globeExtent <- rast.globeExtent + 1 #add 1 to check math is correct
mathtest <- rast.globeExtent - rast.smallextent
#> Warning in rast.globeExtent - rast.smallextent: Raster objects have different
#> extents. Result for their intersection is returned
mathtest
#> class : RasterLayer
#> dimensions : 20, 20, 400 (nrow, ncol, ncell)
#> resolution : 18, 2 (x, y)
#> extent : -180, 180, -20, 20 (xmin, xmax, ymin, ymax)
#> crs : NA
#> source : memory
#> names : layer
#> values : 1, 1 (min, max)
tmap::tm_shape(mathtest) + tmap::tm_raster() + tmap::tm_grid()
HTH!
Created on 2019-12-13 by the reprex package (v0.3.0)

Apply boot::inv.logit() to a raster in R

I have a Formal Class Raster and I am trying to apply the boot::inv.logit() function to its raster cells, for example:
r1 <- raster(nrows=25, ncols=25, vals=rtnorm(n = 625, .1, .9))
r2 <- boot::inv.logit(r1)
However, when I try that, it retruns an error:
> Error in plogis(x) : Non-numeric argument to mathematical function
If I turn the raster into a matrix, and then back to raster, it gets the job done, but I loose all the other info associated with the "Formal Class Raster" I had at the beginning, which is not ideal:
r2 <- boot::inv.logit(as.matrix(r1))
r2 <- as.raster(r2)
Is there an easy way to either recover the Formal Class Raster info I had before or apply the inv.logit() to the raster without the as.matrix() transformation? Thank you in advance.
If you want to apply the function to the raster, use the calc method from raster:
r2 <- calc(r1,boot::inv.logit)
> r2
# class : RasterLayer
# dimensions : 25, 25, 625 (nrow, ncol, ncell)
# resolution : 14.4, 7.2 (x, y)
# extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
# data source : in memory
# names : layer
# values : 0.07434905, 0.9498965 (min, max)
Alternatively, you can make an empty copy of r1, and just fill in the values coming out of inv.logit:
r2 <- raster(r1)
r2[] <- boot::inv.logit(as.matrix(r1))

Modifying and Masking Environmental Layers within specific asia area in R

I am trying to prepare the environmental layers (constrained in specific Asia area) for use in Maxent model. However, I ran into some error messages in the last line:
library(sp)
library(maptools)
library(rworldmap)
library(dismo)
# A specified range of Asia area that suitable for special species
tsta <- read.csv('CM10_Kop_Shp_V1.2/Asiaclip/Asiaclipt.csv',as.is=TRUE)[https://drive.google.com/file/d/0B4vIx9MCfJgfbHpINTlyUGZVbXc/view?usp=sharing][1]
tsta <- tsta[,seq(1,4)]
coordinates(tsta) = c("Lon", "Lat")
gridded(tsta) <- TRUE
ra <- raster(tsta)
# a Rasterstack contains global range of 40 bioclim variables
files3 <- list.files(path=paste
("CM10_1975H_Bio_ASCII_V1.2/CM10_1975H_Bio_V1.2"),
, pattern='txt',full.names=TRUE )[https://www.climond.org/Core/Authenticated/Data/CM10_V1.2/CM10_Bio_V1.2/CM10_Bio_ASCII_V1.2/CM10_1975H_Bio_ASCII_V1.2.zip][1]
predictors3 <- stack(files3)
asia.predictors3 <- mask(predictors3,ra)
Error in compareRaster(x, mask) : different extent
The details for predictors3 were
predictors3
class : RasterStack
dimensions : 857, 2160, 1851120, 40 (nrow, ncol, ncell, nlayers)
resolution : 0.1666667, 0.1666667 (x, y)
extent : -180, 180, -59.16667, 83.66667 (xmin, xmax, ymin, ymax)
coord. ref. : NA
names : CM10_1975H_Bio01_V1.2, CM10_1975H_Bio02_V1.2, CM10_1975H_Bio03_V1.2, CM10_1975H_Bio04_V1.2, CM10_1975H_Bio05_V1.2, CM10_1975H_Bio06_V1.2, CM10_1975H_Bio07_V1.2, CM10_1975H_Bio08_V1.2, CM10_1975H_Bio09_V1.2, CM10_1975H_Bio10_V1.2, CM10_1975H_Bio11_V1.2, CM10_1975H_Bio12_V1.2, CM10_1975H_Bio13_V1.2, CM10_1975H_Bio14_V1.2, CM10_1975H_Bio15_V1.2, ...
The details for ra were:
ra
class : RasterLayer
dimensions : 213, 290, 61770 (nrow, ncol, ncell)
resolution : 0.1666667, 0.1666667 (x, y)
extent : 97.5, 145.8333, 18.16667, 53.66667 (xmin, xmax, ymin, ymax)
coord. ref. : NA
data source : in memory
names : Location
values : 168505, 377653 (min, max)
My goal is to prepare a RasterLayer or Rasterstack contains all variables of "predictors3" but limited in the range of "ra". As you can see the extent of ra was included in the extent of predictors3 and their resolutions were identical. How should I fix the error?
In this case, as the origin and resolution of ra and predictors3 are the same, you can use crop
predictors3 <- raster(xmn=-180, xmx=180, ymn=-59.16667, ymx=83.66667, res=1/6)
ra <- raster(xmn=97.5, xmx=145.8333, ymn=18.16667, ymx=53.66667, res=1/6)
x <- crop(predictors3, ra)
In other cases, you may need to use (dis)aggregate or resample
According to the above suggestions, I crop the the global climate layer "predictors3" to identify the extent of two rasters. Then, mask the latest raster to acquire the targeting variables limited in specific area.
asia.predictors <- crop(predictors3,ra)
asia.predictors3 <- mask(asia.predictors,ra)

Resources