[BioC] On extending class ExpressionSet

Renaud Gaujoux renaud at mancala.cbio.uct.ac.za
Thu Dec 16 07:05:21 CET 2010


Hi Morgan,

thank you very much for the explanation on the initialize method for the 
class ExpressionSet.
I always found the S4 initialization mechanism a bit difficult to handle 
in the case of inheritance. It often requires to manually pass slots to 
the parent class, which should be automatic: each class -- developer -- 
has to deal only with its own data members.

Maybe I am too optimistic, but would something like the following 
definition of initialize,ExpressionSet-method fix the problem without 
changing the current behaviour for the dependent packages (since I 
assume they all pass assayData as a first argument):

structure(function (.Object, ...)
{
	# check if the first argument is an ExpressionSet
	# if so: initialize the object with it and tells .local not to
	# overwrite slots corresponding to missing arguments.
	# otherwise: s
	overwrite.missing<- TRUE
	dotargs<- list(...)	
	if( length(dotargs)>  1&&  is(dotargs[[1]], 'ExpressionSet') ){		
		.Object<- dotargs[[1]]		
		overwrite.missing<- FALSE
		dotargs<- dotargs[-1]
	}		

	# .local should initialize (i.e. overwrite) a slot of .Object with its prototype only if overwrite.missing=TRUE, or in any case with the corresponding non missing argument for this slot.
      .local<- function (.Object, overwrite.missing=TRUE, assayData, phenoData, featureData,
          exprs = new("matrix"), ...)
      {		 
          if (overwrite.missing&&  missing(assayData)) {
	# stuff ...
	}
	# other stuff ...
      }

	# call .local with overwrite.missing as its first argument
	do.call(.local, c(list(.Object, overwrite.missing), dotargs))
	
}

I think this would allow:

eset<- new('ExpressionSet', exprs=matrix(0,10,5))
new('ExpressionSet', eset) # simple copy constructor
new('ExpressionSet', eset, exprs=matrix(0,20,3)) # overwrite original exprs with the one given in argument
# etc... with other slots
# and the current behaviour should also work
new('ExpressionSet', assayData=assayData(eset), exprs=matrix(0,10,5))
# and initialize will still set the object to its prototype if directly called (which a behaviour one might not want to change as it could be use by other packages)
initialize(eset)


Thank you.
Renaud





On 15/12/2010 20:21, Martin Morgan wrote:
> On 12/15/2010 09:42 AM, Renaud Gaujoux wrote:
>> Hi,
>>
>> I am trying to extend class ExpressionSet in a very simple way to add an
>> extra slot.
>> Now suppose I have a valid ExpressionSet object, I want to create an
>> object of class 'A' as follows (this always worked with other S4 classes
>> I defined):
>>
>> library(Biobase)
>> setClass('A', representation(extraslot='list'), contains='ExpressionSet')
>> eset<- new('ExpressionSet')
>> new('A', eset)
>>
>> # this throws the error:
>> Error in function (classes, fdef, mtable)  :
>>    unable to find an inherited method for function
>> "annotatedDataFrameFrom", for signature "ExpressionSet"
>> #Note: this also does not work with a non-empty ExpressionSet object.
>>
>> Is this normal? Is there a specific way to extend the class ExpressionSet?
>> The classes I found that extend ExpressionSet add an extra element in
>> assayData, and from what I saw it requires defining an initialize method
>> to pass all the standard parameters to the underlying ExpressionSet
>> object (exprs, phenoData, featureData, etc...)
> Hi Renaud --
>
> This is an unfortunate consequence of the 'initialize' method that your
> class inherits from ExpressionSet. 'new' uses the prototype of 'A' to
> create .Object, and then passes .Object and other arguments to 'new'
> down to 'initialize'.  The 'initialize' method inherited from
> ExpressionSet is in part
>
>> head(selectMethod(initialize, 'A'))
> 1 structure(function (.Object, ...)
> 2 {
> 3     .local<- function (.Object, assayData, phenoData, featureData,
> 4         exprs = new("matrix"), ...)
> 5     {
> 6         if (missing(assayData)) {
>
> with .local invoked so as .local(.Object, ...) in the body of
> initialize. So your 'eset' is the seen as the second argument, and
> matches by position with the argument 'assayData'; this is not expected
> to be an ExpressionSet, and trouble ensues. In retrospect the 'right'
> signature for initialize,ExpressionSet-method would have placed the
> named arguments after ..., with the user needing to supply named
> assayData= etc arguments.
>
> An additional problem is that the initialize,ExpressionSet-method
> assumes that .Object is from its prototype, so for instance an exprs
> with non-zero dimensions is overwritten
>
>> eset<- new("ExpressionSet", exprs=matrix(0,10,5))
>> eset
> ExpressionSet (storageMode: lockedEnvironment)
> assayData: 10 features, 5 samples
>    element names: exprs
> protocolData: none
> phenoData: none
> featureData: none
> experimentData: use 'experimentData(object)'
> Annotation:
>> initialize(eset)
> ExpressionSet (storageMode: lockedEnvironment)
> assayData: 0 features, 0 samples
>    element names: exprs
> protocolData: none
> phenoData: none
> featureData: none
> experimentData: use 'experimentData(object)'
> Annotation:
>
> You're stuck working with the initialize,ExpressionSet-method as defined
> (changing it now would disrupt a lot of package and user code), probably
> the easiest way being to write an appropriate initialize method or,
> probably better given the pitfalls of doing this correctly, write a
> constructor that does what you want
>
> library(Biobase)
> setClass('A', representation(extraslot='list'),
>           contains='ExpressionSet',
>           prototype=prototype(extraslot=list(a=1:5)))
>
> setGeneric("A", function(x, ...) standardGeneric("A"))
> setMethod(A, "missing", function(x, ...) new("A", ...))
> setMethod(A, "ExpressionSet", function(x, ...) {
>      new("A", assayData=assayData(x), phenoData=phenoData(x),
>          featureData=featureData(x), ...)  ## protocalData here too?
> })
>
> ## test
> eset<- new('ExpressionSet', exprs=matrix(0, 10, 5))
> A(eset)
> A()
> A(eset)@extraslot
> A()@extraslot
> A(eset, extraslot=list(b=5:1))@extraslot
> A(extraslot=list(b=5:1))@extraslot
>
> Martin
>
>> Thank you for any insight on the matter.
>> Renaud
>>
>> sessionInfo:
>> R version 2.12.0 (2010-10-15)
>> Platform: x86_64-pc-linux-gnu (64-bit)
>>
>> locale:
>>   [1] LC_CTYPE=en_ZA.utf8       LC_NUMERIC=C LC_TIME=en_ZA.utf8
>> LC_COLLATE=en_ZA.utf8     LC_MONETARY=C       LC_MESSAGES=en_ZA.utf8
>> LC_PAPER=en_ZA.utf8
>>   [8] LC_NAME=C                 LC_ADDRESS=C              LC_TELEPHONE=C
>>             LC_MEASUREMENT=en_ZA.utf8 LC_IDENTIFICATION=C
>>
>> attached base packages:
>> [1] stats     graphics  grDevices utils     datasets  methods   base
>>
>> other attached packages:
>> [1] Biobase_2.8.0
>>
>>
>>
>>
>> ###
>> UNIVERSITY OF CAPE TOWN
>> This e-mail is subject to the UCT ICT policies and e-mai...{{dropped:5}}
>>
>> _______________________________________________
>> Bioconductor mailing list
>> Bioconductor at r-project.org
>> https://stat.ethz.ch/mailman/listinfo/bioconductor
>> Search the archives:
>> http://news.gmane.org/gmane.science.biology.informatics.conductor
>

 

###
UNIVERSITY OF CAPE TOWN 

This e-mail is subject to the UCT ICT policies and e-mai...{{dropped:5}}



More information about the Bioconductor mailing list