Scale raster cell in stack from -1 to 1 R

Scale raster cell in stack from -1 to 1 R



I have a raster stack with 364 layers with a daily rate of change in NDVI values.



I want to scale these values in every cell if positive from 0 to 1 and if negative from -1 to 0. So far I have only found a solution that scale values in single layers (see here: Replace specific value in each band of raster brick in R) and not along cells of multilayer objects. Additionally I have a decent amount of cells with NA for the entire time series and I'm not quite sure how to deal with this fact either.



I took the code from the previously mentioned post and tried to get it working for my problem:


norm <- function(x)-1+(x-min)*((1-(-1))/(max-min))

for(j in 1:ncell(tif))

if(is.na(sum(tif[j])))
NULL
else

cat(paste("Currently processing layer:", j,"/",ncell(tif), "n"))

min <- cellStats(tif[j],'min')
max <- cellStats(tif[j],'max')

#initialize cluster
#number of cores to use for clusterR function (max recommended: ncores - 1)
beginCluster(31)

#normalize
tif[j] <- clusterR(tif[j], calc, args=list(fun=norm), export=c('min',"max"))

#end cluster
endCluster()




I'm not quite certain if this produces the desired output. Any help is very much appreciated!




1 Answer
1



Some example data


library(raster)
r <- raster(ncol=10, nrow=10)
s <- stack(lapply(1:5, function(i) setValues(r, runif(100, -1, 1))))
# adding NAs
s[[2]][sample(100, 25, TRUE)] <- NA



For scaling (or any other operation) by cell (as requested) you can use calc together with a function that works on a vector. For example:


calc


ff <- function(i)
p <- which(i >= 0)
n <- which(i <= 0)
# positive values
if (length(p) > 0)
i[p] <- i[p] - min(i[p], na.rm=TRUE)
i[p] <- i[p] / max(i[p])

# negative values
if (length(n) > 0)
i[n] <- i[n] - max(i[n], na.rm=TRUE)
i[n] <- i[n] / abs(min(i[n]))

i



Test it


ff(c(-.3, -.1, .1, .4, .8))
#[1] -1.0000000 0.0000000 0.0000000 0.4285714 1.0000000
ff(c(-.3, -.1, .1, .4, .8, NA))
#[1] -1.0000000 0.0000000 0.0000000 0.4285714 1.0000000 NA
ff(c(-2,-1))
#[1] -1 0
ff(c(NA, NA))
#[1] NA NA



And use it


z <- calc(s, ff)



See the below to scale by layer, based on the min and max of all cell values (I first thought that this is what was asked for). Note that the functions I used below scale values from -1 to 1, but not the lowest positive value and highest negative value to zero.


minv <- abs(cellStats(s,'min'))
maxv <- cellStats(s,'max')

f1 <- function(i, mn, mx)
j <- i < 0
j[is.na(j)] <- TRUE
i[j] <- i[j] / abs(mn)
i[!j] <- i[!j] / mx
i


ss <- list()
for (i in 1:nlayers(s))
ss[[i]] <- calc(s[[i]], fun=function(x) f1(x, minv[i], maxv[i]))


ss1 <- stack(ss)



Or without a loop


f2 <- function(x, mn, mx)
x <- t(x)
i <- which(x > 0)
i[is.na(i)] <- FALSE
mxx <- x / mx
x <- x / mn
x[i] <- mxx[i]
t(x)


ss2 <- calc(s, fun=function(x) f2(x, minv, maxv))



For reference, to simply scale between 0 and 1


mnv <- cellStats(s,'min')
mxv <- cellStats(s,'max')
x <- (s - mnv) / (mxv - mnv)



To get values between -1 and 1 you can then do


y <- 2 * (x - 1)



But that way previously negative values can become positive and vice versa.



See ?raster::scale for other types of scaling.


?raster::scale






thanks for this great answer! It is almost what I need, but as far as I understood it, this solution works with the min/max values per layer and I would need one that works with the min/max per cell (kind of a local min/max) in order to scale every cell from -1 to 1, don't I?

– Benjamin Sigrist
Sep 16 '18 at 9:16






OK, I missed that because you used cellStats in your code.

– Robert Hijmans
Sep 16 '18 at 19:29



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)