[Bioc-devel] Problem with S4 method dispatch: .. bug in methods package ? SummarizedExperiment, but not SingleCellExperiment
Martin Maechler
m@ech|er @end|ng |rom @t@t@m@th@ethz@ch
Sun Jan 26 08:51:17 CET 2025
>>>>> Axel Klenk
>>>>> on Thu, 23 Jan 2025 15:31:18 +0100 writes:
> Hi Martin and all,
>> In principle it should be reproducible with only base R
>> (incl methods package), not involving your given extra
>> packages; just using functions setClassUnion(), ... etc
>> from methods.
>>
>> Is that possible?
> Yes, it is -- but I found that in order to reproduce the
> issue I need to mimic the "original" constellation where
> class A and its subclass C are defined in some example
> package expkg and D, a subclass of C is defined in a
> dependent package depkg. Then a method defined for a
> class union U of class A and some other class B will be
> found for an object of class C (same package as A), but
> not one of class D (different package)... I have prepared
> two packages expkg and depkg on my GitHub to demonstrate
> this as follows:
> if(!requireNamespace("remotes", quietly = TRUE))
> install.packages("remotes")
> remotes::install_github(c("axelklenk/expkg",
> "axelklenk/depkg"))
> library("expkg") setClass("B") setClassUnion("U", c("A",
> "B")) setGeneric("Umethod", function(x)
> standardGeneric("Umethod")) setMethod("Umethod",
> signature="U", function(x) cat("Found Umethod!\n"))
> o <- new("C") Umethod(o) ## it works!!
> library("depkg") p <- new("D") Umethod(p) ## Error:
> unable to find an inherited method for function 'Umethod'
> for signature 'x = "D"'
> The packages contain nothing but the necessary setClass()
> and their respective NAMESPACE files are pretty simple.
> For expkg, the package defining superclasses A and C:
> exportClasses(A) exportClasses(C) import(methods)
> and for depkg, the package defining subclass D
> exportClasses(D) import(methods)
> importClassesFrom(expkg,A) importClassesFrom(expkg,C)
> I have studied WRE 1.5[.6] and added "Depends: methods¨ to
> the packages' DESCRIPTION files and "import(methods)" to
> their NAMESPACE files but that didn't seem to make a
> difference. Otherwise I didn't find any hints in WRE.
> Ah, and after running the code above, the inheritance
> relation between U and C is "known" as well as between A
> and D, but not between U and D:
>> getClass("C")
> Class "C" [package "expkg"]
> No Slots, prototype of class "S4"
> Extends: Class "A", directly Class "U", by class "A",
> distance 2
>> getClass("D")
> Class "D" [package "depkg"]
> No Slots, prototype of class "S4"
> Extends: Class "C", directly Class "A", by class "C",
> distance 2
>> getClass("U")
> Extended class definition ( "ClassUnionRepresentation" )
> Virtual Class "U" [in ".GlobalEnv"]
> No Slots, prototype of class "C"
> Known Subclasses: Class "A", directly Class "B", directly
> Class "C", by class "A", distance 2
> Now, does that look like a bug in the methods package or
> rather like 'some "unhappy coincidence" in how the
> involved packages interact there'? I have no idea how to
> tell -- and therefore will follow this advice:
>> Otherwise, yes, do as you are advised, i.e. -->
>> https://www.r-project.org/bugs.html and apply for an R
>> bugzilla account.
Thanks a lot, Axel, for your reproducible example.
and so, as I am also one of the recipients of the R bugzilla applications,
I was wondering why we have not yet received yours ...
> Thanks to all for your help so far and any additional
> advice,
> - axel
Indeed, notably thanks for your own help by reducing the example!
Ideally your packages could become even much smaller (to be
added to a test suite in the future):
- no LICENSE, README.md nor man/
- no 'Depends:' in DESCRIPTION, only 'Imports: methods'
- in NAMESPACE, wrt methods, you'd only have
importFrom(methods, setClass)
Best,
Martin
> Am Mi., 15. Jan. 2025 um 09:08 Uhr schrieb Martin Maechler
> <maechler using stat.math.ethz.ch>:
>>
>> >>>>> Axel Klenk >>>>> on Sat, 11 Jan 2025 01:16:49 +0100
>> writes:
>>
>> > Hi Hervé, Kasper, Helena and all, > and thanks a lot
>> for your replies!
>>
>> > First of all, if this is a bug in the methods package,
>> I'd of course > volunteer to report it -- sounds like a
>> great learning opportunity > for the New Year. ;-)
>>
>> As an R corer with special interest in S4/ methods, I had
>> wanted to chime in earlier: Yes, _if this is a bug in the
>> methods package_
>>
>> In principle it should be reproducible with only base R
>> (incl methods package), not involving your given extra
>> packages; just using functions setClassUnion(), ... etc
>> from methods.
>>
>> Is that possible?
>>
>> Of course, it might be that it is related to the use of
>>
>> ImportClassesFrom(), ImportMethodsFrom(), ExportClasses()
>> ...
>>
>> directives in the involved packages' NAMESPACE files, and
>> some "unhappy coincidence" in how the involved packages
>> interact there .. but probably Hervé or you have already
>> looked into these.
>>
>> Otherwise, yes, do as you are advised, i.e. -->
>> https://www.r-project.org/bugs.html and apply for an R
>> bugzilla account.
>>
>> Best, Martin
>>
>>
>> > In my original message I tried to focus on the error
>> and provided only > the code necessary to reproduce it
>> but of course I'm happy > to provide more background and
>> receive advice on design and maintainability.
>>
>> > The reason for class unions was the need to store any
>> user-provided > data container in a slot of GSVA's
>> parameter objects when > those were introduced.
>> (Actually there is one for data > matrices/containers and
>> another one for gene sets in lists or >
>> GSEABase::GeneSetCollection.) As you seem to be a bit
>> reluctant to > use class unions, is there a good way to
>> avoid them as > the slot class in this case?
>>
>> > Once the class union existed, methods on the union were
>> added to avoid > long functions with unwieldy if/else
>> constructs, as the > number of supported containers is
>> growing. However, so far there are > only two actual use
>> cases for methods on class unions: > (1) the (containing)
>> parameter object's show() method that includes > output
>> from show() methods of the (contained) data objects, >
>> with more specialized methods only required for matrix
>> and dgCMatrix > that otherwise show() all of their
>> content, and > (2) some method for extracting a
>> matrix-like data object from a data > container --
>> assay() for SummarizedExperiment and derivatives, >
>> exprs() for ExpressionSet, the object itself for
>> matrix/dgCMatrix.
>>
>> > So, we are actually starting from the class unions
>> rather than the > methods that could be replaced the way
>> Hervé suggested. > The methods are just where the error
>> message happened to appear and I > was not sure if this
>> was caused by a bug or not expected > to work at all or a
>> known issue requiring some special measures or ...
>>
>> > By the way, in the meantime we have been experimenting
>> with the mock > example below -- which works as
>> expected?!?
>>
>> > setClass("A") ## this would be like 'dgCMatrix' >
>> setClass("B") ## this would be like
>> 'SummarizedExperiment' > setClass("C", contains="B") ##
>> this would be like 'SingleCellExperiment' >
>> setClassUnion("U", c("A", "B")) > setGeneric("Umethod",
>> function(x) standardGeneric("Umethod")) >
>> setMethod("Umethod", signature="U", function(x)
>> cat("Umethod!\n")) > o <- new("C") > Umethod(o) ## it
>> works!!
>>
>> > Thanks in advance for your support and suggestions,
>>
>> > - axel
>>
>>
>> > Am Fr., 10. Jan. 2025 um 18:17 Uhr schrieb Kasper
>> Daniel Hansen > <kasperdanielhansen using gmail.com>:
>> >>
>> >> In my experience, class unions are hard to work with
>> and quickly get out of hand. I don't really understand
>> what you actually want to do, beyond defining a class
>> union. My impression is that your main goal is to write
>> simplified code. I could be wrong, but I doubt class
>> unions is the best way to solve your problem. What you
>> really need is that these classes share a common API in
>> that you can do stuff like >> assay() >> on them. Either
>> this common API already exists or it does not. It it
>> already exists, there is - as far as I can tell - no
>> gains from the class union. If it does not exist, you
>> still need to write class specific code to get the API
>> working.
>> >>
>> >> Like Herve, I suggest not starting with a method. I
>> find that too many developers are too quick to reach for
>> methods.
>> >>
>> >> We might be able to give you more useful feedback and
>> help if you can tell us more precisely what you want to
>> do.
>> >>
>> >> Best, >> Kasper
>> >>
>> >>
>> >> On Thu, Jan 9, 2025 at 2:38 PM Hervé Pagès
>> <hpages.on.github using gmail.com> wrote:
>> >>>
>> >>> Looks like a bug in the methods package to me.
>> >>>
>> >>> The extends() relationship looks transitive, as it
>> should be:
>> >>>
>> >>> > extends("SingleCellExperiment",
>> "SummarizedExperiment") >>> [1] TRUE >>> >
>> is(new("SingleCellExperiment"), "ExpData") >>> [1] TRUE
>> >>> > extends("SingleCellExperiment", "ExpData") >>> [1]
>> TRUE
>> >>>
>> >>> Also is() is doing the right thing as Helena pointed
>> out:
>> >>>
>> >>> > is(new("SingleCellExperiment"), "ExpData") >>> [1]
>> TRUE
>> >>>
>> >>> However, when using the single-arg form of extends()
>> to list all the >>> ancestor classes, ExpData is no
>> longer seen as an ancestor of >>> SingleCellExperiment:
>> >>>
>> >>> > extends("SummarizedExperiment") >>> [1]
>> "SummarizedExperiment" "RectangularData" "Vector" >>> [4]
>> "ExpData" "Annotated" "vector_OR_Vector"
>> >>>
>> >>> > extends("SingleCellExperiment") >>> [1]
>> "SingleCellExperiment" "RangedSummarizedExperiment" >>>
>> [3] "SummarizedExperiment" "RectangularData" >>> [5]
>> "Vector" "Annotated" >>> [7] "vector_OR_Vector"
>> >>>
>> >>> Same problem with selectSuperClasses(), which is an
>> other way to list >>> all the ancestors of a given class:
>> >>>
>> >>> > selectSuperClasses("SummarizedExperiment",
>> directOnly=FALSE) >>> [1] "RectangularData" "Vector"
>> "ExpData" "Annotated" >>> [5] "vector_OR_Vector"
>> >>>
>> >>> > selectSuperClasses("SingleCellExperiment",
>> directOnly=FALSE) >>> [1] "RangedSummarizedExperiment"
>> "SummarizedExperiment" >>> [3] "RectangularData" "Vector"
>> >>> [5] "Annotated" "vector_OR_Vector"
>> >>>
>> >>> And same problem when trying to retrieve this list
>> directly from the >>> 'contains' slot of the class
>> definitions:
>> >>>
>> >>> > names(getClass("SummarizedExperiment")@contains)
>> >>> [1] "RectangularData" "Vector" "ExpData" "Annotated"
>> >>> [5] "vector_OR_Vector"
>> >>>
>> >>> >
>> names(getClass("RangedSummarizedExperiment")@contains)
>> >>> [1] "SummarizedExperiment" "RectangularData" "Vector"
>> >>> [4] "ExpData" "Annotated" "vector_OR_Vector"
>> >>>
>> >>> > names(getClass("SingleCellExperiment")@contains)
>> >>> [1] "RangedSummarizedExperiment"
>> "SummarizedExperiment" >>> [3] "RectangularData" "Vector"
>> >>> [5] "Annotated" "vector_OR_Vector"
>> >>>
>> >>> Any volunteer to report this to the methods
>> maintainer? (via the R bug >>> tracker)
>> >>>
>> >>> Anyways, not sure exactly what methods you're
>> planning to implement for >>> ExpData derivatives. Have
>> you considered doing something like this instead:
>> >>>
>> >>> .check_expdata <- function(expdata) >>> { >>> ok <-
>> is.matrix(expdata) || >>> is(expdata, "dgCMatrix") || >>>
>> is(expdata, "ExpressionSet") || >>> is(expdata,
>> "SummarizedExperiment") >>> if (!ok) stop("'expdata' must
>> be a matrix or dgCMatrix or ", >>> "ExpressionSet or
>> SummarizedExperiment derivative") >>> }
>> >>>
>> >>> foo <- function(expdata) >>> { >>>
>> .check_expdata(expdata) >>> ... >>> ... >>> }
>> >>>
>> >>> Personally I find that using a union and method
>> dispatch for this is a >>> little bit overkill.
>> >>>
>> >>> Best,
>> >>>
>> >>> H.
>> >>>
>> >>>
>> >>> On 1/8/25 05:35, Helena L. Crowell wrote: >>> > Ui,
>> my bad, messed up my environment… Indeed, I think what
>> you had in mind doesn’t work. My guess is that the class
>> union is “strict” in that method dispatch doesn’t just
>> propagate to classes that inherit from what’s in the
>> union.
>> >>> >
>> >>> > Anything against something like … which should
>> definitely work (I think):
>> >>> >
>> >>> > setClassUnion("ExpData", c( >>> > "matrix",
>> "dgCMatrix", "ExpressionSet", >>> >
>> "SingleCellExperiment", "SummarizedExperiment”))
>> >>> >
>> >>> > What’s really weird imo is that is(se, "ExpData”)
>> and is(sce, "ExpData”) both return TRUE, but still the
>> SCE method can’t be found? >>> > Maybe someone else has
>> more insights, sorry!!
>> >>> >
>> >>> >> On Jan 8, 2025, at 14:11, Axel Klenk
>> <axel.klenk using gmail.com> wrote:
>> >>> >>
>> >>> >> Hi Helena,
>> >>> >>
>> >>> >> thanks for your reply. Unfortunately it doesn't
>> work for me -- when >>> >> copy+paste'ing your code >>>
>> >> the error now occurs for SummarizedExperiment
>> (transcript below, >>> >> including session info >>> >>
>> that I had forgotten yesterday).
>> >>> >>
>> >>> >> In the current version of GSVA the class union
>> contains all of SE, SCE >>> >> and SPE and we >>> >>
>> still need to define all methods for all of them which
>> doesn't feel >>> >> right... but I must be doing >>> >>
>> something wrong.
>> >>> >>
>> >>> >> Any ideas?
>> >>> >>
>> >>> >> Cheers,
>> >>> >>
>> >>> >> - axel
>> >>> >>
>> >>> >>
>> >>> >>> library("Matrix") >>> >>> library("Biobase") >>>
>> >> Loading required package: BiocGenerics
>> >>> >>
>> >>> >> Attaching package: 'BiocGenerics'
>> >>> >>
>> >>> >> The following objects are masked from
>> 'package:stats':
>> >>> >>
>> >>> >> IQR, mad, sd, var, xtabs
>> >>> >>
>> >>> >> The following objects are masked from
>> 'package:base':
>> >>> >>
>> >>> >> anyDuplicated, aperm, append, as.data.frame,
>> basename, cbind, >>> >> colnames, dirname, do.call,
>> duplicated, eval, evalq, Filter, Find, >>> >> get, grep,
>> grepl, intersect, is.unsorted, lapply, Map, mapply, >>>
>> >> match, mget, order, paste, pmax, pmax.int, pmin,
>> pmin.int, >>> >> Position, rank, rbind, Reduce, rownames,
>> sapply, saveRDS, setdiff, >>> >> table, tapply, union,
>> unique, unsplit, which.max, which.min
>> >>> >>
>> >>> >> Welcome to Bioconductor
>> >>> >>
>> >>> >> Vignettes contain introductory material; view with
>> >>> >> 'browseVignettes()'. To cite Bioconductor, see >>>
>> >> 'citation("Biobase")', and for packages
>> 'citation("pkgname")'.
>> >>> >>
>> >>> >>> library("SummarizedExperiment") >>> >> Loading
>> required package: MatrixGenerics >>> >> Loading required
>> package: matrixStats
>> >>> >>
>> >>> >> Attaching package: 'matrixStats'
>> >>> >>
>> >>> >> The following objects are masked from
>> 'package:Biobase':
>> >>> >>
>> >>> >> anyMissing, rowMedians
>> >>> >>
>> >>> >>
>> >>> >> Attaching package: 'MatrixGenerics'
>> >>> >>
>> >>> >> The following objects are masked from
>> 'package:matrixStats':
>> >>> >>
>> >>> >> colAlls, colAnyNAs, colAnys, colAvgsPerRowSet,
>> colCollapse, >>> >> colCounts, colCummaxs, colCummins,
>> colCumprods, colCumsums, >>> >> colDiffs, colIQRDiffs,
>> colIQRs, colLogSumExps, colMadDiffs, >>> >> colMads,
>> colMaxs, colMeans2, colMedians, colMins, colOrderStats,
>> >>> >> colProds, colQuantiles, colRanges, colRanks,
>> colSdDiffs, colSds, >>> >> colSums2, colTabulates,
>> colVarDiffs, colVars, colWeightedMads, >>> >>
>> colWeightedMeans, colWeightedMedians, colWeightedSds, >>>
>> >> colWeightedVars, rowAlls, rowAnyNAs, rowAnys,
>> rowAvgsPerColSet, >>> >> rowCollapse, rowCounts,
>> rowCummaxs, rowCummins, rowCumprods, >>> >> rowCumsums,
>> rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps, >>> >>
>> rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians,
>> rowMins, >>> >> rowOrderStats, rowProds, rowQuantiles,
>> rowRanges, rowRanks, >>> >> rowSdDiffs, rowSds, rowSums2,
>> rowTabulates, rowVarDiffs, rowVars, >>> >>
>> rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
>> >>> >> rowWeightedSds, rowWeightedVars
>> >>> >>
>> >>> >> The following object is masked from
>> 'package:Biobase':
>> >>> >>
>> >>> >> rowMedians
>> >>> >>
>> >>> >> Loading required package: GenomicRanges >>> >>
>> Loading required package: stats4 >>> >> Loading required
>> package: S4Vectors
>> >>> >>
>> >>> >> Attaching package: 'S4Vectors'
>> >>> >>
>> >>> >> The following objects are masked from
>> 'package:Matrix':
>> >>> >>
>> >>> >> expand, unname
>> >>> >>
>> >>> >> The following object is masked from
>> 'package:utils':
>> >>> >>
>> >>> >> findMatches
>> >>> >>
>> >>> >> The following objects are masked from
>> 'package:base':
>> >>> >>
>> >>> >> expand.grid, I, unname
>> >>> >>
>> >>> >> Loading required package: IRanges >>> >> Loading
>> required package: GenomeInfoDb >>> >>>
>> library("SingleCellExperiment") >>> >>>
>> setClassUnion("ExpData", c("matrix", "dgCMatrix", >>> >>
>> + "ExpressionSet", "SingleCellExperiment")) >>> >>>
>> setGeneric("expShow", \(.) standardGeneric("expShow"))
>> >>> >> [1] "expShow" >>> >>> setMethod("expShow",
>> "ExpData", \(.) show(.)) >>> >>> p <- 10 >>> >>> n <- 30
>> >>> >>> y <- matrix(rnorm(n*p), nrow=p, ncol=n, >>> >> +
>> dimnames=list( >>> >> + paste("g", 1:p, sep="") , >>> >>
>> + paste("s", 1:n, sep=""))) >>> >>> se <-
>> SummarizedExperiment(y) >>> >>> sce <-
>> SingleCellExperiment(y) >>> >>> expShow(se) >>> >> Error:
>> unable to find an inherited method for function 'expShow'
>> for >>> >> signature '. = "SummarizedExperiment"' >>> >>>
>> expShow(sce) >>> >> class: SingleCellExperiment >>> >>
>> dim: 10 30 >>> >> metadata(0): >>> >> assays(1): '' >>>
>> >> rownames(10): g1 g2 ... g9 g10 >>> >> rowData
>> names(0): >>> >> colnames(30): s1 s2 ... s29 s30 >>> >>
>> colData names(0): >>> >> reducedDimNames(0): >>> >>
>> mainExpName: NULL >>> >> altExpNames(0):
>> >>> >>>
>> >>> >>>
>> >>> >>> sessionInfo() >>> >> R version 4.4.2 (2024-10-31)
>> >>> >> Platform: x86_64-pc-linux-gnu >>> >> Running
>> under: Ubuntu 20.04.6 LTS
>> >>> >>
>> >>> >> Matrix products: default >>> >> BLAS:
>> /home/axel/R/local/R-4.4.2/lib/libRblas.so >>> >> LAPACK:
>> /home/axel/R/local/R-4.4.2/lib/libRlapack.so; LAPACK
>> version 3.12.0
>> >>> >>
>> >>> >> locale: >>> >> [1] LC_CTYPE=en_US.UTF-8
>> LC_NUMERIC=C >>> >> [3] LC_TIME=es_ES.UTF-8
>> LC_COLLATE=en_US.UTF-8 >>> >> [5] LC_MONETARY=es_ES.UTF-8
>> LC_MESSAGES=en_US.UTF-8 >>> >> [7] LC_PAPER=es_ES.UTF-8
>> LC_NAME=C >>> >> [9] LC_ADDRESS=C LC_TELEPHONE=C >>> >>
>> [11] LC_MEASUREMENT=es_ES.UTF-8 LC_IDENTIFICATION=C
>> >>> >>
>> >>> >> time zone: Europe/Madrid >>> >> tzcode source:
>> system (glibc)
>> >>> >>
>> >>> >> attached base packages: >>> >> [1] stats4 stats
>> graphics grDevices utils datasets methods >>> >> [8] base
>> >>> >>
>> >>> >> other attached packages: >>> >> [1]
>> SingleCellExperiment_1.28.1 SummarizedExperiment_1.36.0
>> >>> >> [3] GenomicRanges_1.58.0 GenomeInfoDb_1.42.1 >>>
>> >> [5] IRanges_2.40.1 S4Vectors_0.44.0 >>> >> [7]
>> MatrixGenerics_1.18.0 matrixStats_1.5.0 >>> >> [9]
>> Biobase_2.66.0 BiocGenerics_0.52.0 >>> >> [11]
>> Matrix_1.7-1
>> >>> >>
>> >>> >> loaded via a namespace (and not attached): >>> >>
>> [1] R6_2.5.1 SparseArray_1.6.0 zlibbioc_1.52.0 >>> >> [4]
>> lattice_0.22-6 abind_1.4-8 GenomeInfoDbData_1.2.13 >>> >>
>> [7] S4Arrays_1.6.0 XVector_0.46.0 UCSC.utils_1.2.0 >>> >>
>> [10] fortunes_1.5-4 grid_4.4.2 DelayedArray_0.32.0 >>> >>
>> [13] compiler_4.4.2 httr_1.4.7 tools_4.4.2 >>> >> [16]
>> crayon_1.5.3 jsonlite_1.8.9
>> >>> >>
>> >>> >> Am Mi., 8. Jan. 2025 um 13:41 Uhr schrieb Helena
>> L. Crowell <helena using crowell.eu>: >>> >>> SCE inherits from
>> SE, but not vice versa. So setting the class union on SCE
>> (not SE) will do the trick. Briefly, Anything defined on
>> an SCE will work upstream (SE), but anything defined on
>> SE will not work downstream (SPE, SCE).
>> >>> >>>
>> >>> >>> ***
>> >>> >>>
>> >>> >>> This works:
>> >>> >>>
>> >>> >>> library("Matrix") >>> >>> library("Biobase") >>>
>> >>> library("SummarizedExperiment") >>> >>>
>> library("SingleCellExperiment")
>> >>> >>>
>> >>> >>> setClassUnion("ExpData", c("matrix", "dgCMatrix",
>> >>> >>> "ExpressionSet", "SingleCellExperiment"))
>> >>> >>>
>> >>> >>> setGeneric("expShow", \(.)
>> standardGeneric("expShow")) >>> >>> setMethod("expShow",
>> "ExpData", \(.) show(.))
>> >>> >>>
>> >>> >>> p <- 10 >>> >>> n <- 30 >>> >>> y <-
>> matrix(rnorm(n*p), nrow=p, ncol=n, >>> >>> dimnames=list(
>> >>> >>> paste("g", 1:p, sep="") , >>> >>> paste("s", 1:n,
>> sep="")))
>> >>> >>>
>> >>> >>> se <- SummarizedExperiment(y) >>> >>> sce <-
>> SingleCellExperiment(y)
>> >>> >>>
>> >>> >>> expShow(se) >>> >>> expShow(sce)
>> >>> >>>
>> >>> >>>> On Jan 7, 2025, at 21:33, Axel Klenk
>> <axel.klenk using gmail.com> wrote:
>> >>> >>>>
>> >>> >>>> Dear Community, dear S4 Experts,
>> >>> >>>>
>> >>> >>>> in the GSVA package I want to use an S4 class
>> union as a superclass >>> >>>> for all supported data
>> containers and S4 methods >>> >>>> defined for this
>> superclass, rather than for each subclass, where a >>>
>> >>>> class-specific implementation is not necessary. In
>> particular >>> >>>> I want to avoid having to implement
>> individual methods for all current >>> >>>> (and
>> possibly, future) subclasses of SummarizedExperiment >>>
>> >>>> for common operations like accessing assay names and
>> dimensions, assay >>> >>>> data, etc.
>> >>> >>>>
>> >>> >>>> As you can see from the example code and output
>> below, this works as >>> >>>> expected for
>> SummarizedExperiment objects but not >>> >>>> for its
>> subclasses such as SingleCellExperiment or
>> SpatialExperiment >>> >>>> (if SummarizedExperiment is
>> part of the class union and >>> >>>> the others are not).
>> In the latter case the result is "Error: unable >>> >>>>
>> to find an inherited method for function ..." (please see
>> below).
>> >>> >>>>
>> >>> >>>> I'd be very grateful if someone with more S4
>> expertise than myself >>> >>>> could please let me know
>> if and how this can be solved -- or >>> >>>> if the whole
>> thing is not a good idea at all. ;-)
>> >>> >>>>
>> >>> >>>> Thanks a lot,
>> >>> >>>>
>> >>> >>>> - axel
>> >>> >>>>
>> >>> >>>>
>> >>> >>>>
>> >>> >>>> ### define a class union as a common superclass
>> >>> >>>> library("Matrix") >>> >>>> library("Biobase")
>> >>> >>>> library("SummarizedExperiment") >>> >>>>
>> library("SingleCellExperiment") >>> >>>> ## [package
>> startup messages omitted]
>> >>> >>>>
>> >>> >>>> setClassUnion("ExpData", >>> >>>> c("matrix",
>> "dgCMatrix", "ExpressionSet", "SummarizedExperiment"))
>> >>> >>>>
>> >>> >>>> ### ... and an example method for the superclass
>> >>> >>>> setGeneric("expShow", function(object)
>> standardGeneric("expShow")) >>> >>>> setMethod("expShow",
>> >>> >>>> signature=signature(object="ExpData"), >>> >>>>
>> function(object) { >>> >>>> show(object) >>> >>>> })
>> >>> >>>>
>> >>> >>>> ### generate some example data and test the
>> method: >>> >>>> p <- 10 >>> >>>> n <- 30 >>> >>>> y <-
>> matrix(rnorm(n*p), nrow=p, ncol=n, >>> >>>>
>> dimnames=list(paste("g", 1:p, sep="") , paste("s", 1:n,
>> sep="")))
>> >>> >>>>
>> >>> >>>> se <- SummarizedExperiment(y) >>> >>>> show(se)
>> >>> >>>> ## class: SummarizedExperiment >>> >>>> ## dim:
>> 10 30 >>> >>>> ## metadata(0): >>> >>>> ## assays(1): ''
>> >>> >>>> ## rownames(10): g1 g2 ... g9 g10 >>> >>>> ##
>> rowData names(0): >>> >>>> ## colnames(30): s1 s2 ... s29
>> s30 >>> >>>> ## colData names(0):
>> >>> >>>>
>> >>> >>>> expShow(se) >>> >>>> ## class:
>> SummarizedExperiment >>> >>>> ## dim: 10 30 >>> >>>> ##
>> metadata(0): >>> >>>> ## assays(1): '' >>> >>>> ##
>> rownames(10): g1 g2 ... g9 g10 >>> >>>> ## rowData
>> names(0): >>> >>>> ## colnames(30): s1 s2 ... s29 s30 >>>
>> >>>> ## colData names(0):
>> >>> >>>>
>> >>> >>>> sce <- SingleCellExperiment(y) >>> >>>>
>> show(sce) >>> >>>> ## class: SingleCellExperiment >>>
>> >>>> ## dim: 10 30 >>> >>>> ## metadata(0): >>> >>>> ##
>> assays(1): '' >>> >>>> ## rownames(10): g1 g2 ... g9 g10
>> >>> >>>> ## rowData names(0): >>> >>>> ## colnames(30):
>> s1 s2 ... s29 s30 >>> >>>> ## colData names(0): >>> >>>>
>> ## reducedDimNames(0): >>> >>>> ## mainExpName: NULL >>>
>> >>>> ## altExpNames(0):
>> >>> >>>>
>> >>> >>>> expShow(sce) >>> >>>> ## Error: unable to find
>> an inherited method for function 'expShow' >>> >>>> for
>> signature 'object = "SingleCellExperiment"'
>> >>> >>>>
>> >>> >>>> ### ### ###
>> >>> >>>>
>> >>> >>>> ## we can define a new subclass of
>> SummarizedExperiment in the global >>> >>>> environment
>> that works -- as >>> >>>> ## long as it is not coerced to
>> SingleCellExperiment
>> >>> >>>>
>> >>> >>>> setClass("expA", >>> >>>>
>> contains="RangedSummarizedExperiment")
>> >>> >>>>
>> >>> >>>> ea <- new("expA") >>> >>>> show(ea) >>> >>>> ##
>> An object of class "expA" >>> >>>> ## Slot "rowRanges":
>> >>> >>>> ## GRanges object with 0 ranges and 0 metadata
>> columns: >>> >>>> ## seqnames ranges strand >>> >>>> ##
>> <Rle> <IRanges> <Rle>
>> >>> >>>> ## -------
>> >>> >>>> ## seqinfo: no sequences
>> >>> >>>> ##
>> >>> >>>> ## Slot "colData": >>> >>>> ## DataFrame with 0
>> rows and 0 columns
>> >>> >>>> ##
>> >>> >>>> ## Slot "assays": >>> >>>> ## NULL
>> >>> >>>> ##
>> >>> >>>> ## Slot "NAMES": >>> >>>> ## NULL
>> >>> >>>> ##
>> >>> >>>> ## Slot "elementMetadata": >>> >>>> ## DataFrame
>> with 0 rows and 0 columns
>> >>> >>>> ##
>> >>> >>>> ## Slot "metadata": >>> >>>> ## list()
>> >>> >>>>
>> >>> >>>> expShow(ea) >>> >>>> ## class:
>> SummarizedExperiment >>> >>>> ## dim: 0 0 >>> >>>> ##
>> metadata(0): >>> >>>> ## assays(0): >>> >>>> ## rownames:
>> NULL >>> >>>> ## rowData names(0): >>> >>>> ## colnames:
>> NULL >>> >>>> ## colData names(0):
>> >>> >>>>
>> >>> >>>> scea <- as(ea, "SingleCellExperiment") >>> >>>>
>> show(scea) >>> >>>> ## class: SingleCellExperiment >>>
>> >>>> ## dim: 0 0 >>> >>>> ## metadata(0): >>> >>>> ##
>> assays(0): >>> >>>> ## rownames: NULL >>> >>>> ## rowData
>> names(0): >>> >>>> ## colnames: NULL >>> >>>> ## colData
>> names(0): >>> >>>> ## reducedDimNames(0): >>> >>>> ##
>> mainExpName: NULL >>> >>>> ## altExpNames(0):
>> >>> >>>>
>> >>> >>>> expShow(scea) >>> >>>> ## Error: unable to find
>> an inherited method for function 'expShow' >>> >>>> for
>> signature 'object = "SingleCellExperiment"'
>> >>> >>>>
>> >>> >>>> ### ### ### ### ###
>> >>> >>>>
>> >>> >>>> ## as shown below, SummarizedExperiment and
>> ExpData "know" about their >>> >>>> inheritance relation
>> but >>> >>>> ## SingleCellExperiment does not...
>> >>> >>>>
>> >>> >>>> getClass("SummarizedExperiment") >>> >>>> ##
>> Class "SummarizedExperiment" [package
>> "SummarizedExperiment"]
>> >>> >>>> ##
>> >>> >>>> ## Slots:
>> >>> >>>> ##
>> >>> >>>> ## Name: colData assays NAMES >>> >>>>
>> elementMetadata metadata >>> >>>> ## Class: DataFrame
>> Assays_OR_NULL character_OR_NULL >>> >>>> DataFrame list
>> >>> >>>> ##
>> >>> >>>> ## Extends: >>> >>>> ## Class "RectangularData",
>> directly >>> >>>> ## Class "Vector", directly >>> >>>> ##
>> Class "ExpData", directly >>> >>>> ## Class "Annotated",
>> by class "Vector", distance 2 >>> >>>> ## Class
>> "vector_OR_Vector", by class "Vector", distance 2
>> >>> >>>> ##
>> >>> >>>> ## Known Subclasses: >>> >>>> ## Class
>> "RangedSummarizedExperiment", directly, with explicit
>> coerce
>> >>> >>>>
>> >>> >>>> getClass("ExpData") >>> >>>> ## Extended class
>> definition ( "ClassUnionRepresentation" ) >>> >>>> ##
>> Virtual Class "ExpData" [in ".GlobalEnv"]
>> >>> >>>> ##
>> >>> >>>> ## No Slots, prototype of class "matrix"
>> >>> >>>> ##
>> >>> >>>> ## Known Subclasses: >>> >>>> ## Class "matrix",
>> directly >>> >>>> ## Class "dgCMatrix", directly >>> >>>>
>> ## Class "ExpressionSet", directly >>> >>>> ## Class
>> "SummarizedExperiment", directly >>> >>>> ## Class "mts",
>> by class "matrix", distance 2 >>> >>>> ## Class
>> "RangedSummarizedExperiment", by class >>> >>>>
>> "SummarizedExperiment", distance 2, with explicit coerce
>> >>> >>>>
>> >>> >>>> getClass("SingleCellExperiment") >>> >>>> ##
>> Class "SingleCellExperiment" [package
>> "SingleCellExperiment"]
>> >>> >>>> ##
>> >>> >>>> ## Slots:
>> >>> >>>> ##
>> >>> >>>> ## Name: int_elementMetadata int_colData >>>
>> >>>> int_metadata >>> >>>> ## Class: DataFrame DataFrame
>> >>> >>>> list
>> >>> >>>> ##
>> >>> >>>> ## Name: rowRanges colData >>> >>>> assays >>>
>> >>>> ## Class: GenomicRanges_OR_GRangesList DataFrame >>>
>> >>>> Assays_OR_NULL
>> >>> >>>> ##
>> >>> >>>> ## Name: NAMES elementMetadata >>> >>>> metadata
>> >>> >>>> ## Class: character_OR_NULL DataFrame >>> >>>>
>> list
>> >>> >>>> ##
>> >>> >>>> ## Extends: >>> >>>> ## Class
>> "RangedSummarizedExperiment", directly >>> >>>> ## Class
>> "SummarizedExperiment", by class >>> >>>>
>> "RangedSummarizedExperiment", distance 2 >>> >>>> ##
>> Class "RectangularData", by class
>> "RangedSummarizedExperiment", distance 3 >>> >>>> ##
>> Class "Vector", by class "RangedSummarizedExperiment",
>> distance 3 >>> >>>> ## Class "Annotated", by class
>> "RangedSummarizedExperiment", distance 4 >>> >>>> ##
>> Class "vector_OR_Vector", by class
>> "RangedSummarizedExperiment", distance 4
>> >>> >>>>
>> >>> >>>> ### ### ### ### ###
>> >>> >>>>
>> >>> >>>> getClass("SummarizedExperiment") >>> >>>> ##
>> Class "SummarizedExperiment" [package
>> "SummarizedExperiment"]
>> >>> >>>> ##
>> >>> >>>> ## Slots:
>> >>> >>>> ##
>> >>> >>>> ## Name: colData assays NAMES >>> >>>>
>> elementMetadata metadata >>> >>>> ## Class: DataFrame
>> Assays_OR_NULL character_OR_NULL >>> >>>> DataFrame list
>> >>> >>>> ##
>> >>> >>>> ## Extends: >>> >>>> ## Class "RectangularData",
>> directly >>> >>>> ## Class "Vector", directly >>> >>>> ##
>> Class "ExpData", directly >>> >>>> ## Class "Annotated",
>> by class "Vector", distance 2 >>> >>>> ## Class
>> "vector_OR_Vector", by class "Vector", distance 2
>> >>> >>>> ##
>> >>> >>>> ## Known Subclasses: >>> >>>> ## Class
>> "RangedSummarizedExperiment", directly, with explicit
>> coerce >>> >>>> ## Class "expA", by class
>> "RangedSummarizedExperiment", distance 2, >>> >>>> with
>> explicit coerce
>> >>> >>>>
>> >>> >>>> getClass("expA") >>> >>>> ## Class "expA" [in
>> ".GlobalEnv"]
>> >>> >>>> ##
>> >>> >>>> ## Slots:
>> >>> >>>> ##
>> >>> >>>> ## Name: rowRanges colData >>> >>>> assays >>>
>> >>>> ## Class: GenomicRanges_OR_GRangesList DataFrame >>>
>> >>>> Assays_OR_NULL
>> >>> >>>> ##
>> >>> >>>> ## Name: NAMES elementMetadata >>> >>>> metadata
>> >>> >>>> ## Class: character_OR_NULL DataFrame >>> >>>>
>> list
>> >>> >>>> ##
>> >>> >>>> ## Extends: >>> >>>> ## Class
>> "RangedSummarizedExperiment", directly >>> >>>> ## Class
>> "SummarizedExperiment", by class >>> >>>>
>> "RangedSummarizedExperiment", distance 2, with explicit
>> coerce >>> >>>> ## Class "RectangularData", by class
>> "RangedSummarizedExperiment", distance 3 >>> >>>> ##
>> Class "Vector", by class "RangedSummarizedExperiment",
>> distance 3 >>> >>>> ## Class "ExpData", by class
>> "RangedSummarizedExperiment", distance 3, >>> >>>> with
>> explicit coerce >>> >>>> ## Class "Annotated", by class
>> "RangedSummarizedExperiment", distance 4 >>> >>>> ##
>> Class "vector_OR_Vector", by class
>> "RangedSummarizedExperiment", distance 4
>> >>> >>>>
>> >>> >>>> getClass("SingleCellExperiment") >>> >>>> ##
>> Class "SingleCellExperiment" [package
>> "SingleCellExperiment"]
>> >>> >>>> ##
>> >>> >>>> ## Slots:
>> >>> >>>> ##
>> >>> >>>> ## Name: int_elementMetadata int_colData >>>
>> >>>> int_metadata >>> >>>> ## Class: DataFrame DataFrame
>> >>> >>>> list
>> >>> >>>> ##
>> >>> >>>> ## Name: rowRanges colData >>> >>>> assays >>>
>> >>>> ## Class: GenomicRanges_OR_GRangesList DataFrame >>>
>> >>>> Assays_OR_NULL
>> >>> >>>> ##
>> >>> >>>> ## Name: NAMES elementMetadata >>> >>>> metadata
>> >>> >>>> ## Class: character_OR_NULL DataFrame >>> >>>>
>> list
>> >>> >>>> ##
>> >>> >>>> ## Extends: >>> >>>> ## Class
>> "RangedSummarizedExperiment", directly >>> >>>> ## Class
>> "SummarizedExperiment", by class >>> >>>>
>> "RangedSummarizedExperiment", distance 2 >>> >>>> ##
>> Class "RectangularData", by class
>> "RangedSummarizedExperiment", distance 3 >>> >>>> ##
>> Class "Vector", by class "RangedSummarizedExperiment",
>> distance 3 >>> >>>> ## Class "Annotated", by class
>> "RangedSummarizedExperiment", distance 4 >>> >>>> ##
>> Class "vector_OR_Vector", by class
>> "RangedSummarizedExperiment", distance 4
>> >>> >>>>
>> >>> >>>> _______________________________________________
>> >>> >>>> Bioc-devel using r-project.org mailing list >>> >>>>
>> https://stat.ethz.ch/mailman/listinfo/bioc-devel
>> >>> >>>>
>> >>> > _______________________________________________ >>>
>> > Bioc-devel using r-project.org mailing list >>> >
>> https://stat.ethz.ch/mailman/listinfo/bioc-devel
>> >>>
>> >>> --
>> >>> Hervé Pagès
>> >>>
>> >>> Bioconductor Core Team >>> hpages.on.github using gmail.com
>> >>>
>> >>> _______________________________________________ >>>
>> Bioc-devel using r-project.org mailing list >>>
>> https://stat.ethz.ch/mailman/listinfo/bioc-devel
>> >>
>> >>
>> >>
>> >> --
>> >> Best, >> Kasper
>>
>> > _______________________________________________ >
>> Bioc-devel using r-project.org mailing list >
>> https://stat.ethz.ch/mailman/listinfo/bioc-devel
More information about the Bioc-devel
mailing list