1 Getting started

GenomicScores is an R package distributed as part of the Bioconductor project. To install the package, start R and enter:

source("http://bioconductor.org/biocLite.R")
biocLite("GenomicScores")

Once GenomicScores is installed, it can be loaded with the following command.

library(GenomicScores)

Often, however, GenomicScores will be automatically loaded when working with an annotation package that uses GenomicScores, such as phastCons100way.UCSC.hg19.

2 Genomewide position-specific scores

Genomewide scores assign each genomic position a numeric value denoting an estimated measure of constraint or impact on variation at that position. They are commonly used to filter single nucleotide variants or assess the degree of constraint or functionality of genomic features. Genomic scores are built on the basis of different sources of information such as sequence homology, functional domains, physical-chemical changes of amino acid residues, etc.

One particular example of genomic scores are phastCons scores. They provide a measure of conservation obtained from genomewide alignments using the program phast (Phylogenetic Analysis with Space/Time models) from Siepel et al. (2005). The GenomicScores package allows one to retrieve these scores through annotation packages (Section 4) or as AnnotationHub resources (Section 5).

Often, genomic scores such as phastCons are used within workflows running on top of R and Bioconductor. The purpose of the GenomicScores package is to enable an easy and interactive access to genomic scores within those workflows.

3 Lossy storage of genomic scores with compressed vectors

Storing and accessing genomic scores within R is challenging when their values cover large regions of the genome, resulting in gigabytes of double-precision numbers. This is the case, for instance, for phastCons (Siepel et al. 2005), CADD (Kircher et al. 2014) or M-CAP (Jagadeesh et al. 2016) scores.

We address this problem by using lossy compression, also called quantization, coupled with run-length encoding (Rle) vectors. Lossy compression attempts to trade off precision for compression without compromising the scientific integrity of the data (Zender 2016).

Sometimes, measurements and statistical estimates under certain models generate false precision. False precision is essentialy noise that wastes storage space and it is meaningless from the scientific point of view (Zender 2016). In those circumstances, lossy compression not only saves storage space, but also removes false precision.

The use of lossy compression leads to a subset of quantized values much smaller than the original set of genomic scores, resulting in long runs of identical values along the genome. These runs of identical values can be further compressed using the implementation of Rle vectors available in the S4Vectors Bioconductor package.

To enable a seamless access to genomic scores stored with quantized values in compressed vectors the GenomicScores defines the GScores class of objects. This class manages the location, loading and dequantization of genomic scores stored separately on each chromosome. A further class, called MafDb, is derived from GScores to store minor allele frequency (MAF) data accounting for specific features of this kind of values such as their organization into populations of individuals.

4 Retrieval of genomic scores through annotation packages

There are currently four different annotation packages that store genomic scores and can be accessed using the GenomicScores package; see Table 1.


Table 1: Bioconductor annotation packages storing genomic scores
Annotation Package Description
phastCons100way.UCSC.hg19 phastCons scores derived from the alignment of the human genome (hg19) to other 99 vertebrate species.
phastCons100way.UCSC.hg38 phastCons scores derived from the alignment of the human genome (hg38) to other 99 vertebrate species.
phastCons7way.UCSC.hg38 phastCons scores derived from the alignment of the human genome (hg38) to other 6 mammal species.
fitCons.UCSC.hg19 fitCons scores: fitness consequences of functional annotation for the human genome (hg19).

This is an example of how genomic scores can be retrieved using the phastCons100way.UCSC.hg19 package. Here, a GScores object is created when the package is loaded.

library(phastCons100way.UCSC.hg19)
gsco <- phastCons100way.UCSC.hg19
class(gsco)
## [1] "GScores"
## attr(,"package")
## [1] "GenomicScores"

The help page of the GScores class describes the different methods to access the information and metadata stored in a GScores object. To retrieve genomic scores for specific positions we should use the function scores(), as follows.

scores(gsco, GRanges(seqnames="chr22", IRanges(start=50967020:50967025, width=1)))
## GRanges object with 6 ranges and 1 metadata column:
##       seqnames               ranges strand |    scores
##          <Rle>            <IRanges>  <Rle> | <numeric>
##   [1]    chr22 [50967020, 50967020]      * |         1
##   [2]    chr22 [50967021, 50967021]      * |         1
##   [3]    chr22 [50967022, 50967022]      * |       0.8
##   [4]    chr22 [50967023, 50967023]      * |         1
##   [5]    chr22 [50967024, 50967024]      * |         1
##   [6]    chr22 [50967025, 50967025]      * |         0
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths

The GenomicScores package only loads the scores data from one sequence to retrieve metadata and from the sequences that are being queried. Note that now the GScores object has loaded the scores from chr22.

gsco
## GScores object 
## # organism: Homo sapiens (UCSC, hg19)
## # provider: UCSC
## # provider version: 09Feb2014
## # download date: Mar 17, 2017
## # loaded sequences: chr19_gl000208_random, chr22
## # maximum abs. error: 0.05
## # use 'citation()' to know how to cite these data in publications

The bibliographic reference to cite the genomic scores stored in a GScores object can be accessed using the citation() method either on the package name or on the GScores object. The latter is implemented in the GenomicScores package and provides a bibentry object.

citation(gsco)
## Adam Siepel, Gill Berejano, Jakob S. Pedersen, Angie S. Hinrichs,
## Minmei Hou, Kate Rosenbloom, Hiram Clawson, John Spieth, LaDeana W.
## Hillier, Stephen Richards, George M. Weinstock, Richard K. Wilson,
## Richard A. Gibbs, W. James Kent, Webb Miller and David Haussler (2005).
## "Evolutionarily conserved elements in vertebrate, insect, worm, and
## yeast genomes." _Genome Research_, *15*, pp. 1034-1050. doi:
## 10.1101/gr.3715005 (URL: http://doi.org/10.1101/gr.3715005).

Other methods tracing provenance and other metadata are provider(), providerVersion(), organism() and seqlevelsStyle(); please consult the help page of the GScores class for a comprehensive list of available methods.

provider(gsco)
## [1] "UCSC"
providerVersion(gsco)
## [1] "09Feb2014"
organism(gsco)
## [1] "Homo sapiens"
seqlevelsStyle(gsco)
## [1] "UCSC"

5 Retrieval of genomic scores through AnnotationHub resources

Another way to retrieve genomic scores is by using the AnnotationHub, which is a web resource that provides a central location where genomic files (e.g., VCF, bed, wig) and other resources from standard (e.g., UCSC, Ensembl) and distributed sites, can be found. A Bioconductor AnnotationHub web resource creates and manages a local cache of files retrieved by the user, helping with quick and reproducible access.

The first step to retrieve genomic scores is to check the ones available to download.

availableGScores()
##  [1] "cadd.v1.3.hg19"            "fitCons.UCSC.hg19"        
##  [3] "mcap.v1.0.hg19"            "phastCons100way.UCSC.hg19"
##  [5] "phastCons100way.UCSC.hg38" "phastCons27way.UCSC.dm6"  
##  [7] "phastCons60way.UCSC.mm10"  "phastCons7way.UCSC.hg38"  
##  [9] "phyloP100way.UCSC.hg19"    "phyloP100way.UCSC.hg38"

The selected resource can be downloaded with the function getGScores(). After the resource is downloaded the first time, the cached copy will enable a quicker retrieval later.

gsco <- getGScores("phastCons100way.UCSC.hg19")

Finally, the phastCons score of a particular genomic position is retrieved exactly in the same we did with the annotation package.

scores(gsco, GRanges(seqnames="chr22", IRanges(start=50967020:50967025, width=1)))
## GRanges object with 6 ranges and 1 metadata column:
##       seqnames               ranges strand |    scores
##          <Rle>            <IRanges>  <Rle> | <numeric>
##   [1]    chr22 [50967020, 50967020]      * |         1
##   [2]    chr22 [50967021, 50967021]      * |         1
##   [3]    chr22 [50967022, 50967022]      * |       0.8
##   [4]    chr22 [50967023, 50967023]      * |         1
##   [5]    chr22 [50967024, 50967024]      * |         1
##   [6]    chr22 [50967025, 50967025]      * |         0
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths

5.1 Building an annotation package from a GScores object

Retrieving genomic scores through AnnotationHub resources requires an internet connection and we may want to work with such resources offline. For that purpose, we can create ourselves an annotation package, such as phastCons100way.UCSC.hg19, from a GScores object corresponding to a downloaded AnnotationHub resource. To do that we use the function makeGScoresPackage() as follows:

makeGScoresPackage(gsco, maintainer="Me <me@example.com>", author="Me", version="1.0.0")
## Creating package in ./phastCons100way.UCSC.hg19

An argument, destDir, which by default points to the current working directory, can be used to change where in the filesystem the package is created. Afterwards, we should still build and install the package via, e.g., R CMD build and R CMD INSTALL, to be able to use it offline.

6 Retrieval of multiple scores per genomic position

Among the score sets available as AnnotationHub web resources shown in the previous section, two of them, CADD (Kircher et al. 2014) and M-CAP (Jagadeesh et al. 2016), provide multiple scores per genomic position that capture the tolerance to mutations of single nucleotides. Using M-CAP scores, we will illustrate how this type of scores are retrieved by default.

mcap <- getGScores("mcap.v1.0.hg19")
mcap
## GScores object 
## # organism: Homo sapiens (UCSC, hg19)
## # provider: Stanford
## # provider version: v1.0
## # download date: Mar 15, 2017
## # loaded sequences: chr22
## # maximum abs. error: 0.005
## # use 'citation()' to know how to cite these data in publications
citation(mcap)
## Karthik A. Jagadeesh, Aaron M. Wenger, Mark J. Berger, Harendra Guturu,
## Peter D. Stenson, David N. Cooper, Jonathan A. Bernstein and Gill
## Berejano (2016). "M-CAP eliminates a majority of variants of uncertain
## significance in clinical exomes at high sensitivity." _Nature
## Genetics_, *48*, pp. 1581-1586. doi: 10.1038/ng.3703 (URL:
## http://doi.org/10.1038/ng.3703).
gr <- GRanges(seqnames="chr22", IRanges(50967020:50967025, width=1))
scores(mcap, gr)
## GRanges object with 6 ranges and 3 metadata columns:
##       seqnames               ranges strand |   scores1   scores2   scores3
##          <Rle>            <IRanges>  <Rle> | <numeric> <numeric> <numeric>
##   [1]    chr22 [50967020, 50967020]      * |      0.54      0.55      0.34
##   [2]    chr22 [50967021, 50967021]      * |      0.47      0.64      0.64
##   [3]    chr22 [50967022, 50967022]      * |      <NA>      <NA>      <NA>
##   [4]    chr22 [50967023, 50967023]      * |      0.57      0.39      0.46
##   [5]    chr22 [50967024, 50967024]      * |      <NA>       0.5      0.49
##   [6]    chr22 [50967025, 50967025]      * |      <NA>      0.59      0.59
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths

The previous call to the scores() method returns three scores per position corresponding to the M-CAP scores that estimate the tolerance of mutating the reference nucleotide at that position to each of the possible alternative alleles, in alphabetical order. One may directly retrieve the scores for combinations of reference and alternative alelles using the ref and alt arguments of the scores() method. See the following example with the the previous genomic positions and some randomly selected alternative alleles.

library(BSgenome.Hsapiens.UCSC.hg19)

refAlleles <- as.character(getSeq(Hsapiens, gr))
altAlleles <- DNA_BASES[(match(refAlleles, DNA_BASES)) %% 4 + 1]
cbind(REF=refAlleles, ALT=altAlleles)
##      REF ALT
## [1,] "C" "G"
## [2,] "G" "T"
## [3,] "T" "A"
## [4,] "C" "G"
## [5,] "C" "G"
## [6,] "G" "T"
scores(mcap, gr, ref=refAlleles, alt=altAlleles)
## GRanges object with 6 ranges and 1 metadata column:
##       seqnames               ranges strand |    scores
##          <Rle>            <IRanges>  <Rle> | <numeric>
##   [1]    chr22 [50967020, 50967020]      * |      0.55
##   [2]    chr22 [50967021, 50967021]      * |      0.64
##   [3]    chr22 [50967022, 50967022]      * |      <NA>
##   [4]    chr22 [50967023, 50967023]      * |      0.39
##   [5]    chr22 [50967024, 50967024]      * |       0.5
##   [6]    chr22 [50967025, 50967025]      * |      0.59
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths

7 Summarization of genomic scores

The input genomic ranges to the scores() method may have widths larger than one nucleotide. In those cases, and when there is only one score per position, the scores() method calculates, by default, the arithmetic mean of the scores across each range.

gr1 <- GRanges(seqnames="chr22", IRanges(start=50967020:50967025, width=1))
gr1 <- scores(gsco, gr1)
gr1
## GRanges object with 6 ranges and 1 metadata column:
##       seqnames               ranges strand |    scores
##          <Rle>            <IRanges>  <Rle> | <numeric>
##   [1]    chr22 [50967020, 50967020]      * |         1
##   [2]    chr22 [50967021, 50967021]      * |         1
##   [3]    chr22 [50967022, 50967022]      * |       0.8
##   [4]    chr22 [50967023, 50967023]      * |         1
##   [5]    chr22 [50967024, 50967024]      * |         1
##   [6]    chr22 [50967025, 50967025]      * |         0
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths
mean(gr1$scores)
## [1] 0.8
gr2 <- GRanges(seqnames="chr22", IRanges(start=50967020, width=6))
scores(gsco, gr2)
## GRanges object with 1 range and 1 metadata column:
##       seqnames               ranges strand |    scores
##          <Rle>            <IRanges>  <Rle> | <numeric>
##   [1]    chr22 [50967020, 50967025]      * |       0.8
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths

However, we may change the way in which scores from multiple-nucleotide ranges are summarized with the argument summaryFun, as follows.

scores(gsco, gr2, summaryFun=max)
## GRanges object with 1 range and 1 metadata column:
##       seqnames               ranges strand |    scores
##          <Rle>            <IRanges>  <Rle> | <numeric>
##   [1]    chr22 [50967020, 50967025]      * |         1
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths
scores(gsco, gr2, summaryFun=min)
## GRanges object with 1 range and 1 metadata column:
##       seqnames               ranges strand |    scores
##          <Rle>            <IRanges>  <Rle> | <numeric>
##   [1]    chr22 [50967020, 50967025]      * |         0
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths
scores(gsco, gr2, summaryFun=median)
## GRanges object with 1 range and 1 metadata column:
##       seqnames               ranges strand |    scores
##          <Rle>            <IRanges>  <Rle> | <numeric>
##   [1]    chr22 [50967020, 50967025]      * |         1
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths

8 Retrieval of quantized genomic scores

The specific quantization and dequantization functions are stored as part of the metadata of a GScores object and they can be examined with the methods qfun() and dqfun(), respectively. The latter is called by the scores() method to retrieve genomic scores.

phastqfun <- qfun(gsco)
phastqfun
## function (x) 
## {
##     q <- as.integer(sprintf("%.0f", 10 * x))
##     q <- q + 1L
##     q
## }
## attr(,"description")
## [1] "multiply by 10, round to nearest integer, add up one"
phastdqfun <- dqfun(gsco)
phastdqfun
## function (q) 
## {
##     x <- as.numeric(q)
##     x[x == 0] <- NA
##     x <- (x - 1)/10
##     x
## }
## <bytecode: 0x1c32e6a0>
## attr(,"description")
## [1] "subtract one integer unit, divide by 10"

For single-nucleotide ranges, we can retrieve the quantized genomic scores using the argument quantized=TRUE.

gr1 <- scores(gsco, gr1, quantized=TRUE)
gr1
## GRanges object with 6 ranges and 1 metadata column:
##       seqnames               ranges strand | scores
##          <Rle>            <IRanges>  <Rle> |  <Rle>
##   [1]    chr22 [50967020, 50967020]      * |     0b
##   [2]    chr22 [50967021, 50967021]      * |     0b
##   [3]    chr22 [50967022, 50967022]      * |     09
##   [4]    chr22 [50967023, 50967023]      * |     0b
##   [5]    chr22 [50967024, 50967024]      * |     0b
##   [6]    chr22 [50967025, 50967025]      * |     01
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths

Using the dequantization function we can obtain later the genomic scores.

phastdqfun(gr1$scores)
## [1] 1.0 1.0 0.8 1.0 1.0 0.0

9 Retrieval of minor allele frequency data

The MafDb class derived from GSscores enables the storage and access of minor allele frequency (MAF) data. There are currently 9 different annotation packages that store MAF values using the GenomicScores package; see Table 2 below.

Table 2: Bioconductor annotation packages storing MAF data
Annotation Package Description
MafDb.1Kgenomes.phase1.hs37d5 MAF data from the 1000 Genomes Project Phase 1 for the human genome version GRCh37.
MafDb.1Kgenomes.phase3.hs37d5 MAF data from the 1000 Genomes Project Phase 3 for the human genome version GRCh37.
MafDb.ESP6500SI.V2.SSA137.hs37d5 MAF data from NHLBI ESP 6500 exomes for the human genome version GRCh37.
MafDb.ESP6500SI.V2.SSA137.GRCh38 MAF data from NHLBI ESP 6500 exomes for the human genome version GRCh38.
MafDb.ExAC.r1.0.hs37d5 MAF data from ExAC 60706 exomes for the human genome version GRCh37.
MafDb.ExAC.r1.0.nonTCGA.hs37d5 MAF data from ExAC 53105 nonTCGA exomes for the human genome version GRCh37.
MafDb.gnomAD.r2.0.1.hs37d5 MAF data from gnomAD 15496 genomes for the human genome version GRCh37.
MafDb.gnomADex.r2.0.1.hs37d5 MAF data from gnomADex 123136 exomes for the human genome version GRCh37.
MafDb.TOPMed.freeze5.hg38 MAF data from NHLBI TOPMed 62784 genomes for the human genome version GRCh38.

A MafDb object compresses the data in the same way as a GScores object but it can store multiple versions of the data corresponding to MAF values derived from different populations of individuals.

library(MafDb.1Kgenomes.phase1.hs37d5)

mafdb <- MafDb.1Kgenomes.phase1.hs37d5
mafdb
## Minor allele frequency Db (MafDb) object
## # organism: Homo sapiens
## # provider: IGSR
## # provider version: Phase1
## # download date: Apr 10, 2017
## # loaded sequences (SNVs): 22
## # loaded sequences (nonSNVs): none
## # loaded populations (SNVs): ASN_AF
## # loaded populations (nonSNVs): none
## # nr. of variants: 39706715
populations(mafdb)
## [1] "AF"     "AFR_AF" "AMR_AF" "ASN_AF" "EUR_AF"

Because MafDb objects derive from the GScores class, all the GScores methods also apply.

citation(mafdb)
## The 1000 Genomes Project Consortium (2012). "An integrated map of
## genetic variation from 1,092 human genomes." _Nature_, *491*, pp.
## 56-65. doi: 10.1038/nature11632 (URL:
## http://doi.org/10.1038/nature11632).
provider(mafdb)
## [1] "IGSR"
providerVersion(mafdb)
## [1] "Phase1"
organism(mafdb)
## [1] "Homo sapiens"
seqlevelsStyle(mafdb)
## [1] "NCBI"    "Ensembl"

The interface to access MAF values is also different to be more consistent with the one of SNPlocs.* packages; see, for instance, SNPlocs.Hsapiens.dbSNP144.GRCh37. More concretely, MafDb objects should be queried with the following two functions:

  • mafByOverlaps(x, ranges, pop="AF", type=c("snvs", "nonsnvs"), caching=TRUE): returns MAF values from the MafDb object in the argument x, whose positions overlap with the genomic ranges given in the argument ranges for the populations given in the argument pop. Additionally, one may query for single nucleotide variants -SNVs- (default) or nonSNVs by indicating it in the argument type. The argument caching flags whether the queried data should be cahced into main memory (default).

  • mafById(x, ids, pop, caching): return MAF values from the MafDb object in the argument x annotated by the data producer to the identifiers given in the argument ids. Arguments pop and caching work as in mafByOverlaps().

Consider the following example in which we are interested in MAF values for variants associated with eye color. We can start by fetching the corresponding variant identifers from the GWAS catalog using the gwascat package, as follows.

library(gwascat)
data(ebicat37)
eyersids <- subsetByTraits(ebicat37, tr="Eye color")$SNPS
eyersids
##  [1] "rs12913832" "rs12913832" "rs7173419"  "rs3002288"  "rs12896399"
##  [6] "rs12896399" "rs1408799"  "rs12520016" "rs288139"   "rs1667394" 
## [11] "rs4596632"  "rs12913832" "rs12913832" "rs12203592" "rs16891982"
## [16] "rs1393350"  "rs1847134"  "rs12896399" "rs12896399"

While we could directly interrogate a MafDb object with these identifiers and the function mafById(), that query relies on a specific dbSNP annotation used by the MAF data producer to annotate variants, which may not be the most up date nor may assign identifiers to every variant. From this perspective, it is safer to first query the genomic position of the variant identifiers with a recent release of dbSNP, as follows.

library(SNPlocs.Hsapiens.dbSNP144.GRCh37)
rng <- snpsById(SNPlocs.Hsapiens.dbSNP144.GRCh37, ids=eyersids)
rng
## GPos object with 19 positions and 2 metadata columns:
##        seqnames       pos strand |   RefSNP_id alleles_as_ambig
##           <Rle> <integer>  <Rle> | <character>      <character>
##    [1]       15  28365618      * |  rs12913832                R
##    [2]       15  28365618      * |  rs12913832                R
##    [3]       15  28196821      * |   rs7173419                Y
##    [4]        1 213126565      * |   rs3002288                R
##    [5]       14  92773663      * |  rs12896399                K
##    ...      ...       ...    ... .         ...              ...
##   [15]        5  33951693      * |  rs16891982                S
##   [16]       11  89011046      * |   rs1393350                R
##   [17]       11  89005253      * |   rs1847134                M
##   [18]       14  92773663      * |  rs12896399                K
##   [19]       14  92773663      * |  rs12896399                K
##   -------
##   seqinfo: 25 sequences (1 circular) from GRCh37.p13 genome

Finally, query the MAF values on those positions.

eyecolormafs <- mafByOverlaps(mafdb, rng, c("AF", "EUR_AF", "AFR_AF"))
eyecolormafs
## GPos object with 19 positions and 3 metadata columns:
##        seqnames       pos strand |        AF    EUR_AF    AFR_AF
##           <Rle> <integer>  <Rle> | <numeric> <numeric> <numeric>
##    [1]       15  28365618      * |      0.29      0.29      0.04
##    [2]       15  28365618      * |      0.29      0.29      0.04
##    [3]       15  28196821      * |      0.44      0.25      0.26
##    [4]        1 213126565      * |      0.33      0.46      0.08
##    [5]       14  92773663      * |      0.29      0.43      0.03
##    ...      ...       ...    ... .       ...       ...       ...
##   [15]        5  33951693      * |      0.44      0.03      0.05
##   [16]       11  89011046      * |      0.11      0.24      0.01
##   [17]       11  89005253      * |      0.22       0.3      0.15
##   [18]       14  92773663      * |      0.29      0.43      0.03
##   [19]       14  92773663      * |      0.29      0.43      0.03
##   -------
##   seqinfo: 25 sequences (1 circular) from GRCh37.p13 genome

The following code produces the barplot shown in Figure 1 illustrating graphically the differences in MAF values from these variants between the three queried populations.

par(mar=c(3, 5, 1, 1))
bp <- barplot(t(as.matrix(mcols(eyecolormafs))), beside=TRUE,
              col=c("darkblue", "darkgreen", "darkorange"),
              ylim=c(0, 0.55), las=1, ylab="Minor allele frequency")
axis(1, bp[2, ], 1:length(eyecolormafs))
mtext("Variant", side=1, line=2)
legend("topright", colnames(mcols(eyecolormafs)), fill=c("darkblue", "darkgreen", "darkorange"))
Eye color MAFs. Minor allele frequencies (MAFs) of variants associated with eye color for global, european and african populations of the Phase 1 data from the 1000 Genomes Project.

Figure 1: Eye color MAFs
Minor allele frequencies (MAFs) of variants associated with eye color for global, european and african populations of the Phase 1 data from the 1000 Genomes Project.

10 Annotating variants with genomic scores

A typical use case of the GenomicScores package is in the context of annotating variants with genomic scores, such as phastCons conservation scores. For this purpose, we load the VariantAnnotaiton and TxDb.Hsapiens.UCSC.hg19.knownGene packages. The former will allow us to read a VCF file and annotate it, and the latter contains the gene annotations from UCSC that will be used in this process.

library(VariantAnnotation)
library(TxDb.Hsapiens.UCSC.hg19.knownGene)

Let’s load one of the sample VCF files that form part of the VariantAnnotation package.

fl <- system.file("extdata", "chr22.vcf.gz", package="VariantAnnotation")
vcf <- readVcf(fl, "hg19")
seqlevelsStyle(vcf)
## [1] "NCBI"    "Ensembl"
txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene
seqlevelsStyle(txdb)
## [1] "UCSC"

Because the chromosome nomenclature from the VCF file (NCBI) is different from the one with the gene annotations (UCSC) we use the seqlevelsStyle() function to force our variants having the chromosome nomenclature of the gene annotations.

seqlevelsStyle(vcf) <- seqlevelsStyle(txdb)

We annotate the location of variants using the function locateVariants() from the VariantAnnotation package.

loc <- locateVariants(vcf, txdb, AllVariants())
loc[1:3]
## GRanges object with 3 ranges and 9 metadata columns:
##    seqnames               ranges strand | LOCATION  LOCSTART    LOCEND
##       <Rle>            <IRanges>  <Rle> | <factor> <integer> <integer>
##       chr22 [50300078, 50300078]      - |   intron     10763     10763
##       chr22 [50300086, 50300086]      - |   intron     10755     10755
##       chr22 [50300101, 50300101]      - |   intron     10740     10740
##      QUERYID        TXID         CDSID      GENEID       PRECEDEID
##    <integer> <character> <IntegerList> <character> <CharacterList>
##            1       75253                     79087                
##            2       75253                     79087                
##            3       75253                     79087                
##           FOLLOWID
##    <CharacterList>
##                   
##                   
##                   
##   -------
##   seqinfo: 1 sequence from hg19 genome; no seqlengths
table(loc$LOCATION)
## 
## spliceSite     intron    fiveUTR   threeUTR     coding intergenic   promoter 
##         11      22572        309       1368       2822       2867       2864

Annotate phastCons conservation scores on the variants and store those annotations as an additional metadata column of the GRanges object. For this specific purpose we should the argument scores.only=TRUE that makes the scores() method to return the genomic scores as a numeric vector instead as a metadata column in the input ranges object.

loc$PHASTCONS <- scores(gsco, loc, scores.only=TRUE)
loc[1:3]
## GRanges object with 3 ranges and 10 metadata columns:
##    seqnames               ranges strand | LOCATION  LOCSTART    LOCEND
##       <Rle>            <IRanges>  <Rle> | <factor> <integer> <integer>
##       chr22 [50300078, 50300078]      - |   intron     10763     10763
##       chr22 [50300086, 50300086]      - |   intron     10755     10755
##       chr22 [50300101, 50300101]      - |   intron     10740     10740
##      QUERYID        TXID         CDSID      GENEID       PRECEDEID
##    <integer> <character> <IntegerList> <character> <CharacterList>
##            1       75253                     79087                
##            2       75253                     79087                
##            3       75253                     79087                
##           FOLLOWID PHASTCONS
##    <CharacterList> <numeric>
##                          0.0
##                          0.1
##                          0.0
##   -------
##   seqinfo: 1 sequence from hg19 genome; no seqlengths

Using the following code we can examine the distribution of phastCons conservation scores of variants across the different annotated regions, shown in Figure 2.

x <- split(loc$PHASTCONS, loc$LOCATION)
mask <- elementNROWS(x) > 0
boxplot(x[mask], ylab="phastCons score", las=1, cex.axis=1.2, cex.lab=1.5, col="gray")
points(1:length(x[mask])+0.25, sapply(x[mask], mean, na.rm=TRUE), pch=23, bg="black")
Distribution of phastCons conservation scores in variants across different annotated regions. Diamonds indicate mean values.

Figure 2: Distribution of phastCons conservation scores in variants across different annotated regions
Diamonds indicate mean values.

Next, we can annotate M-CAP and CADD scores as follows. Note that we need to take care to only query positions of single nucleotide variants, and using the QUERYID column of the annotations to fetch back reference and alternative alleles from the original VCF file container.

maskSNVs <- isSNV(vcf)[loc$QUERYID]
loc$MCAP <- rep(NA_real_, length(loc))
loc$MCAP[maskSNVs] <- scores(mcap, loc[maskSNVs],
                             ref=ref(vcf)[loc$QUERYID[maskSNVs]],
                             alt=alt(vcf)[loc$QUERYID[maskSNVs]],
                             scores.only=TRUE)
maskSNVs <- isSNV(vcf)[loc$QUERYID]
loc$CADD <- rep(NA_real_, length(loc))
loc$CADD[maskSNVs] <- scores(cadd, loc[maskSNVs],
                             ref=ref(vcf)[loc$QUERYID[maskSNVs]],
                             alt=alt(vcf)[loc$QUERYID[maskSNVs]],
                             scores.only=TRUE)

Using the code below we can produce the plot of Figure 3 comparing CADD and M-CAP scores and labeling the location of the variants from which they are derived.

library(RColorBrewer)
par(mar=c(4, 5, 1, 1))
hmcol <- colorRampPalette(brewer.pal(nlevels(loc$LOCATION), "Set1"))(nlevels(loc$LOCATION))
plot(jitter(loc$MCAP, factor=2), jitter(loc$CADD, factor=2), pch=19,
     col=hmcol, xlab="M-CAP scores", ylab="CADD scores",
     las=1, cex.axis=1.2, cex.lab=1.5, panel.first=grid())
legend("bottomright", levels(loc$LOCATION), pch=19, col=hmcol, inset=0.01)
Comparison of M-CAP and CADD scores. Values on the x- and y-axis are jittered to facilitate visualization.

Figure 3: Comparison of M-CAP and CADD scores
Values on the x- and y-axis are jittered to facilitate visualization.

Finally, we will show how to annotate MAF values on these variants. However, in this particular case, we should take care of the different sequence styles (UCSC vs NCBI) and genome version nomenclatures (hg19 vs. hs37d5) between the annotated variants and the MafDb object.

seqlevelsStyle(loc) <- seqlevelsStyle(mafdb)[1]
seqinfo(loc, new2old=match(seqlevels(mafdb), seqlevels(loc))) <- seqinfo(mafdb)
loc$MAF[width(loc) == 1] <- mafByOverlaps(mafdb, loc[width(loc) == 1])$AF
loc$MAF[width(loc) > 1] <- mafByOverlaps(mafdb, loc[width(loc) > 1], type="nonsnvs")$AF
## mafByOverlaps: more than one variant overlapping queried positions, reporting only the first hit.
loc[1:3]
## GRanges object with 3 ranges and 13 metadata columns:
##    seqnames               ranges strand | LOCATION  LOCSTART    LOCEND
##       <Rle>            <IRanges>  <Rle> | <factor> <integer> <integer>
##          22 [50300078, 50300078]      - |   intron     10763     10763
##          22 [50300086, 50300086]      - |   intron     10755     10755
##          22 [50300101, 50300101]      - |   intron     10740     10740
##      QUERYID        TXID         CDSID      GENEID       PRECEDEID
##    <integer> <character> <IntegerList> <character> <CharacterList>
##            1       75253                     79087                
##            2       75253                     79087                
##            3       75253                     79087                
##           FOLLOWID PHASTCONS      MCAP      CADD       MAF
##    <CharacterList> <numeric> <numeric> <numeric> <numeric>
##                          0.0      <NA>         0      0.34
##                          0.1      <NA>        10      0.01
##                          0.0      <NA>         0      0.01
##   -------
##   seqinfo: 86 sequences (1 circular) from hs37d5 genome

11 Comparison between lossy-compressed and original phastCons scores

To have a sense of the extent of the trade-off between precision and compression in a specific case, we compare here original phastCons scores with the ones obtained by rounding their precision to one significant figure, and stored in the annotation package phastCons100way.UCSC.hg19. Because phastCons scores measure conservation, we sampled uniformly at random one thousand phastCons scores from differently conserved regions, concretely CDS and 3’UTR. These sampled scores are included in this package to illustrate this comparison. Interestingly, among the phastCons scores sampled from 1000 CDS positions, there are only 198 different values despite the apparently very high precision of some of them.

origpcscoCDS <- readRDS(system.file("extdata", "origphastCons100wayhg19CDS.rds", package="GenomicScores"))
origpcscoCDS
## GRanges object with 1000 ranges and 1 metadata column:
##          seqnames                 ranges strand |               score
##             <Rle>              <IRanges>  <Rle> |           <numeric>
##      [1]     chr1     [ 976248,  976248]      * |   0.763999998569489
##      [2]     chr1     [1886625, 1886625]      * | 0.00300000002607703
##      [3]     chr1     [3751636, 3751636]      * |                   1
##      [4]     chr1     [5950945, 5950945]      * |   0.236000001430511
##      [5]     chr1     [6638784, 6638784]      * |    0.99099999666214
##      ...      ...                    ...    ... .                 ...
##    [996]     chrX [154113587, 154113587]      * |                   1
##    [997]     chrX [154261706, 154261706]      * |                   1
##    [998]     chrX [154305499, 154305499]      * |                   1
##    [999]     chrY [ 15481226,  15481226]      * |                   1
##   [1000]     chrY [ 21871402,  21871402]      * |   0.981000006198883
##   -------
##   seqinfo: 25 sequences from an unspecified genome
length(unique(origpcscoCDS$score))
## [1] 198

We look more closely the number of significant figures of precision used in these original phastCons scores.

numDecimals <- function(x) {
  spl <- strsplit(as.character(x+1), "\\.")
  spl <- sapply(spl, "[", 2)
  spl[is.na(spl)] <- ""
  nchar(spl)
}

nd1 <- numDecimals(origpcscoCDS$score)
table(nd1)
## nd1
##   0   1   2  12  13  14 
## 637   1   2   5  63 292

Similarly, in 3’UTR regions, only 209 unique phastCons scores are observed.

origpcsco3UTRs <- readRDS(system.file("extdata", "origphastCons100wayhg193UTR.rds", package="GenomicScores"))
origpcsco3UTRs
## GRanges object with 1000 ranges and 1 metadata column:
##          seqnames                 ranges strand |               score
##             <Rle>              <IRanges>  <Rle> |           <numeric>
##      [1]     chr1     [1189930, 1189930]      * |                   0
##      [2]     chr1     [1227810, 1227810]      * |                   0
##      [3]     chr1     [1595390, 1595390]      * |  0.0149999996647239
##      [4]     chr1     [1595685, 1595685]      * |                   0
##      [5]     chr1     [2336044, 2336044]      * |                   0
##      ...      ...                    ...    ... .                 ...
##    [996]     chrX [125684491, 125684491]      * |                   0
##    [997]     chrX [129190576, 129190576]      * |                   1
##    [998]     chrX [135299066, 135299066]      * |   0.196999996900558
##    [999]     chrX [148560948, 148560948]      * | 0.00300000002607703
##   [1000]     chrX [153289202, 153289202]      * |                   0
##   -------
##   seqinfo: 25 sequences from an unspecified genome
length(table(origpcsco3UTRs$score))
## [1] 209
nd2 <- numDecimals(origpcsco3UTRs$score)
table(nd2)
## nd2
##   0  12  13  14 
## 502   3 112 383

Retrieve the corresponding phastCons scores stored in the annotation package.

pkgpcscoCDS <- scores(gsco, origpcscoCDS, scores.only=TRUE)
pkgpcsco3UTRs <- scores(gsco, origpcsco3UTRs, scores.only=TRUE)

In Figure 4 we show a visual comparison between raw and rounded phastCons scores. The two panels on top compare the whole range of scores observed in CDS (left) and 3’UTR (right) regions. However, the rounding effect can be better observed in the cumulative distributions shown in the panels at the bottom, again for CDS (left) and 3’UTR (right) regions.

In these bottom panels, phastcons scores in CDS and 3’UTR regions display very different cumulative distributions. In CDS regions, most of the genomic scores (>60%) are found between the values of 0.9 and 1.0, while around 25% of the scores are found below 0.1. Indeed, these are the range of values where lossy compression loses more precison. The cumulative distribution of 3’UTR shows the same critical points, with the difference that most of scores are found below 0.1 (>70%).

Original and lossy-compressed phastCons scores. Top panels (a, b): comparison of the distribution of values. Bottom panels (c, d): comparison of the cumulative distribution

Figure 4: Original and lossy-compressed phastCons scores
Top panels (a, b): comparison of the distribution of values. Bottom panels (c, d): comparison of the cumulative distribution

The bottom plots in Figure 4 also reveal that when the cumulative distribution is of interest, such as in the context of filtering genetic variants above or below certain threshold of conservation, the quantization of phastCons scores to one significant figure provides sufficient precision for a wide range of conservation values.

12 Session information

sessionInfo()
## R version 3.4.3 (2017-11-30)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 16.04.3 LTS
## 
## Matrix products: default
## BLAS: /home/biocbuild/bbs-3.6-bioc/R/lib/libRblas.so
## LAPACK: /home/biocbuild/bbs-3.6-bioc/R/lib/libRlapack.so
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=C              
##  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] parallel  stats4    stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] RColorBrewer_1.1-2                      
##  [2] VariantAnnotation_1.24.5                
##  [3] Rsamtools_1.30.0                        
##  [4] SummarizedExperiment_1.8.1              
##  [5] DelayedArray_0.4.1                      
##  [6] matrixStats_0.52.2                      
##  [7] SNPlocs.Hsapiens.dbSNP144.GRCh37_0.99.20
##  [8] gwascat_2.10.0                          
##  [9] Homo.sapiens_1.3.1                      
## [10] TxDb.Hsapiens.UCSC.hg19.knownGene_3.2.2 
## [11] org.Hs.eg.db_3.5.0                      
## [12] GO.db_3.5.0                             
## [13] OrganismDbi_1.20.0                      
## [14] GenomicFeatures_1.30.0                  
## [15] AnnotationDbi_1.40.0                    
## [16] Biobase_2.38.0                          
## [17] MafDb.1Kgenomes.phase1.hs37d5_3.6.0     
## [18] BSgenome.Hsapiens.UCSC.hg19_1.4.0       
## [19] BSgenome_1.46.0                         
## [20] rtracklayer_1.38.2                      
## [21] Biostrings_2.46.0                       
## [22] XVector_0.18.0                          
## [23] phastCons100way.UCSC.hg19_3.6.0         
## [24] GenomicScores_1.2.2                     
## [25] GenomicRanges_1.30.1                    
## [26] GenomeInfoDb_1.14.0                     
## [27] IRanges_2.12.0                          
## [28] S4Vectors_0.16.0                        
## [29] BiocGenerics_0.24.0                     
## [30] BiocStyle_2.6.1                         
## 
## loaded via a namespace (and not attached):
##   [1] backports_1.1.2               Hmisc_4.1-1                  
##   [3] AnnotationHub_2.10.1          fastmatch_1.1-0              
##   [5] gQTLstats_1.10.1              plyr_1.8.4                   
##   [7] lazyeval_0.2.1                splines_3.4.3                
##   [9] BatchJobs_1.7                 BiocParallel_1.12.0          
##  [11] ggplot2_2.2.1                 digest_0.6.13                
##  [13] ensembldb_2.2.0               foreach_1.4.4                
##  [15] BiocInstaller_1.28.0          htmltools_0.3.6              
##  [17] magrittr_1.5                  checkmate_1.8.5              
##  [19] memoise_1.1.0                 BBmisc_1.11                  
##  [21] cluster_2.0.6                 doParallel_1.0.11            
##  [23] limma_3.34.5                  ggbio_1.26.0                 
##  [25] prettyunits_1.0.2             colorspace_1.3-2             
##  [27] blob_1.1.0                    dplyr_0.7.4                  
##  [29] RCurl_1.95-4.10               jsonlite_1.5                 
##  [31] graph_1.56.0                  ffbase_0.12.3                
##  [33] bindr_0.1                     brew_1.0-6                   
##  [35] survival_2.41-3               sendmailR_1.2-1              
##  [37] iterators_1.0.9               glue_1.2.0                   
##  [39] gtable_0.2.0                  zlibbioc_1.24.0              
##  [41] scales_0.5.0                  DBI_0.7                      
##  [43] GGally_1.3.2                  Rcpp_0.12.14                 
##  [45] viridisLite_0.2.0             xtable_1.8-2                 
##  [47] progress_1.1.2                htmlTable_1.11.1             
##  [49] foreign_0.8-69                bit_1.1-12                   
##  [51] Formula_1.2-2                 erma_0.10.0                  
##  [53] htmlwidgets_0.9               httr_1.3.1                   
##  [55] acepack_1.4.1                 ff_2.2-13                    
##  [57] pkgconfig_2.0.1               reshape_0.8.7                
##  [59] XML_3.98-1.9                  Gviz_1.22.2                  
##  [61] nnet_7.3-12                   rlang_0.1.6                  
##  [63] reshape2_1.4.3                munsell_0.4.3                
##  [65] tools_3.4.3                   RSQLite_2.0                  
##  [67] evaluate_0.10.1               stringr_1.2.0                
##  [69] yaml_2.1.16                   knitr_1.18                   
##  [71] bit64_0.9-7                   purrr_0.2.4                  
##  [73] AnnotationFilter_1.2.0        bindrcpp_0.2                 
##  [75] RBGL_1.54.0                   nlme_3.1-131                 
##  [77] mime_0.5                      biomaRt_2.34.1               
##  [79] rstudioapi_0.7                compiler_3.4.3               
##  [81] curl_3.1                      beeswarm_0.2.3               
##  [83] plotly_4.7.1                  interactiveDisplayBase_1.16.0
##  [85] tibble_1.4.1                  stringi_1.1.6                
##  [87] highr_0.6                     GenomicFiles_1.14.0          
##  [89] lattice_0.20-35               ProtGenerics_1.10.0          
##  [91] Matrix_1.2-12                 pillar_1.0.1                 
##  [93] snpStats_1.28.0               data.table_1.10.4-3          
##  [95] bitops_1.0-6                  httpuv_1.3.5                 
##  [97] R6_2.2.2                      latticeExtra_0.6-28          
##  [99] bookdown_0.5                  RMySQL_0.10.13               
## [101] gridExtra_2.3                 vipor_0.4.5                  
## [103] codetools_0.2-15              dichromat_2.0-0              
## [105] assertthat_0.2.0              rprojroot_1.3-2              
## [107] GenomicAlignments_1.14.1      GenomeInfoDbData_1.0.0       
## [109] mgcv_1.8-22                   gQTLBase_1.10.0              
## [111] grid_3.4.3                    rpart_4.1-11                 
## [113] tidyr_0.7.2                   rmarkdown_1.8                
## [115] biovizBase_1.26.0             shiny_1.0.5                  
## [117] base64enc_0.1-3               ggbeeswarm_0.6.0

References

Jagadeesh, Karthik A, Aaron M Wenger, Mark J Berger, Harendra Guturu, Peter D Stenson, David N Cooper, Jonathan A Bernstein, and Gill Bejerano. 2016. “M-Cap Eliminates a Majority of Variants of Uncertain Significance in Clinical Exomes at High Sensitivity.” Nat. Genet. 48 (12). Nature Publishing Group: 1581–6.

Kircher, Martin, Daniela M Witten, Preti Jain, Brian J O’roak, Gregory M Cooper, and Jay Shendure. 2014. “A General Framework for Estimating the Relative Pathogenicity of Human Genetic Variants.” Nat. Genet. 46 (3). Nature Publishing Group: 310–15.

Siepel, Adam, Gill Bejerano, Jakob S Pedersen, Angie S Hinrichs, Minmei Hou, Kate Rosenbloom, Hiram Clawson, et al. 2005. “Evolutionarily Conserved Elements in Vertebrate, Insect, Worm, and Yeast Genomes.” Genome Res. 15 (8). Cold Spring Harbor Laboratory: 1034–50.

Zender, Charles S. 2016. “Bit Grooming: Statistically Accurate Precision-Preserving Quantization with Compression, Evaluated in the NetCDF Operators (Nco, V4. 4.8+).” Geosci. Model Dev. 9 (9). Copernicus GmbH: 3199–3211.