I am trying to use grepl as part of an if control statement in R. I want to subset a SpatialPolygonsDataFrame object in my list (i.e. googleProjectedGroundTruth or googleProjectedFallow) only if its name contains 'groundtruth'

My code is:

shapefileGroundTruth  <- rgdal::readOGR(fileGeodatabase, layer = 'Bard_Groundtruth_2018T2')
shapefileFallow  <- rgdal::readOGR(fileGeodatabase, layer = 'BardFallowing2018')
googleProjectedGroundTruth <- sp::spTransform(shapefileGroundTruth, sp::CRS('+init=epsg:4326'))
googleProjectedFallow <- sp::spTransform(shapefileFallow, sp::CRS('+init=epsg:4326'))

list <- c(googleProjectedGroundTruth, googleProjectedFallow)
for(i in list){
  if (grepl('groundtruth|Groundtruth|GroundTruth', i)){
    # Subset feature class by region of interest and always by class 1 (ground truth fields)  
    i <- i[i$QUADNAME == 'BARD' & i$CLASS == 1, ] 
  } else { 
    print('Not subsetting SpatialPolygonsDataFrame since not ground truth data')

The error received is:

Error in as.character.default(googleProjectionShapefile) : no method for coercing this S4 class to a vector
  • What do you mean by 'its name'? And you say "if its name contains 'groundtruth'" but you search for matches to 'google'? – Kadir Şahbaz Sep 4 '18 at 21:13
  • @Kadir, thanks for pointing that out. I'm isolating code from a larger function and meant to change variables. I've made a new example. – ENIAC-6 Sep 4 '18 at 21:58

First, you are specifying the spatial object and not the attributes. Second, your if statement does not recycle the results of grepl. You can have multiple Boolean conditions returned so you should receive the warning:

the condition has length > 1 and only the first element will be used

Check it on a simple vector here:

googleProjectedShapefile <- c("Google","google","not","still-not")
grepl('google|Google', googleProjectedShapefile)
  if (grepl('google|Google', googleProjectedShapefile)){

You can use a length or any statement to meet the condition but, given your problem, it still does not entirely track. It would be more prudent to use the index returned by grep and then apply the condition. If you are applying a condition in a for loop, this is a much more efficient approach that does not require iteration.

Here is an example that may aim you towards a solution. First, lets create some example data, emulating your data, using meuse in sp.

coordinates(meuse) <- ~x+y
cat("size of meuse =", nrow(meuse), "\n")
  meuse$Groundtruth <- NA
    meuse$Groundtruth[sample(1:nrow(meuse),50)] <- "google" 
  meuse$QUADNAME <- NA
    meuse$QUADNAME[sample(1:nrow(meuse),50)] <- "BARD" 
  meuse$CLASS <- NA
    meuse$CLASS[sample(1:nrow(meuse),50)] <- 1

Now we can create an index of rows that contain the google string and then apply your condition to just these rows. The second index are rows that contain the google string and meet the QUADNAME == "BRAD" & CLASS == 1 condition. We then just remove the matches based on the corresponding row index values.

( idx <- grep('google|Google', meuse$Groundtruth) )
( idx <- which(meuse[idx,]$QUADNAME == "BARD" & meuse[idx,]$CLASS == 1 ) )

if(length(idx) > 0) { meuse <- meuse[-idx,] }
  cat("subset size of meuse =", nrow(meuse), "\n")

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.