0

I'm working on some post processing of a very large raster (437760000 cells) using other raster layers of the same extent/crs for constraints. The code is working for the most part but I'm running into an issue.

r1[r2== 6 & r3>= 40 & r3<= 60] <- sample(2:4, length(r1[r2== 6 & r3>= 40 & r3 <= 60]), replace = T)

Where r1, r2, and r3 are unique raster layers. r1 is being updated based on the constraints with the aim to improve the map.

This code executes with no issues but throws the following warning upon completion:

Warning message:
In .local(x, i, j = j, ..., value) :
  the first replacement value is used for all cells

I want to ensure that all three values are being picked at random (and eventually I want to use the prob argument in sample to weight one of the values). I've tried numerous fixes and they all throw the same warning message, which I'm taking to mean that only one of the three values is being applied across the raster. I am working in terra for this.

Any thoughts? Thanks!

slaca
  • 1
  • I see you're a new user. Welcome! Now, if you want to maximise your chances of having an answer, try to create a reproducible example. In this case, create a bogus raster of size ~20x20 and apply your code to it that produces the error. On our side, it will be easier to understand your goal and we will simply copy paste your code in our R session. – Bastien Jan 07 '21 at 13:17

2 Answers2

1

Here is a reproducible example for your problem:

library(terra)

set.seed(123)
r1 <- rast(matrix(round(runif(400, 0, 100)), 20, 20))
plot(r1)

r2 <- rast(matrix(round(runif(400, 0, 10)), 20, 20))
r3 <- rast(matrix(round(runif(400, 30, 70)), 20, 20))

Even if I wasn't able to reproduce your warning code, I think your problem is in your interpretation of this call: r2== 6 & r3>= 40 & r3 <= 60. This line produces a raster:

r2== 6 & r3>= 40 & r3 <= 60
class       : SpatRaster 
dimensions  : 20, 20, 1  (nrow, ncol, nlyr)
resolution  : 0.05, 0.05  (x, y)
extent      : 0, 1, 0, 1  (xmin, xmax, ymin, ymax)
coord. ref. :  
source      : memory 
name        : lyr.1 
min value   :     0 
max value   :     1 

An therefore making this call r1[r2== 6 & r3>= 40 & r3 <= 60] produce a dataframe:

str(r1[r2== 6 & r3>= 40 & r3 <= 60])
'data.frame':   17 obs. of  1 variable:
 $ lyr.1: num  2 2 2 2 2 2 2 2 2 2 ...

You don't want that because length of a 1 column data.frame = 1 and because you can't do value substitution with a data.frame.

Try this instead:

pixel_to_change <- values(r2== 6 & r3>= 40 & r3<= 60) == 1
r1[pixel_to_change] <- sample(2:4, sum(pixel_to_change), replace = T)  

It may be what your are looking for.

Bastien
  • 3,007
  • 20
  • 38
1

Here are two alternative (but similar) solutions to Bastien's. They avoid using values which can be problematic with very large datasets.

library(terra)
set.seed(123)
r1 <- rast(matrix(round(runif(400, 0, 100)), 20, 20))
r2 <- rast(matrix(round(runif(400, 0, 10)), 20, 20))
r3 <- rast(matrix(round(runif(400, 30, 70)), 20, 20))

#1, use lapp

x <- c(r1, r2, r3)
z <- lapp(x, function(r1, r2, r3) {
    i <- r2== 6 & r3>= 40 & r3<= 60
    r1[i] <- sample(2:4, sum(i), replace = T)
    r1
})

#2, use global (instead of length, take the global sum of the raster with TRUE/FALSE values)

i <- r2== 6 & r3>= 40 & r3<= 60
n <- unlist(global(i, "sum"))
r1[i] <- sample(2:4, n, replace = T)
Robert Hijmans
  • 40,301
  • 4
  • 55
  • 63