1 Introduction

The RaggedExperiment package provides a flexible data representation for copy number, mutation and other ragged array schema for genomic location data. It aims to provide a framework for a set of samples that have differing numbers of genomic ranges.

The RaggedExperiment class derives from a GRangesList representation and provides a semblance of a rectangular dataset. The row and column dimensions of the RaggedExperiment correspond to the number of ranges in the entire dataset and the number of samples represented in the data, respectively.

2 Installation

if (!require("BiocManager"))
    install.packages("BiocManager")
BiocManager::install("RaggedExperiment")

Loading the package:

library(RaggedExperiment)
library(GenomicRanges)

3 RaggedExperiment class overview

A schematic showing the class geometry and supported transformations of the RaggedExperiment class is show below. There are three main operations for transforming the RaggedExperiment representation:

  1. sparseAssay
  2. compactAssay
  3. qreduceAssay
RaggedExperiment object schematic. Rows and columns represent genomic ranges and samples, respectively. Assay operations can be performed with (from left to right) compactAssay, qreduceAssay, and sparseAssay.

Figure 1: RaggedExperiment object schematic
Rows and columns represent genomic ranges and samples, respectively. Assay operations can be performed with (from left to right) compactAssay, qreduceAssay, and sparseAssay.

4 Constructing a RaggedExperiment object

We start with a couple of GRanges objects, each representing an individual sample:

sample1 <- GRanges(
    c(A = "chr1:1-10:-", B = "chr1:8-14:+", C = "chr2:15-18:+"),
    score = 3:5)
sample2 <- GRanges(
    c(D = "chr1:1-10:-", E = "chr2:11-18:+"),
    score = 1:2)

Include column data colData to describe the samples:

colDat <- DataFrame(id = 1:2)

4.1 Using GRanges objects

ragexp <- RaggedExperiment(sample1 = sample1,
                           sample2 = sample2,
                           colData = colDat)
ragexp
## class: RaggedExperiment 
## dim: 5 2 
## assays(1): score
## rownames(5): A B C D E
## colnames(2): sample1 sample2
## colData names(1): id

4.2 Using a GRangesList instance

grl <- GRangesList(sample1 = sample1, sample2 = sample2)
RaggedExperiment(grl, colData = colDat)
## class: RaggedExperiment 
## dim: 5 2 
## assays(1): score
## rownames(5): A B C D E
## colnames(2): sample1 sample2
## colData names(1): id

4.3 Using a list of GRanges

rangeList <- list(sample1 = sample1, sample2 = sample2)
RaggedExperiment(rangeList, colData = colDat)
## class: RaggedExperiment 
## dim: 5 2 
## assays(1): score
## rownames(5): A B C D E
## colnames(2): sample1 sample2
## colData names(1): id

4.4 Using a List of GRanges with metadata

Note: In cases where a SimpleGenomicRangesList is provided along with accompanying metadata (accessed by mcols), the metadata is used as the colData for the RaggedExperiment.

grList <- List(sample1 = sample1, sample2 = sample2)
mcols(grList) <- colDat
RaggedExperiment(grList)
## class: RaggedExperiment 
## dim: 5 2 
## assays(1): score
## rownames(5): A B C D E
## colnames(2): sample1 sample2
## colData names(1): id

5 Accessors

5.1 Range data

rowRanges(ragexp)
## GRanges object with 5 ranges and 0 metadata columns:
##     seqnames    ranges strand
##        <Rle> <IRanges>  <Rle>
##   A     chr1      1-10      -
##   B     chr1      8-14      +
##   C     chr2     15-18      +
##   D     chr1      1-10      -
##   E     chr2     11-18      +
##   -------
##   seqinfo: 2 sequences from an unspecified genome; no seqlengths

5.2 Dimension names

dimnames(ragexp)
## [[1]]
## [1] "A" "B" "C" "D" "E"
## 
## [[2]]
## [1] "sample1" "sample2"

5.3 colData

colData(ragexp)
## DataFrame with 2 rows and 1 column
##                id
##         <integer>
## sample1         1
## sample2         2

6 Subsetting

6.1 by dimension

Subsetting a RaggedExperiment is akin to subsetting a matrix object. Rows correspond to genomic ranges and columns to samples or specimen. It is possible to subset using integer, character, and logical indices.

6.2 by genomic ranges

The overlapsAny and subsetByOverlaps functionalities are available for use for RaggedExperiment. Please see the corresponding documentation in RaggedExperiment and GenomicRanges.

7 *Assay functions

RaggedExperiment package provides several different functions for representing ranged data in a rectangular matrix via the *Assay methods.

7.1 sparseAssay

The most straightforward matrix representation of a RaggedExperiment will return a matrix of dimensions equal to the product of the number of ranges and samples.

dim(ragexp)
## [1] 5 2
Reduce(`*`, dim(ragexp))
## [1] 10
sparseAssay(ragexp)
##   sample1 sample2
## A       3      NA
## B       4      NA
## C       5      NA
## D      NA       1
## E      NA       2
length(sparseAssay(ragexp))
## [1] 10

7.2 compactAssay

Samples with identical ranges are placed in the same row. Non-disjoint ranges are not collapsed.

compactAssay(ragexp)
##              sample1 sample2
## chr1:8-14:+        4      NA
## chr1:1-10:-        3       1
## chr2:11-18:+      NA       2
## chr2:15-18:+       5      NA

7.3 disjoinAssay

This function returns a matrix of disjoint ranges across all samples. Elements of the matrix are summarized by applying the simplifyDisjoin functional argument to assay values of overlapping ranges.

disjoinAssay(ragexp, simplifyDisjoin = mean)
##              sample1 sample2
## chr1:8-14:+        4      NA
## chr1:1-10:-        3       1
## chr2:11-14:+      NA       2
## chr2:15-18:+       5       2

7.4 qreduceAssay

The qreduceAssay function works with a query parameter that highlights a window of ranges for the resulting matrix. The returned matrix will have dimensions length(query) by ncol(x). Elements contain assay values for the i th query range and the j th sample, summarized according to the simplifyReduce functional argument.

For demonstration purposes, we can have a look at the original GRangesList and the associated scores from which the current ragexp object is derived:

unlist(grl, use.names = FALSE)
## GRanges object with 5 ranges and 1 metadata column:
##     seqnames    ranges strand |     score
##        <Rle> <IRanges>  <Rle> | <integer>
##   A     chr1      1-10      - |         3
##   B     chr1      8-14      + |         4
##   C     chr2     15-18      + |         5
##   D     chr1      1-10      - |         1
##   E     chr2     11-18      + |         2
##   -------
##   seqinfo: 2 sequences from an unspecified genome; no seqlengths

This data is represented as rowRanges and assays in RaggedExperiment:

rowRanges(ragexp)
## GRanges object with 5 ranges and 0 metadata columns:
##     seqnames    ranges strand
##        <Rle> <IRanges>  <Rle>
##   A     chr1      1-10      -
##   B     chr1      8-14      +
##   C     chr2     15-18      +
##   D     chr1      1-10      -
##   E     chr2     11-18      +
##   -------
##   seqinfo: 2 sequences from an unspecified genome; no seqlengths
assay(ragexp, "score")
##   sample1 sample2
## A       3      NA
## B       4      NA
## C       5      NA
## D      NA       1
## E      NA       2

Here we provide the “query” region of interest:

(query <- GRanges(c("chr1:1-14:-", "chr2:11-18:+")))
## GRanges object with 2 ranges and 0 metadata columns:
##       seqnames    ranges strand
##          <Rle> <IRanges>  <Rle>
##   [1]     chr1      1-14      -
##   [2]     chr2     11-18      +
##   -------
##   seqinfo: 2 sequences from an unspecified genome; no seqlengths

The simplifyReduce argument in qreduceAssay allows the user to summarize overlapping regions with a custom method for the given “query” region of interest. We provide one for calculating a weighted average score per query range, where the weight is proportional to the overlap widths between overlapping ranges and a query range.

Note that there are three arguments to this function. See the documentation for additional details.

weightedmean <- function(scores, ranges, qranges)
{
    isects <- pintersect(ranges, qranges)
    sum(scores * width(is