Raster overlay from a matrix - r

I have a matrix of 100 raster layers and I'd like to create one new layer that is the average. I understand if there were two layers I could simply use the overlay function or perhaps just use c <- mean (a, b). However, I'm not sure how to proceed with the matrix.
Here is sample of the matrix:
[[1]]
class : RasterLayer
dimensions : 175, 179, 31325 (nrow, ncol, ncell)
resolution : 1, 1 (x, y)
extent : 0, 179, 0, 175 (xmin, xmax, ymin, ymax)
coord. ref. : NA
data source : in memory
names : layer
values : 0, 100 (min, max)
I have tried
a.avg <- mean (a.total[,])
and I receive the error argument is not numeric or logical: returning NA

I assume you have a list of rasterLayers ( or perhaps a stack ). If you already have a stack, skip step one, but I assume you have a list not a matrix which I have called mylistofrasters...
#1 - Get all rasters in the list into a stack
mystack <- do.call( stack , mylistofrasters )
#2 - Take mean of each pixel in the stack returning a single raster that is the average
mean.stack <- calc( mystack , mean , na.rm = TRUE )

This answer is similar to the #SimonO101's answer using a simpler code.
First, let's build a list of RasterLayer (you can skip this step if you already have the list):
library(raster)
r <- raster(nrow=10, ncol=10)
r <- init(r, runif)
lr <- lapply(1:8, function(i)r)
The raster package defines an stack method for lists, so you can use it directly without do.call:
s <- stack(lr)
Besides, there is a mean method for Raster* objects. Therefore, you don't really need calc:
mean(s, na.rm=TRUE)

Related

How can I subset a raster by conditional statement in R using `terra`?

I am trying to plot only certain values from a categorical land cover raster I am working with. I have loaded it in to R using the terra package and it plots fine. However, since the original data did not come with a legend, I am trying to find out which raster value corresponds to what on the map.
Similar to the answer provided here: How to subset a raster based on grid cell values
I have tried using the following line:
> landcover
class : SpatRaster
dimensions : 20057, 63988, 1 (nrow, ncol, nlyr)
resolution : 0.0005253954, 0.0005253954 (x, y)
extent : -135.619, -102, 59.99989, 70.53775 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : spat_n5WpgzBuVAV3Ijm.tif
name : CAN_LC_2015_CAL_wgs
min value : 1
max value : 18
> plot(landcover[landcover == 18])
Error: cannot allocate vector of size 9.6 Gb
However, this line takes a very long time to run and produces a vector memory error. The object is 1.3 kb in the global environment and the original tif is about 300 mb.
You can use cats to find out which values correspond to which categories.
library(terra)
set.seed(0)
r <- rast(nrows=10, ncols=10)
values(r) <- sample(3, ncell(r), replace=TRUE) - 1
cls <- c("forest", "water", "urban")
levels(r) <- cls
names(r) <- "land cover"
cats(r)[[1]]
# ID category
#1 0 forest
#2 1 water
#3 2 urban
To plot a logical (Boolean) layer for one category, you can do
plot(r == "water")
And from from the above you can see that in this case that is equivalent to
plot(r == 1)
I think I found the solution to write the conditional within the plot function as below:
plot(landcover == 18)
For those looking for a reproduceable example, just load the rlogo:
s <- rast(system.file("ex/logo.tif", package="terra"))
s <- s$red
plot(s == 255)

Limitations with RasterStack math and conditional statements

I have a large RasterStack (114 geotiff images) that I have successfully geoprocessed (masked, etc.) in R, but I am having difficulty getting it to apply a simple conditional statement to each raster (all raster layers are the same extent, resolution, and are co-registered). I want to set all pixel values that are less than 95% of each raster's max value to NA. For example, if a layer's max was 85, then pixel values < 80.75 = NA. Here's my code:
#Get max value from each raster layer
r_max <- maxValue(rstack)
#Set all values < 95% of max to NA
rstack[rstack < (r_max * 0.95)] = NA
When I run this code on the entire raster stack, I get "Error in value[j, ] : incorrect number of dimensions." However, if I run it on a smaller set (14 or so), it works exactly as it should.
Because I have successfully executed a number of similar operations (other conditional statements, masking,etc.) on the entire stack without error, I am not sure why it's throwing this error now. Any ideas?
I apologize if this has been discussed before, but I was unable to find such a post. If it does exist, please point me in that direction.
Thanks
Here is a minimal reproducible example:
library(raster)
s <- stack(system.file("external/rlogo.grd", package="raster"))
cutoff <- maxValue(s) * .95
cutoff
#[1] 242.25 242.25 242.25
Now you can do:
s[s < cutoff] = NA
s
#class : RasterBrick
#dimensions : 77, 101, 7777, 3 (nrow, ncol, ncell, nlayers)
#resolution : 1, 1 (x, y)
#extent : 0, 101, 0, 77 (xmin, xmax, ymin, ymax)
#crs : +proj=merc +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
#source : memory
#names : red, green, blue
#min values : 243, 243, 243
#max values : 255, 255, 255
But there is a bug when the RasterStack is large (and needs to be written to file) --- and that is what you have stumbled upon. We can emulate that situation with rasterOptions(todisk=TRUE):
rasterOptions(todisk=TRUE)
s[s < cutoff] = NA
#Error in value[j, ] : incorrect number of dimensions
I will try to fix that. Here is workaround:
s <- stack(system.file("external/rlogo.grd", package="raster"))
cutoff <- maxValue(s) * .95
x <- sapply(1:nlayers(s), function(i) reclassify(s[[i]], cbind(-Inf, cutoff[i], NA)))
x <- stack(x)

Matching the resolution of two rasters

Im working with two rasters each with a different resolution. Im wondering if there is a more efficient way of matching the coarser raster resolution to the finer raster resolution. Right now I am using the mask function to save some time, clip to the correct extent and change the resolution:
library(raster)
#the raster template with the desired resolution
r <- raster(extent(-180, 180, -64, 84), res=0.04166667)
# set some pixels to values, others to NA
r <- setValues(r, sample(c(1:3, NA), ncell(r), replace=TRUE))
#load the raster
lc_r1 <- raster(r)
res(lc_r1) <- 0.5
values(lc_r1) <- 1:ncell(lc_r1)
lc_r1
##class : RasterLayer
##dimensions : 296, 720, 213120 (nrow, ncol, ncell)
##resolution : 0.5, 0.5 (x, y)
##extent : -180, 180, -64, 84 (xmin, xmax, ymin, ymax)
##coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
##data source : in memory
##names : layer
##values : 1, 213120 (min, max)
#create the new finer resolution raster.
lc_r2 <- mask (lc_r1, r2)
Error in compareRaster(x, mask) : different number or columns
Im also trying the disaggregate function in raster but I get this odd error!
lc_r2 <- disaggregate (lc_r1, nrows=3600 )
Error: !is.null(fact) is not TRUE
This seems to work for the time being but not sure if its correct:
lc_r2 <- disaggregate (lc_r1, fact=c(12,12 ), method='bilinear')
Why would this Error: !is.null(fact) is not TRUE be odd? If you look at ?disaggregate you will see that there is no argument nrows, but there is a required argument fact, which you did not supply.
You can do
lc_r2a <- disaggregate (lc_r1, fact=12)
Or
lc_r2b <- disaggregate(lc_r1, fact=12, method='bilinear')
which is equivalent to
lc_r2c <- resample(lc_r1, r)
Why are you not sure that this is correct?
However, given that you want to mask lc_r1, the logical approach would be to go the opposite direction and change the resolution of your mask, r,
ra <- aggregate(r, fact=12, na.rm=TRUE)
lcm <- mask(lc_r1, ra)

Random sampling from large rasterlayer

I have a large Rasterlayer with integers ranging from 0 to 44.
class : RasterLayer
dimensions : 29800, 34470, 1027206000 (nrow, ncol, ncell)
resolution : 10, 10 (x, y)
extent : 331300, 676000, 5681995, 5979995 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs
data source : /home/mkoehler/stk_rast_whz
names : stk_rast_whz
values : 0, 44 (min, max)
I want to do a stratified sampling of 5000 points per stratum.
I get the following error:
POINTS<-sampleStratified(b, size=5000, na.rm=T, xy=F)
(Error in ys[[i]] <- y : attempt to select less than one element)
Here is a code that reproduces the problems (even when only selecting 1
item per stratum):
set.seed(10)
r <- raster(ncol=5000, nrow=5000)
names(r) <- 'stratum'
r[] <- round((runif(ncell(r)))*44)
sampleStratified(r, size=1,xy=T)
Error in ys[[i]] <- y : attempt to select less than one element
Trying that with fewer strata and changing the settings of "size" or
"exp" have no effect.
R version: [64-bit] C:\Program Files\R\R-3.1.1
Any ideas?
thanks in advance!
This appears to be a bug (as at raster 2.3-12), and occurs when (1) your raster contains cells with value 0, and (2) the raster can't be processed in memory (i.e. canProcessInMemory(r) is FALSE).
The function loops over the unique cell values produced by freq(r), and then indexes a list by each of these values in turn. If one of those values is zero, the error will be triggered since the 0th element does not exist. For example:
list()[[0]]
# Error in list()[[0]] : attempt to select less than one element]
You'll notice that the error doesn't occur if you fill r with, e.g., r[] <- sample(44, ncell(r), replace=TRUE), since it won't have any zeroes.
When the raster can be processed in memory, the function loops over the row numbers of freq(r), and so the subsequent list indexing is sensible.
I've contacted the maintainer to report this bug.
Meanwhile, as a temporary fix, you could use something like the following to make a corrected copy of the function (which will remain available in the current R session).
sampleStratified2 <-
eval(parse(text=sub('sr\\[, 2\\] == i', 'sr[, 2] == f[i, 1]',
sub('i in f\\[, 1\\]', 'i in seq_len(nrow(f))',
deparse(getMethod(sampleStratified,
signature='RasterLayer')#.Data))
)))
sampleStratified2(r, size=1, xy=TRUE)

Getting Data out of raster file in R

I'm new to raster files, but they seem to be the best way to open up the large gov't files that have all the weather data, so I'm trying to figure out how to use them. For reference, I'm downloading the files located here (just some run of the mill weather stuff). When I use the raster package of R to import the file like this
> r <- raster("/path/to/file.grb")
Everything works fine. I can even get a little metadata when I type in
> r
class : RasterLayer
band : 1 (of 37 bands)
dimensions : 224, 464, 103936 (nrow, ncol, ncell)
resolution : 0.125, 0.125 (x, y)
extent : -125.0005, -67.0005, 25.0005, 53.0005 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +a=6371200 +b=6371200 +no_defs
data source : /path/to/file.grb
names : NLDAS_MOS0125_H.A20140629.0100.002
All I've managed to do at this point is index the raster in a very obvious way.
> r[100,100]
267.1
So, I guess I can "index" it, but I have no idea what the number 267.1 means. It's certainly not all there is in the cell. There should be a bunch of variables including, but not limited to, soil moisture, surface runoff, and evaporation.
How can I access this information in the same way using R?
# create two rasters
r1 <- raster(matrix(ncol = 10, nrow = 10, runif(100)))
r2 <- raster(matrix(ncol = 10, nrow = 10, runif(100)))
# creates a raster stack -- the stack (or brick function) allows you to
# to use multilayer band rasters
# http://www.inside-r.org/packages/cran/raster/docs/stack
st_r <- stack(r1, r2)
# extract values -- will create a matrix with 100 rows and two columns
vl <- getValues(st_r)
r <- raster("/path/to/file.grb")
values <- getValues(r)
You can read about the function here:
http://www.inside-r.org/packages/cran/raster/docs/values
I believe that the problem is that you are using raster and not stack. The raster function results in a single layer (matrix) whereas stack or brick read an array with all of the raster layers. Here is an example that demonstrates extracting values using an [i,j,z] index.
library(raster)
setwd("D:/TMP")
download.file("ftp://hydro1.sci.gsfc.nasa.gov/data/s4pa/NLDAS/NLDAS_MOS0125_H.002/2014/180/NLDAS_MOS0125_H.A20140629.0000.002.grb",
destfile="NLDAS_MOS0125_H.A20140629.0000.002.grb", mode="wb")
r <- stack("NLDAS_MOS0125_H.A20140629.0000.002.grb")
names(r) <- paste0("L", seq(1:nlayers(r)))
class(r)
# Values for [i,j]
i=100
j=100
r[i,j]
# Values for i,j and z at layer(s) 1, 5 and 10
z=c(1,5,10)
r[i,j][z]

Resources