Error when extracting values from a rasterBrick or rasterStack - r

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)

Related

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)

Subset R rasterstack based on difference in raster layers grid cell numbers

I want to create subsets of raster stacks and write them as new stacks when the difference between the previous layer and the next layer is all NA. I.e., starting from layer 1, I want to create a subset of raster stacks until there are no-overlapping pixels between the previous and next layers (i.e., the difference between the two layers is all NA) So I want is; starting from layer 1, retain all the layers that have at least 1 common pixel between the previous and next layer, write them as a 1 stack, and move to the next. Below are a sample data and unsuccessful for-loop. In this example, I want to retain layers 1:8, name and write them and start again from layer 9 and so on.
r <- raster(ncol=5, nrow=5)
set.seed(0)
#create raster layers with some values
s <- stack(lapply(1:8, function(i) setValues(r, runif(ncell(r)))))
s1<-extend(s,c(-500,100,-400,100))
#to recreate the condition I am looking for, create 2 layers with `NA` vlaues
s2 <- stack(lapply(1:2, function(i) setValues(r, runif(ncell(r)))))
s1e<-extend(s2,c(-500,100,-400,100))
s1e[]<-NA
#Stack the layers
r_stk<-stack(s1,s1e)
plot(r_stk)
#here is the sample code showing what i am expecting here but could not get
required_rst_lst<-list() # sample list of raster layers with overlapping pixels I am hoping to create
for ( i in 1: nlayers(r_stk))
# i<-1
lr1<-subset(r_stk,i)
lr1
lr2<-subset(r_stk,i+1)
lr2
diff_lr<-lr1-lr2
plot(diff_lr)
if ((sum(!is.na(getValues(diff_lr)))) ==0)) #??
required_rst_lst[[i]] #?? I want layers 1: 8 in this list
#because the difference in these layers in not NA
Something like this may work for you.
Your example data
library(raster)
r <- raster(ncol=5, nrow=5)
set.seed(0)
s <- stack(lapply(1:8, function(i) setValues(r, runif(ncell(r)))))
s1 <- extend(s,c(-500,100,-400,100))
s2 <- stack(lapply(1:2, function(i) setValues(r, runif(ncell(r)))))
s1e <- extend(s2,c(-500,100,-400,100))
values(s1e) <- NA
r_stk <- stack(s1,s1e)
Solution:
out <- lst <- list()
nc <- ncell(r_stk)
for (i in 1:nlayers(r_stk)) {
if (i==1) {
j <- 1
s <- r_stk[[i]]
} else {
s <- s + r_stk[[i]]
}
if (freq(s, value=NA) == nc) {
ii <- max(j, i-1)
out <- c(out, r_stk[[j:ii]])
s <- r_stk[[i]]
j <- i
}
}
out <- c(out, r_stk[[j:i]])
out
#[[1]]
#class : RasterStack
#dimensions : 14, 9, 126, 8 (nrow, ncol, ncell, nlayers)
#resolution : 72, 36 (x, y)
#extent : -468, 180, -414, 90 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +no_defs
#names : layer.1.1, layer.2.1, layer.3, layer.4, layer.5, layer.6, layer.7, layer.8
#min values : 0.06178627, 0.01339033, 0.07067905, 0.05893438, 0.01307758, 0.03554058, 0.06380848, 0.10087313
#max values : 0.9919061, 0.8696908, 0.9128759, 0.9606180, 0.9926841, 0.9850952, 0.8950941, 0.9437248
#
#[[2]]
#class : RasterLayer
#dimensions : 14, 9, 126 (nrow, ncol, ncell)
#resolution : 72, 36 (x, y)
#extent : -468, 180, -414, 90 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +no_defs
#source : memory
#names : layer.1.2
#values : NA, NA (min, max)
#
#[[3]]
#class : RasterLayer
#dimensions : 14, 9, 126 (nrow, ncol, ncell)
#resolution : 72, 36 (x, y)
#extent : -468, 180, -414, 90 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +no_defs
#source : memory
#names : layer.2.2
#values : NA, NA (min, max)

Reclassify values in a RasterBrick by the use of an additional Raster (Digital elevation model)

I have a RasterBrick consisting of daily snow cover data with the values 1, 2 and 3 (1= snow, 2= no snow, 3= cloud-obscured).
Example of snow cover of one day:
> snowcover
class : Large RasterBrick
dimensions : 26, 26, 2938 (nrow, ncol, nlayers)
resolution : 231, 232 (x, y)
extent : 718990, 724996, 5154964, 5160996 (xmin, xmax, ymin, ymax)
crs : +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs +ellps=WGS84
+towgs84=0,0,0
Now I wish to interpolate the cloud-obscured pixels (but only where there are less than 90 % cloud cover in a single RasterLayer, otherwise the original values should be retained for this Layers).
For spatial interpolation I want to use a digital elevation model (same study area and already in same resolution) to extract upper and lower snowline boundaries for each Layer of the RasterBrick respectively. The upper snow line represents the elevation where
all cloud-free pixels are classified as snow. The lower snowline identifies the
altitude below which all cloud-free pixels are also snow-free.
> dem
class : RasterLayer
resolution : 231, 232 (x, y)
extent : 718990.2, 724996.2, 5154964, 5160996 (xmin, xmax, ymin, ymax)
crs : +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs +ellps=WGS84
+towgs84=0,0,0
values : 1503, 2135 (min, max)
For the upper snowlines I need the minimum elevation of the snow-covered pixels (value = 1). Now all pixels of value 3 in a RasterLayer of the RasterBrick above this minimum elevation, should be reclassified as value 1 (assumed to be snow-covered).
For the lower snowline on the other hand I need to identify the maximum elevation of the no-snow-pixels (value = 2). Now all pixels of value 3 in a RasterLayer of the RasterBrick above this maximum elevation should be reclassified as value 2 (assumed to be snow-free).
Is this possible using R?
I tried to make use of the overlay function, but I got stuck there.
# For the upper snowline:
overlay <- overlay(snowcover, dem, fun=function(x,y){ x[y>=minValue(y[x == 1])] <- 1; x})
Here is some example data
library(raster)
dem <- raster(ncol=8, nrow=7, xmn=720145, xmx=721993, ymn=5158211, ymx=5159835, crs='+proj=utm +zone=32 +datum=WGS84')
values(dem) <- ncell(dem):1
snow <- setValues(dem, c(1, 1, rep(1:3, each=18)))
snow[,c(2,5)] <- NA
snow[3] <- 3
plot(snow)
lines(as(dem, 'SpatialPolygons'))
text(dem)
The plot shows the snow classes (1, 2, 3) with the elevation values on top.
We can use mask, but need to deal with the missing values.
msnow <- reclassify(snow, cbind(NA, 0))
# mask to get only the snow elevations
x <- mask(dem, msnow, maskvalue=1, inverse=TRUE)
# minimum elevation of the snow-covered cells
minsnow <- minValue(x)
minsnow
#[1] 37
# snow elevation = 1
snowy <- reclassify(dem, rbind(c(-Inf, minsnow, NA), c(minsnow, Inf, 1)))
newsnow <- cover(snow, snowy)
s <- stack(dem, snow, newsnow)
names(s) <- c("elevation", "old_snow", "new_snow")
You were very close, as you can do
r <- overlay(dem, snow, fun=function(e, s){ s[e >= minsnow] <- 1; s})
But note that that also overwrites high cells with no snow.
Which could be fixed like this:
r <- overlay(dem, snow, fun=function(e, s){ s[e >= minsnow & is.na(s)] <- 1; s})
To select layers with more than x% cells with value 3 (here I use a threshold of 34%):
threshold = .34
s <- stack(snow, snow+1, snow+2)
f <- freq(snow)
f
# value count
#[1,] 1 14
#[2,] 2 13
#[3,] 3 15
#[4,] NA 14
nas <- f[is.na(f[,1]), 2]
ss <- subs(s, data.frame(from=3, to=1, subsWithNA=TRUE))
cs <- cellStats(ss, sum)
csf <- cs / (ncell(snow) - nas)
csf
# layer.1 layer.2 layer.3
#0.3571429 0.3095238 0.3333333
i <- which(csf < threshold)
use <- s[[i]]
#use
class : RasterStack
dimensions : 7, 8, 56, 2 (nrow, ncol, ncell, nlayers)
resolution : 231, 232 (x, y)
extent : 720145, 721993, 5158211, 5159835 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=32 +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
names : layer.2, layer.3
min values : 2, 3
max values : 4, 5

Band math with calc and / or overlay returning single-valued images

When I try to run band math the result is always an image of a color and the values min and max very different from the one predicted.
I did not find any question here that showed this problem.
I worked out this way
r.stack <- stack("path to raster file"))
I use resampling instead of crop to cut out the white edges that were in the original images
prj <- "+proj=utm +zone=23 +south +datum=WGS84 +units=m"
r <- raster(res=11.47, ext=extent(c(301496, 323919, 9888968, 9913982)), crs=prj, vals=NA
r.stack <- resample(r.stack, r)
After that the images have this configuration:
> class : RasterBrick
> dimensions : 2181, 1955, 4263855, 4 (nrow, ncol, ncell, nlayers)
> resolution : 11.47, 11.47 (x, y)
> extent : 301496, 323919.8, 9888966, 9913982 (xmin, xmax, ymin, ymax)
>coord. ref. : +proj=utm +zone=23 +south +datum=WGS84 +units=m +ellps=WGS84 +towgs84=0,0,0
>data source : in memory
>names : l.1, l.2, l.3, l.4
>min values : -36.12217, -45.12768, -46.30455, -35.26328
>max values : 10.567671, 4.050200, 3.878345, 11.613799
and than use the function below for calc
f <- function(x){
(x[[2]])/(x[[1]])
}
s <- r.stack[[c(1,2)]]
r2 <- calc(s, f)
and I also run overlay whit the fun
f <- function(x,y){
y/x
}
r2 <- overlay(r.stack[[1]], r.stack[[2]], fun= f)
Any of the methods result in a image of one value
Am I missing some steps?
Here is your code with some example data (without that it is hard to answer questions). I have simplified one function, a bit, but the results are the same.
library(raster)
b <- brick(system.file("external/rlogo.grd", package="raster"))
b <- b/10 + 1
f <- function(x){ x[2]/ x[1] }
s <- b[[c(1,2)]]
r1 <- calc(s, f)
f <- function(x,y){ y / x }
r2 <- overlay(b[[1]], b[[2]], fun= f)
Or simply
r3 <- b[[2]] / b[[1]]
r3
#class : RasterLayer
#dimensions : 77, 101, 7777 (nrow, ncol, ncell)
#resolution : 1, 1 (x, y)
#extent : 0, 101, 0, 77 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=merc +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
#data source : in memory
#names : layer
#values : 0.7692308, 1.7 (min, max)
r1 and r2 are the same.
The reason that you get a "single color" is because most values are near 1, but there are a few big outliers; probably because of a division by a number between -1 and 1? This might illustrate it:
q <- quantile(r3, c(0.1, 0.9))
d <- clamp(r3, q[1], q[2])
plot(d)
And look at the extremes
i <- which.max(r3)
b[i][,2:1]

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.

Resources