[Bioc-devel] Problem with S4 method dispatch: method found for SummarizedExperiment, but not SingleCellExperiment

Axel Klenk @xe|@k|enk @end|ng |rom gm@||@com
Tue Jan 7 21:33:57 CET 2025


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



More information about the Bioc-devel mailing list