2
votes

In R I can easily compute the max/min value of each cell in a georeferenced raster stack using the max/min commands.

set.seed(42)
require(raster)
r1 <- raster(nrows=10, ncols=10)
r2=r3=r4=r1
r1[]= runif(ncell(r1))
r2[]= runif(ncell(r1))+0.2
r3[]= runif(ncell(r1))-0.2
r4[]= runif(ncell(r1))
rs=stack(r1,r2,r3,r4)
plot(rs)
max(rs)
min(rs)

However, I have been trying to find a way to find the second highest values across a stack. In my case, each raster on the stack denotes performance of a particular model across space. I would like to compare the first vs second best values to determine how much better is the best model from its runner up without having to convert my stack to a matrix and then back into a raster. Any ideas or suggestions??

1
max(rs[rs<max(rs)]) is one sloppy way.Carl Witthoft
Unfortunately that does not work as r does not have defined methods to subset a stack using the syntax you suggested: ' Error in rs[rs < max(rs)] : object of type 'S4' is not subsettable'Lucas Fortini
Yeah, sorry -- you'd have to do some coercion on the attributes of the stack.Carl Witthoft

1 Answers

5
votes

You'll probably want to use calc(), adapting the code below to your precise situation. Just to show that it works as advertised, I've separately plotted layers formed by taking the highest, second highest, third, and fourth highest values found in each cell of the 4-layer RasterStack object.

zz <- range(cellStats(rs, range))

par(mfcol=c(2,2))
plot(calc(rs, fun=function(X,na.rm) X[order(X,decreasing=T)[1]]), main="1st",zlim=zz)
plot(calc(rs, fun=function(X,na.rm) X[order(X,decreasing=T)[2]]), main="2nd",zlim=zz)
plot(calc(rs, fun=function(X,na.rm) X[order(X,decreasing=T)[3]]), main="3rd",zlim=zz)
plot(calc(rs, fun=function(X,na.rm) X[order(X,decreasing=T)[4]]), main="4th",zlim=zz)

Or, more compactly and efficiently, just construct a new raster stack holding the reordered values and then plot its layers:

zz <- range(cellStats(rs, range))
rs_ord <- calc(rs, fun=function(X,na.rm) X[order(X,decreasing=T)])

par(mfcol=c(2,2))
plot(rs_ord[[1]], main="1st", zlim=zz)
plot(rs_ord[[2]], main="2nd", zlim=zz)
plot(rs_ord[[3]], main="3rd", zlim=zz)
plot(rs_ord[[4]], main="4th", zlim=zz)

enter image description here