0

I created my own function to filter out single pixels or clumps from a raster.

sieve_raster = function(x, pixelNum=1, areaThr=0, precise=FALSE){
  if (!is(x, "RasterLayer")) stop("The provided object is not a RasterLayer")

  if( pixelNum < 1L ){ stop("pixelNum cannot be smaller than 1" )}

  if( length(unique(na.omit(getValues(x)))) > 1){ stop("raster is not binary (value;NA)") }

  if( areaThr < 0){ # override pixelNum, calculating it from area threshold
    stop("Area cannot be negative")
  } else if( areaThr > 0){
    pixelNum = round(areaThr / (raster::res(x)[1] * raster::res(x)[2]))
  }

  # remove single cells
  #https://geoscripting-wur.github.io/AdvancedRasterAnalysis/
  raster.clumps = raster::clump(x, directions=8) # Group raster cells into clumps of connected pixels
  excludeID = as.data.frame(freq(raster.clumps))

  if( isTRUE(precise) ){ # Put these into a vector of clump ID's to be removed
    excludeID <- excludeID$value[which(excludeID$count == pixelNum)] # select only values equal to pixelNum
  } else {
    excludeID <- excludeID$value[which(excludeID$count <= pixelNum)] # select a range below pixelNum
  }

  x[(raster.clumps %in% excludeID)] <- NA # Assign NA to all clumps whose IDs are found in excludeID

  if ( all(is.na(getValues(x))) ){ warning("Raster is blank after sieving: try a lower pixelNum value.", call. = FALSE) }

  return(x)
}

If I run each line of the function with proper inputs, it works well but when I run the function, it fails (since few days ago) reporting the following error:

Error in evaluating argument 'i' in the selection of a method for the function '[<-': 'match' requires vector arguments

Running in debug mode with Rstudio I get that the function gets stuck in the following line:

x[(raster.clumps %in% excludeID)] <- NA

I added the round brackets after a comment in a StackExchange post (that I can't find anymore...): -even if without knowing why- it did the job in that case but unfortunately doesn't help me out. Anything I'm missing? Any alternative to %in% operator?

I'm working on W10, Rstudio, R 4.1.1 and updated packages.

HERE a sample input raster: I'm using pixelNum=50, but function fails with every other value.

4
  • Do you know what data this is getting when you run "in a script"? Is it different to the data you feed it when it works? Because I can't break it...
    – Spacedman
    Oct 8 '21 at 13:08
  • I added a link to the failing raster and few more details in the description. could it be possible that %in% interacts with other fucntions/packages? I can't get where that "match" comes from.
    – Nico
    Oct 11 '21 at 7:20
  • right now I found a workaround x[ifelse(match(getValues(raster.clumps),excludeID),TRUE,FALSE)] <- NA but I'm still puzzled in understanding the original issue
    – Nico
    Oct 11 '21 at 9:16
  • Still can't break it using your sample raster. I do z=raster("PL.tif"); sieve_raster(z, pixelNum=50) and I get a raster returned. No error. An (ignorable) projection warning but that's irrelevant. raster:3.4.13, R:4.1.1 igraph:1.2.6, on Linux.
    – Spacedman
    Oct 11 '21 at 15:52
0

Finally I can replicate your error, but not with your code...

If I try and do a raster %in% value before attaching the raster package, I can get that error. From a clean R start, and calling raster functions by raster::function:

> z = raster::raster("PL.tif")
> z %in% 1
Error in match(x, table, nomatch = 0L) : 
  'match' requires vector arguments

If I now attach the raster package, it works:

> library(raster)
Loading required package: sp
> z %in% 1
class      : RasterLayer 
dimensions : 301, 260, 78260  (nrow, ncol, ncell)

This is because before attaching the raster package the %in% operator is this:

> get("%in%")
function (x, table) 
match(x, table, nomatch = 0L) > 0L
<bytecode: 0x556890f73bf8>
<environment: namespace:base>

But afterwards its a generic function which means methods for classes like rasters can be defined:

> library(raster)
Loading required package: sp
> get("%in%")
standardGeneric for "%in%" defined from package "base"

function (x, table) 
standardGeneric("%in%")
<environment: 0x556891423158>
Methods may be defined for arguments: x, table
Use  showMethods(%in%)  for currently available ones.

What I don't understand is how your function can get anywhere without the raster package attached, seeing as it uses getValues which R can only find if raster is attached, in which case why doesn't it get the generic version of %in%?

I get identical behaviour if I use match:

> z = raster::raster("PL.tif")
> match(z, 1)
Error in match(z, 1) : 'match' requires vector arguments
> library(raster)
Loading required package: sp
> match(z, 1)
class      : RasterLayer 
dimensions : 301, 260, 78260  (nrow, ncol, ncell)

The safe thing to do is to use raster:: everywhere, but that makes it hard to use operators (like %in%) so use raster::match.

> z = raster::raster("PL.tif")
> match(z,1 )
Error in match(z, 1) : 'match' requires vector arguments
> raster::match(z,1 )
class      : RasterLayer 
dimensions : 301, 260, 78260  (nrow, ncol, ncell)
resolution : 3, 3  (x, y)
1
  • whoa, I would have never got there...it seems there's quite more to learn about. Many thanks to open my eyes!
    – Nico
    Oct 12 '21 at 15:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.