[Bioc-devel] Problems with converting GPos to GRanges.

Pages, Herve hp@ge@ @end|ng |rom |redhutch@org
Fri Sep 13 10:12:48 CEST 2019


Hi Charles,

Cryptic (but short) answer: the methods package **automatically** 
creates a coercion method from CTSS to GRanges for you. Unfortunately 
this method is broken.

Decryption:

Warning, this will take us to the very dark side of the S4 coercion system!

First this automatic method cannot be seen in a fresh session i.e. 
selectMethod() does NOT show it:

   > library(CAGEr)
   > selectMethod("coerce", c("CTSS", "GRanges"))
   Method Definition:

   function (from, to = "GRanges", strict = TRUE)
   {
     if (!isTRUEorFALSE(strict))
         stop("'strict' must be TRUE or FALSE")
     if (!strict)
         return(from)
     class(from) <- "GRanges"
     from using ranges <- as(from using ranges, "IRanges")
     from
   }
   <bytecode: 0x8fa9280>
   <environment: namespace:GenomicRanges>

   Signatures:
           from             to
   target  "CTSS"           "GRanges"
   defined "UnstitchedGPos" "GRanges"

As we will realize later, the method found by selectMethod() is not the 
one that is effectively used when coercing a CTSS object to GRanges. The 
method is defined in the GenomicRanges package and does the right thing. 
Note that its signature is UnstitchedGPos,GRanges not CTSS,GRanges but 
since CTSS extends UnstitchedGPos, it makes sense that it got picked up 
by selectMethod(). Note that, predictably, getMethod() doesn't find it 
because, unlike selectMethod(), it does not use inheritance:

   > getMethod("coerce", c("CTSS", "GRanges"))
   Error in getMethod("coerce", c("CTSS", "GRanges")) :
     no method found for function 'coerce' and signature CTSS, GRanges

Where it becomes really nasty is that this method is NOT the method that 
will get called when we do as(ctss, "GRanges"):

   gr0 <- as(new("CTSS"), "GRanges")

How do I know that? Let's use getMethod() again:

   > getMethod("coerce", c("CTSS", "GRanges"))
   Method Definition:

   function (from, to = "GRanges", strict = TRUE)
   if (strict) {
     from <- {
         class(from) <- "UnstitchedGPos"
         from
     }
     {
         from <- from
         {
             value <- new("GRanges")
             for (what in c("seqnames", "ranges", "strand", "seqinfo",
             "elementMetadata", "elementType", "metadata")) slot(value,
                 what) <- slot(from, what)
             value
         }
     }
   } else from
   <environment: namespace:GenomicRanges>

   Signatures:
         from   to
   target  "CTSS" "GRanges"
   defined "CTSS" "GRanges"

Surprise! And don't trust the appearances: this method is NOT defined by 
the GenomicRanges package (despite the <environment: 
namespace:GenomicRanges> line). It's an automatic coercion method that 
is defined on-the-fly by the methods package the first time the coercion 
is "needed". The methods package automatically defines these coercion 
methods between 2 classes when (1) one class is a parent of the other 
and (2) the developer didn't define its own method.

In addition to not be detectable by selectMethod() or getMethod(), 
another problem with these automatic coercion methods is that they tend 
to be wrong. And that's what happens with the coercion method from CTSS 
to GRanges: it returns a broken GRanges instance (which is why calling 
promoters() on it fails later).

So all you need to do is define your own coercion method from CTSS to 
GRanges. You can do this with:

   setMethod("coerce", c("CTSS", "GRanges"), from_GPos_to_GRanges)

The from_GPos_to_GRanges() function is defined in GenomicRanges. It used 
to be .from_GPos_to_GRanges() but I just renamed and exported it in 
GenomicRanges 1.37.16:

 
https://github.com/Bioconductor/GenomicRanges/commit/d7a0353830ae01d7776924045bebeabd035659d7

Note that it's important that you use setMethod("coerce", ...) instead 
of setAs(...) here. This is another long story but if you are curious I 
have some grumpy comments about this in GenomicRanges/R/GPos-class.R and 
in other places e.g. here:

 
https://github.com/Bioconductor/S4Vectors/blob/f4b4ee769d2e57ecc4a672bc117bff5c28edfad4/R/HitsList-class.R#L91-L116

Cheers,
H.


On 9/12/19 21:29, Charles Plessy wrote:
> Hello,
> 
> I am trying to make the CAGEr package (1.27.2) pass its regression
> tests, and I am still struggling with the refactoring of GPos to
> UnstitchedGPos and StitchedGPos in the devel branch of Bioconductor...
> 
> Currently, my problem is with the following command:
> 
> promoters(GRanges(CTSScoordinatesGR(exampleCAGEexp)))
> 
> CTSScoordinatesGR(exampleCAGEexp) returns a GPos object of transcription
> start sites, that I want to transform in promoter ranges.
> 
> While it worked in the past, I now have the following error:
> 
> Error in (function (classes, fdef, mtable)  :
>     unable to find an inherited method for function ‘update_ranges’ for
> signature ‘"UnstitchedIPos"’
> 
> I tried the same command with the gpos1a and gpos1b example objects from
> the GPos manual page, and they do not trigger the error.
> 
> Further inspection showed me that
> GRanges(CTSScoordinatesGR(exampleCAGEexp)) returns a GRanges object
> where the ranges are still in UnstitchedIPos class, while in the case of
> gpos1a and gpos1b they has been converted.
> 
> I do not know how to deal with that problem and I would appreciate some
> help.
> 
> Have a nice day,
> 
> Charles
> 

-- 
Hervé Pagès

Program in Computational Biology
Division of Public Health Sciences
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N, M1-B514
P.O. Box 19024
Seattle, WA 98109-1024

E-mail: hpages using fredhutch.org
Phone:  (206) 667-5791
Fax:    (206) 667-1319


More information about the Bioc-devel mailing list