rdataframefilterr-s4

add personal funtion in setMethod in R


I have and new S4 object with 4 Slots, one of them is a data.frame (g_table), so I want to add a parameters to setMethod to subset the data:

this is my actual code:

setGeneric('g_table', function(x) standardGeneric('g_table'))
setMethod('g_table', 'NewPackage', function(x) { x@g_table })

# assignment-methods: 
setGeneric("g_table<-", function(x, value) standardGeneric("g_table<-"))
setMethod("g_table<-", "NewPackage", function(x, value) {
  x@g_table <- value
  return(x)
})

and have no problem with it, just if I want to filter something in the data.frame (g_table) I need to do something like:

g_table(myObj) %>% filter(., gene %in% c("gene1", "gene2") )

and it filter the data, but I want to add the filter or subset option to g_table methods

first I tried to create a function

my_function <- function(obj, by){
    par <- substitute(by)
    dat <- obj@g_table
    gt <- subset(dat, eval(par, dat))
    return(gt)
}

it works like:

my_function(myObj, gene %in% c("gene1", "gene2") )

so I tried to replicate it in setMethod, something like:

setGeneric('g_table', function(x, by=NULL) standardGeneric('g_table'))

setMethod('g_table', 'NewPackage', function(x, by=NULL) { 

  if(!is.null(by)){
    par <- substitute(by)
    dat <- x@g_table
    gt <- subset(dat, eval(par, dat))
  }  
  if(is.null(by)){
        gt <- x@g_table 
  }
  return(gt)
})

This is the error:

g_table(MyObj, gene %in% c("gene1", "gene1") )
 Error in h(simpleError(msg, call)) : 
error in evaluating the argument 'x' in selecting a method for function '%in%': object 'gene' not found

any way to fix or do it ??

Thanks


Solution

  • This doesn't appear to have anything to do with S4's setMethod specifically. You can simplify this to

    foo <- function(x, by=NULL) { 
      if(!is.null(by)){
        par <- substitute(by)
        subset(x, eval(par, x))
      } else {
        x
      }
    }
    
    dd <- data.frame(gene=c("gene1", "gene2", "gene3", "gene1"), val=1:4)
    
    foo(dd, gene %in% c("gene1", "gene2"))
    

    which gives the same error. The problem is when you do is.null(by) you are evaluating the by parameter. The collapses the promise and you can no longer use substitute on that value.

    It's safer to use missing() rather than checking for NULL

    foo <- function(x, by) { 
      if(!missing(by)){
        par <- substitute(by)
        subset(x, eval(par, x))
      } else {
        x
      }
    }
    
    foo(dd, gene %in% c("gene1", "gene2"))
    foo(dd)
    

    If you really needed to check for NULL, you could do something like

    foo <- function(x, by=NULL) { 
      by <- substitute(by)
      if(length(by)>0 && as.list(by)[[1]] != as.symbol("NULL")){
        subset(x, eval(by, x))
      } else {
        x
      }
    }
    
    foo(dd, gene %in% c("gene1", "gene2"))
    foo(dd)
    foo(dd, NULL)