Apply boot::inv.logit() to a raster in R - 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))

Related

How to mask or clip rasters in R?

I am working with a marine species that has a shallow distribution, and I would like to delimit modelling of several ascii layers (e.g.SST, SSS) to a 50m depth threshold along the coastline using a bathymetric dataset (e.g. Bio-Oracle, MARSPEC or GEBCO). I am working in R. I do not want bathymetry to be part of the model though.
Does anyone know how to do this?
This is the bathymetric raster (with values down to 100m depth):
class : RasterLayer
dimensions : 600, 420, 252000 (nrow, ncol, ncell)
resolution : 0.08333333, 0.08333333 (x, y)
extent : -20, 15, 10, 60 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : bathy
values : -100, -1 (min, max)
AND THIS IS RASTER STACK
class : RasterStack
dimensions : 600, 420, 252000, 4 (nrow, ncol, ncell, nlayers)
resolution : 0.08333333, 0.08333333 (x, y)
extent : -20, 15, 10, 60 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
names : SST.min, SST.max, SST.range, BO_dissox
min values : -0.120, 10.940, 0.000, 4.052
max values : 26.640, 30.320, 21.460, 8.058
Cheers,
Rita
library(raster)
library(marmap)
library(rgdal)
# your coordinate reference setup
this_crs <- crs("+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0")
this_extent <- extent(-20, 15, 10, 60)
# a simple raster stack for example purpose
r <- raster(ncol=420, nrow=600, ext = this_extent, crs = this_crs)
values(r) <- (1:ncell(r))/100
r_SST <- sin(r)
r_SSS <- r + runif(ncell(r), 0, 100)^2
r_stack <- stack(r_SST, r_SSS)
# Get some sample bathymetric data to match your stack
# the marmaps package is handy but you could use your own
download_bathy <- getNOAA.bathy(-20, 15, 10, 60, res = 5, keep = TRUE)
bath_mask <- marmap::as.raster(download_bathy)
bath_mask <- projectRaster(from = bath_mask, to = r_stack)
# clip your raster stack to the desired bathymetric limits
bath_mask[bath_mask > 0 | bath_mask < -50] <- NA
clipped_stack <- mask(r_stack, bath_mask)
# check the result with a plot
plot(clipped_stack)
First use SDMPlay:::delim.area in which the first layer of the stack is used to delimit the 100m depth.
Then isolate the bathymetry layer with subset.
User raster:::mask to delimit all rasters to bathymetric area.
And finally remove bathymetry from stack, raster:::dropLayer.
Thanks to all and specially to Guillaumot Charlene!
Rita

Error while extracting netcdf files into raster

I have many NCDF files in a folder. I try to extract them into raster brick using raster and ncdf4 packages. If I separately extract each NCDF file it works. However, I try to extract all files using for loop then it gives me error.
R<-list.files("D:/Results/TimeSeries/NETCDF/")
r<-brick(paste0("D:/Results/TimeSeries/NETCDF/",R[[1]]),varname="T_min")
for(i in 2:length(R)){
r1<-brick(paste0("D:/Results/TimeSeries/NETCDF/",R[[i]]),varname="T_min")
r<-brick(r,r1)
}
Error in as.integer(nl) : cannot coerce type 'S4' to vector of type
'integer'
If I look at r and r1 separately they seem to have same extent and both are raster brick type:
> r
class : RasterBrick
dimensions : 81, 81, 6561, 122 (nrow, ncol, ncell, nlayers)
resolution : 1, 1 (x, y)
extent : 0.5, 81.5, 0.5, 81.5 (xmin, xmax, ymin, ymax)
coord. ref. : NA
data source : D:\Results\TimeSeries\NETCDF\timeseries_1km_2026.nc
names : X0026.05.02, X0026.05.03, X0026.05.04, X0026.05.05, X0026.05.06, X0026.05.07, X0026.05.08, X0026.05.09, X0026.05.10, X0026.05.11, X0026.05.12, X0026.05.13, X0026.05.14, X0026.05.15, X0026.05.16, ...
Date : 0026-05-02, 0026-08-31 (min, max)
varname : T_min
> r1
class : RasterBrick
dimensions : 81, 81, 6561, 122 (nrow, ncol, ncell, nlayers)
resolution : 1, 1 (x, y)
extent : 0.5, 81.5, 0.5, 81.5 (xmin, xmax, ymin, ymax)
coord. ref. : NA
data source : D:\Results\TimeSeries\NETCDF\timeseries_1km_2027.nc
names : X0027.05.02, X0027.05.03, X0027.05.04, X0027.05.05, X0027.05.06, X0027.05.07, X0027.05.08, X0027.05.09, X0027.05.10, X0027.05.11, X0027.05.12, X0027.05.13, X0027.05.14, X0027.05.15, X0027.05.16, ...
Date : 0027-05-02, 0027-08-31 (min, max)
varname : T_min
Please help.
There is no need to loop, raster is vectorized, try
p <- "D:/Results/TimeSeries/NETCDF"
R <- list.files(p, pattern = "nc$")
r <- raster::stack(file.path(p, R), varname = "T_min")
If you did need to loop, I'd do it like this:
r <- raster::stack(lapply(file.path(p, R), raster::raster, varname = "T_min"))
Edit: replace raster::raster with raster::stack.
Also note the use of file.path, and the facilities available within list.files. (Pasting text for file paths can be problematic, and is more complicated than using available functions).

R - create boxplot with rasters

this might be rather simple, but I am a novice in R. I have tried for awhile now to plot two rasters against each other using boxplot from the package raster.
I have a DEM raster and a categorical raster that contains 4 cluster groups, which I would like to use as 'zones' as described in the manual:
boxplot(x, y=NULL, maxpixels=100000, ...)
x Raster* object
y If x is a RasterLayer object, y can be an additional RasterLayer to group the
values of x by ’zone’
> DEM
class : RasterLayer
dimensions : 12381, 61922, 766656282 (nrow, ncol, ncell)
resolution : 0.1, 0.1 (x, y)
extent : 478307.4, 484499.6, 6131862, 6133100 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs
data source : /Users/Yvonne/Desktop/Boxplot/Ribe_DEM_0.1m.tif
names : Ribe_DEM_0.1m
values : -7.523334, -0.36 (min, max)
> Cluster
class : RasterLayer
dimensions : 12381, 61922, 766656282 (nrow, ncol, ncell)
resolution : 0.1, 0.1 (x, y)
extent : 478307.4, 484499.6, 6131862, 6133100 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs
data source : /Users/Yvonne/Desktop/Boxplot/final_cluster.tif
names : final_cluster
values : 1, 4 (min, max)
attributes :
ID Rowid COUNT
1 0 463524
2 1 4118997
3 2 3390160
4 3 3218998
> boxplot(DEM, Cluster, xlab="Cluster", ylab="Elevation")
Error in parse(text = x, keep.source = FALSE) :
<text>:2:0: unexpected end of input
1: ~
^
In addition: Warning message:
In .local(x, ...) : taking a sample of 1e+05 cells
Update:
I just found a working example, which does exactly what I want. However if I run it with my own data I always get above error. Maybe someone could explain the error message. Would be really appreciated.
r1 <- r2 <- r3 <- raster(ncol=10, nrow=10)
r1[] <- rnorm(ncell(r1), 100, 40)
r2[] <- rnorm(ncell(r1), 80, 10)
r3[] <- rnorm(ncell(r1), 120, 30)
s <- stack(r1, r2, r3)
names(s) <- c('A', 'B', 'C')
rc <- round(r1[[1]]/100)
hist(rc)
summary(rc)
boxplot(s[[1]],rc)
Okey I found an answer, I don't know exactly why but it works for me:
I had to create a brick and then I could use the boxplot as mentioned above.
s <- stack(DEM, Cluster)
sbrick <- brick(s)
boxplot(sbrick[[1]], sbrick[[2]], xlab="Cluster", ylab="Elevation")
Resulting in this plot boxplot DEM against cluster groups
Thanks everyone for their help!
You can use bwplot function in rasterVis library.
Here is an example from rasterVis:
library(raster)
library(rasterVis)
r <- raster(system.file("external/test.grd", package="raster"))
s <- stack(r, r*2)
bwplot(s,violin=FALSE,strip=strip.custom(strip.levels=TRUE))
It is not clear to me why you get that error. Perhaps you can run the code below and see for yourself:
x <- stack(DEM, Cluster)
s <- sampleRegular(s, 100000, useGDAL=TRUE)
cn <- colnames(s)
f <- as.formula(paste(cn[1], '~', cn[2]))
boxplot(f, data=s)
Perhaps you should only provide your raster values as a vector and let the boxplot() function do the rest by:
boxplot(values(DEM) ~ values(Cluster), xlab="Cluster", ylab="Elevation")
Note that this will only work if both DEM and Cluster are exactly the same extent and resolution.

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)

Error when extracting values from a rasterBrick or rasterStack

I am having trouble extracting values or a point from a multi band raster of class rasterStack or rasterBrick. 'extract' works well with the individual rasters but posts an error when applied to the rasterStack or brick.
> all.var
class : RasterBrick
dimensions : 89, 180, 16020, 34 (nrow, ncol, ncell, nlayers)
resolution : 2, 2 (x, y)
extent : -179, 181, -89, 89 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : period_max, pct_signif_periodmax, pct_coi_periodmax, pct_ispos_signif, events_pos_periodmax, events_neg_periodmax, events_pos_all, events_neg_all, maxpower_pos, maxpower_neg, maxpower_events_pos, maxpower_events_neg, maxpower_pos_norm, maxpower_neg_norm, maxpower_events_pos_norm, ...
> point
Lon Lat
1 166.2790 -10.2690
2 26.9000 -33.6000
3 153.6209 -28.7001
4 113.8333 -28.6833
5 153.6335 -28.6591
6 153.5836 -28.4643
7 32.6833 -27.5333
8 32.6880 -27.5260
9 32.6880 -27.5260
10 32.6880 -27.5260
> point.extract<-extract(all.var, point, buffer=50000,na.rm=TRUE,fun=mean)
Error in apply(x, 2, fun2) : dim(X) must have a positive length
This works with individual rasters but fails with stack/brick and elicits an error only when I use a buffer argument.
Here is a working R example that illustrates the error:
library(raster)
b <- brick(nrow=89, ncol=180, nl=34, xmn=-179, xmx=181, ymn=-89, ymx=89, crs="+proj=longlat +datum=WGS84")
b[] <- 1
p <- matrix(c(166.2790,-10.2690,26.9000,-33.6000,153.6209,-28.7001,113.8333,-28.6833,153.6335,-28.6591,153.5836,-28.4643,32.6833,-27.5333,32.6880,-27.5260,32.6880,-27.5260,32.6880,-27.5260), ncol=2, byrow=TRUE)
v <- extract(b, p, buffer=50000, na.rm=TRUE, fun=mean)
That indeed gives the error you reported, probably due a bug in the raster package. Here is a work-around:
v <- extract(b, p, buffer=15000000)
# get the mean for each point (buffer) by layer
vv <- lapply(v, function(x) ifelse(is.matrix(x), colMeans(x, na.rm=TRUE), x))
# combine
do.call(rbind, vv)

Resources