### =========================================================================
### GRangesList objects
### -------------------------------------------------------------------------
###
setClass("GRangesList",
contains="GenomicRangesList",
representation("VIRTUAL"),
prototype(elementType="GRanges")
)
setClass("SimpleGRangesList",
contains=c("GRangesList", "SimpleGenomicRangesList")
)
setClass("CompressedGRangesList",
contains=c("GRangesList", "CompressedGenomicRangesList"),
representation(unlistData="GRanges")
)
### TODO: Get rid of this! Used in RangedSummarizedExperiment class definition
### to specify the class of the 'rowRanges' slot and was originally introduced
### to support this use case. However, more packages use it these days e.g.
### DEFormats, GenomicFiles, ggbio, gmapR, HelloRanges, profileplyr, and maybe
### more... Everybody now should use GenomicRanges_OR_GenomicRangesList instead
### of GenomicRanges_OR_GRangesList.
setClassUnion("GenomicRanges_OR_GRangesList", c("GenomicRanges", "GRangesList"))
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### Link GRanges to CompressedGRangesList
###
### Used by splitAsList() and family (e.g. relist(), extractList(), etc...)
### to infer the class of the output when the input is a GRanges object or
### derivative.
###
setMethod("relistToClass", "GRanges", function(x) "CompressedGRangesList")
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### Constructors
###
GRangesList <- function(..., compress=TRUE)
{
if (!isTRUEorFALSE(compress))
stop("'compress' must be TRUE or FALSE")
objects <- list(...)
if (length(objects) == 1L) {
tmp <- objects[[1L]]
if (is.list(tmp) || (is(tmp, "List") && !is(tmp, "GenomicRanges")))
objects <- tmp
}
if (compress)
suppressWarnings(as(objects, "CompressedGRangesList"))
else
as(objects, "SimpleGRangesList")
}
### Typically, the field values will come from a file that needs to be loaded
### into a data.frame first.
makeGRangesListFromFeatureFragments <- function(seqnames=Rle(factor()),
fragmentStarts=list(),
fragmentEnds=list(),
fragmentWidths=list(),
strand=character(0),
sep=",")
{
fragmentStarts <- normarg_list_of_integers(fragmentStarts, sep,
"fragmentStarts")
nfrag_per_feature <- elementNROWS(fragmentStarts)
start <- unlist(fragmentStarts, recursive=FALSE, use.names=FALSE)
fragmentEnds <- normarg_list_of_integers(fragmentEnds, sep,
"fragmentEnds")
nend_per_elt <- elementNROWS(fragmentEnds)
if (length(nend_per_elt) != 0L) {
if (length(nfrag_per_feature) == 0L)
nfrag_per_feature <- nend_per_elt
else if (!identical(nend_per_elt, nfrag_per_feature))
stop("'fragmentStarts' and 'fragmentEnds' have ",
"incompatible \"shapes\"")
}
end <- unlist(fragmentEnds, recursive=FALSE, use.names=FALSE)
fragmentWidths <- normarg_list_of_integers(fragmentWidths, sep,
"fragmentWidths")
nwidth_per_elt <- elementNROWS(fragmentWidths)
if (length(nwidth_per_elt) != 0L) {
if (length(nfrag_per_feature) == 0L)
nfrag_per_feature <- nwidth_per_elt
else if (!identical(nwidth_per_elt, nfrag_per_feature))
stop("\"shape\" of 'fragmentWidths' is incompatible ",
"with \"shape\" of 'fragmentStarts' or 'fragmentEnds'")
}
width <- unlist(fragmentWidths, recursive=FALSE, use.names=FALSE)
ranges <- IRanges(start=start, end=end, width=width)
nfrag <- sum(nfrag_per_feature)
if (nfrag != length(ranges))
stop("GenomicRanges internal error in makeGRangesListFromFields(): ",
"nfrag != length(ranges). This should never happen. ",
"Please report.")
if (nfrag == 0L) {
## Cannot blindly subset by FALSE because it doesn't work on a
## zero-length Rle.
if (length(seqnames) != 0L)
seqnames <- seqnames[FALSE]
if (length(strand) != 0L)
strand <- strand[FALSE]
} else {
if (length(seqnames) != length(nfrag_per_feature) ||
length(strand) != length(nfrag_per_feature))
stop("length of 'seqnames' and/or 'strand' is incompatible ",
"with fragmentStarts/Ends/Widths")
seqnames <- rep.int(seqnames, nfrag_per_feature)
strand <- rep.int(strand, nfrag_per_feature)
}
unlistData <- GRanges(seqnames=seqnames, ranges=ranges, strand=strand)
partitioning <- PartitioningByEnd(cumsum(nfrag_per_feature), names=NULL)
relist(unlistData, partitioning)
}
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### Accessors
###
setMethod("ranges", "CompressedGRangesList",
function(x, use.names=TRUE, use.mcols=FALSE)
{
if (!isTRUEorFALSE(use.names))
stop("'use.names' must be TRUE or FALSE")
if (!isTRUEorFALSE(use.mcols))
stop("'use.mcols' must be TRUE or FALSE")
unlisted_x <- unlist(x, use.names=FALSE)
unlisted_ans <- unlisted_x@ranges
if (use.mcols)
mcols(unlisted_ans) <- mcols(unlisted_x, use.names=FALSE)
ans <- relist(unlisted_ans, x)
if (!use.names)
names(ans) <- NULL
if (use.mcols)
mcols(ans) <- mcols(x, use.names=FALSE)
ans
}
)
setReplaceMethod("ranges", "CompressedGRangesList",
function(x, value)
{
if (!is(value, "IntegerRangesList") ||
!identical(elementNROWS(x), elementNROWS(value)))
stop("replacement 'value' is not an IntegerRangesList with the ",
"same elementNROWS as 'x'")
ranges(x@unlistData) <- as(unlist(value, use.names = FALSE), "IRanges")
x
}
)
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### Coercion from list-like object to SimpleGRangesList
###
### Try to turn an arbitrary **list-like** object into an ordinary list of
### GRanges objects.
.as_list_of_GRanges <- function(from)
{
if (is(from, "GenomicRanges")) {
if (!is(from, "GRanges"))
from <- as(from, "GRanges", strict=FALSE)
along_idx <- setNames(seq_along(from), names(from))
names(from) <- NULL
mcols(from) <- NULL
lapply(along_idx, function(i) from[i])
} else {
lapply(from, as, "GRanges", strict=FALSE)
}
}
### --- From ordinary list to SimpleGRangesList ---
### Note that being able to coerce a length-one ordinary list to
### SimpleGRangesList will automatically make [[<- work on SimpleGRangesList
### objects.
.from_list_to_SimpleGRangesList <- function(from)
{
x <- .as_list_of_GRanges(from)
S4Vectors:::new_SimpleList_from_list("SimpleGRangesList", x)
}
setAs("list", "SimpleGRangesList", .from_list_to_SimpleGRangesList)
setAs("list", "GRangesList", .from_list_to_SimpleGRangesList)
### --- From List derivative to SimpleGRangesList ---
.from_List_to_SimpleGRangesList <- function(from)
{
x <- .as_list_of_GRanges(from)
S4Vectors:::new_SimpleList_from_list("SimpleGRangesList", x,
metadata=metadata(from),
mcols=mcols(from, use.names=FALSE))
}
setAs("List", "SimpleGRangesList", .from_List_to_SimpleGRangesList)
### Automatic coercion methods from SimpleList, GenomicRangesList, or
### SimpleGenomicRangesList to SimpleGRangesList silently return a broken
### object (unfortunately these dummy automatic coercion methods don't bother
### to validate the object they return). So we overwrite them.
setAs("SimpleList", "SimpleGRangesList",
.from_List_to_SimpleGRangesList)
setAs("GenomicRangesList", "SimpleGRangesList",
.from_List_to_SimpleGRangesList)
setAs("SimpleGenomicRangesList", "SimpleGRangesList",
.from_List_to_SimpleGRangesList)
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### Coercion from list-like object to CompressedGRangesList
###
### --- From ordinary list to CompressedGRangesList ---
### Note that being able to coerce a length-one ordinary list to
### CompressedGRangesList will automatically make [[<- work on
### CompressedGRangesList objects.
.from_list_to_CompressedGRangesList <- function(from)
{
x <- .as_list_of_GRanges(from)
IRanges:::new_CompressedList_from_list("CompressedGRangesList", x)
}
setAs("list", "CompressedGRangesList", .from_list_to_CompressedGRangesList)
### --- From List derivative to CompressedGRangesList ---
.from_List_to_CompressedGRangesList <- function(from)
{
if (is(from, "GenomicRanges")) {
## Perform a "dumb split".
if (!is(from, "GRanges"))
from <- as(from, "GRanges", strict=FALSE)
## We call IRanges:::from_Vector_to_CompressedList() to perform
## the "dumb split". This is **very** efficient!
return(IRanges:::from_Vector_to_CompressedList(from))
}
x <- .as_list_of_GRanges(from)
IRanges:::new_CompressedList_from_list("CompressedGRangesList", x,
metadata=metadata(from),
mcols=mcols(from, use.names=FALSE))
}
setAs("List", "CompressedGRangesList",
.from_List_to_CompressedGRangesList)
setAs("List", "GRangesList",
function(from)
{
if (is(from, "CompressedList") || is(from, "GenomicRanges"))
as(from, "CompressedGRangesList")
else
as(from, "SimpleGRangesList")
}
)
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### Other coercions
###
setAs("CompressedGRangesList", "CompressedIRangesList",
function(from) ranges(from, use.mcols=TRUE)
)
setAs("CompressedGRangesList", "IRangesList",
function(from) ranges(from, use.mcols=TRUE)
)
setAs("CompressedGRangesList", "IntegerRangesList",
function(from) ranges(from, use.mcols=TRUE)
)
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### Sorting
###
### S3/S4 combo for sort.GRangesList
.sort.GRangesList <- function(x, decreasing=FALSE, ...)
{
gr <- deconstructGRLintoGR(x)
gr2 <- sort(gr, decreasing=decreasing, ...)
reconstructGRLfromGR(gr2, x)
}
sort.GRangesList <- function(x, decreasing=FALSE, ...)
.sort.GRangesList(x, decreasing=decreasing, ...)
setMethod("sort", "CompressedGRangesList", .sort.GRangesList)
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### Subsetting
###
### TODO: We should have more general methods defined at the GenomicRangesList
### level instead of the methods below.
###
.sBracketSubsetGRList <- function(x, i, j, ..., drop)
{
if (!missing(i)) {
x <- callNextMethod(x = x, i = i)
}
if (!missing(j)) {
if (!is.character(j))
stop("'j' must be a character vector")
withinLevel <- (j %in% colnames(x@unlistData@elementMetadata))
if (any(withinLevel) && !all(withinLevel))
stop("'j' cannot mix between and within metadata column names")
if (any(withinLevel)) {
mcols(x, level="within") <-
mcols(x, use.names=FALSE, level="within")[, j, drop=FALSE]
} else {
mcols(x) <- mcols(x, use.names=FALSE)[, j, drop=FALSE]
}
}
x
}
setMethod("[", "CompressedGRangesList", .sBracketSubsetGRList)
.sBracketReplaceGRList <- function(x, i, j, ..., value)
{
if (!is(value, class(x)[1]))
stop(paste0("replacement value must be a ", class(x)[1], " object"))
if (!missing(i))
i <- extractROWS(setNames(seq_along(x), names(x)), i)
if (!missing(j)) {
if (!is.character(j))
stop("'j' must be a character vector")
withinLevel <- (j %in% colnames(x@unlistData@elementMetadata))
if (any(withinLevel) && !all(withinLevel))
stop("'j' cannot mix between and within metadata column names")
if (missing(i)) {
if (any(withinLevel)) {
mcols(x, level="within")[, j] <-
mcols(x, use.names=FALSE, level="within")
} else {
mcols(x)[, j] <- mcols(x, use.names=FALSE)
}
} else {
if (any(withinLevel)) {
mcols(x, level="within")[i, j] <-
mcols(x, use.names=FALSE, level="within")
} else {
mcols(x)[i, j] <- mcols(x, use.names=FALSE)
}
}
}
callNextMethod(x = x, i = i, value = value)
}
setReplaceMethod("[", "CompressedGRangesList", .sBracketReplaceGRList)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.