Name Mode Size
NEWS.md 120000
R 040000
inst 040000
man 040000
tests 040000
vignettes 040000
.Rbuildignore 100644 0 kb
.gitignore 100644 0 kb
.travis.yml 100644 1 kb
CODE_OF_CONDUCT.md 100644 1 kb
CONTRIBUTING.md 100644 2 kb
DESCRIPTION 100644 2 kb
Makefile 100644 0 kb
NAMESPACE 100644 14 kb
README.Rmd 100644 7 kb
README.md 100644 15 kb
_pkgdown.yml 100644 2 kb
appveyor.yml 100644 2 kb
codecov.yml 100644 0 kb
README.md
<!-- README.md is generated from README.Rmd. Please edit that file --> # plyranges: fluent genomic data analysis <img id="plyranges_logo" src="man/figures/logo.png" align="right" width = "125" /> [![Build Status](https://travis-ci.org/sa-lee/plyranges.svg?branch=master)](https://travis-ci.org/sa-lee/plyranges) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/sa-lee/plyranges?branch=master&svg=true)](https://ci.appveyor.com/project/sa-lee/plyranges) [![Codecov test coverage](https://codecov.io/gh/sa-lee/plyranges/branch/master/graph/badge.svg)](https://codecov.io/gh/sa-lee/plyranges?branch=master) `plryanges` provides a consistent interface for importing and wrangling genomics data from a variety of sources. The package defines a grammar of genomic data manipulation based on `dplyr` and the Bioconductor packages `IRanges`, `GenomicRanges`, and `rtracklayer`. It does this by providing a set of verbs for developing analysis pipelines based on *Ranges* objects that represent genomic regions: - Modify genomic regions with the `mutate()` and `stretch()` functions. - Modify genomic regions while fixing the start/end/center coordinates with the `anchor_` family of functions. - Sort genomic ranges with `arrange()`. - Modify, subset, and aggregate genomic data with the `mutate()`, `filter()`, and `summarise()`functions. - Any of the above operations can be performed on partitions of the data with `group_by()`. - Find nearest neighbour genomic regions with the `join_nearest_` family of functions. - Find overlaps between ranges with the `join_overlaps_` family of functions. - Merge all overlapping and adjacent genomic regions with `reduce_ranges()`. - Merge the end points of all genomic regions with `disjoin_ranges()`. - Import and write common genomic data formats with the `read_/write_` family of functions. For more details on the features of plryanges, read the [introduction vignette](https://sa-lee.github.io/plyranges/articles/an-introduction.html). # Installation The package is currently available from Bioconductor. ``` r # install.packages("BiocManager") BiocManager::install("plyranges") ``` To install the development version from GitHub: ``` r BiocManager::install("sa-lee/plyranges") ``` # Quick overview ## About `Ranges` `Ranges` objects can either represent sets of integers as `IRanges` (which have start, end and width attributes) or represent genomic intervals (which have additional attributes, sequence name, and strand) as `GRanges`. In addition, both types of `Ranges` can store information about their intervals as metadata columns (for example GC content over a genomic interval). `Ranges` objects follow the tidy data principle: each row of a `Ranges` object corresponds to an interval, while each column will represent a variable about that interval, and generally each object will represent a single unit of observation (like gene annotations). We can construct a `IRanges` object from a `data.frame` with a `start` or `width` using the `as_iranges()` method. ``` r library(plyranges) df <- data.frame(start = 1:5, width = 5) as_iranges(df) #> IRanges object with 5 ranges and 0 metadata columns: #> start end width #> <integer> <integer> <integer> #> [1] 1 5 5 #> [2] 2 6 5 #> [3] 3 7 5 #> [4] 4 8 5 #> [5] 5 9 5 # alternatively with end df <- data.frame(start = 1:5, end = 5:9) as_iranges(df) #> IRanges object with 5 ranges and 0 metadata columns: #> start end width #> <integer> <integer> <integer> #> [1] 1 5 5 #> [2] 2 6 5 #> [3] 3 7 5 #> [4] 4 8 5 #> [5] 5 9 5 ``` We can also construct a `GRanges` object in a similar manner. Note that a `GRanges` object requires at least a seqnames column to be present in the data.frame (but not necessarily a strand column). ``` r df <- data.frame(seqnames = c("chr1", "chr2", "chr2", "chr1", "chr2"), start = 1:5, width = 5) as_granges(df) #> GRanges object with 5 ranges and 0 metadata columns: #> seqnames ranges strand #> <Rle> <IRanges> <Rle> #> [1] chr1 1-5 * #> [2] chr2 2-6 * #> [3] chr2 3-7 * #> [4] chr1 4-8 * #> [5] chr2 5-9 * #> ------- #> seqinfo: 2 sequences from an unspecified genome; no seqlengths # strand can be specified with `+`, `*` (mising) and `-` df$strand <- c("+", "+", "-", "-", "*") as_granges(df) #> GRanges object with 5 ranges and 0 metadata columns: #> seqnames ranges strand #> <Rle> <IRanges> <Rle> #> [1] chr1 1-5 + #> [2] chr2 2-6 + #> [3] chr2 3-7 - #> [4] chr1 4-8 - #> [5] chr2 5-9 * #> ------- #> seqinfo: 2 sequences from an unspecified genome; no seqlengths ``` # Example: finding GWAS hits that overlap known exons Let’s look at a more a realistic example (taken from HelloRanges vignette). Suppose we have two *GRanges* objects: one containing coordinates of known exons and another containing SNPs from a GWAS. The first and last 5 exons are printed below, there are two additional columns corresponding to the exon name, and a score. We could check the number of exons per chromosome using `group_by` and `summarise`. ``` r exons #> GRanges object with 459752 ranges and 2 metadata columns: #> seqnames ranges strand | #> <Rle> <IRanges> <Rle> | #> [1] chr1 11874-12227 + | #> [2] chr1 12613-12721 + | #> [3] chr1 13221-14409 + | #> [4] chr1 14362-14829 - | #> [5] chr1 14970-15038 - | #> ... ... ... ... . #> [459748] chrY 59338754-59338859 + | #> [459749] chrY 59338754-59338859 + | #> [459750] chrY 59340194-59340278 + | #> [459751] chrY 59342487-59343488 + | #> [459752] chrY 59342487-59343488 + | #> name score #> <character> <numeric> #> [1] NR_046018_exon_0_0_chr1_11874_f 0 #> [2] NR_046018_exon_1_0_chr1_12613_f 0 #> [3] NR_046018_exon_2_0_chr1_13221_f 0 #> [4] NR_024540_exon_0_0_chr1_14362_r 0 #> [5] NR_024540_exon_1_0_chr1_14970_r 0 #> ... ... ... #> [459748] NM_002186_exon_6_0_chrY_59338754_f 0 #> [459749] NM_176786_exon_7_0_chrY_59338754_f 0 #> [459750] NM_002186_exon_7_0_chrY_59340194_f 0 #> [459751] NM_002186_exon_8_0_chrY_59342487_f 0 #> [459752] NM_176786_exon_8_0_chrY_59342487_f 0 #> ------- #> seqinfo: 93 sequences from an unspecified genome; no seqlengths exons %>% group_by(seqnames) %>% summarise(n = n()) #> DataFrame with 49 rows and 2 columns #> seqnames n #> <Rle> <integer> #> 1 chr1 43366 #> 2 chr1_gl000191_random 42 #> 3 chr1_gl000192_random 46 #> 4 chr10 19420 #> 5 chr11 24476 #> ... ... ... #> 45 chrUn_gl000222 20 #> 46 chrUn_gl000223 22 #> 47 chrUn_gl000228 85 #> 48 chrX 18173 #> 49 chrY 4128 ``` Next we create a column representing the transcript\_id with `mutate`: ``` r exons <- exons %>% mutate(tx_id = sub("_exon.*", "", name)) ``` To find all GWAS SNPs that overlap exons, we use `join_overlap_inner`. This will create a new *GRanges* with the coordinates of SNPs that overlap exons, as well as metadata from both objects. ``` r olap <- join_overlap_inner(gwas, exons) olap #> GRanges object with 3439 ranges and 4 metadata columns: #> seqnames ranges strand | name.x #> <Rle> <IRanges> <Rle> | <character> #> [1] chr1 1079198 * | rs11260603 #> [2] chr1 1247494 * | rs12103 #> [3] chr1 1247494 * | rs12103 #> [4] chr1 1247494 * | rs12103 #> [5] chr1 1247494 * | rs12103 #> ... ... ... ... . ... #> [3435] chrX 153764217 * | rs1050828 #> [3436] chrX 153764217 * | rs1050828 #> [3437] chrX 153764217 * | rs1050828 #> [3438] chrX 153764217 * | rs1050828 #> [3439] chrX 153764217 * | rs1050828 #> name.y score tx_id #> <character> <numeric> <character> #> [1] NR_038869_exon_2_0_chr1_1078119_f 0 NR_038869 #> [2] NM_001256456_exon_1_0_chr1_1247398_r 0 NM_001256456 #> [3] NM_001256460_exon_1_0_chr1_1247398_r 0 NM_001256460 #> [4] NM_001256462_exon_1_0_chr1_1247398_r 0 NM_001256462 #> [5] NM_001256463_exon_1_0_chr1_1247398_r 0 NM_001256463 #> ... ... ... ... #> [3435] NM_001042351_exon_9_0_chrX_153764152_r 0 NM_001042351 #> [3436] NM_000402_exon_9_0_chrX_153764152_r 0 NM_000402 #> [3437] NM_001042351_exon_9_0_chrX_153764152_r 0 NM_001042351 #> [3438] NM_000402_exon_9_0_chrX_153764152_r 0 NM_000402 #> [3439] NM_001042351_exon_9_0_chrX_153764152_r 0 NM_001042351 #> ------- #> seqinfo: 93 sequences from an unspecified genome; no seqlengths ``` For each SNP we can count the number of times it overlaps a transcript. ``` r olap %>% group_by(name.x, tx_id) %>% summarise(n = n()) #> DataFrame with 1619 rows and 3 columns #> name.x tx_id n #> <character> <character> <integer> #> 1 rs17121403 NM_000028 1 #> 2 rs429358 NM_000041 3 #> 3 rs7412 NM_000041 3 #> 4 rs2234978 NM_000043 1 #> 5 rs1801516 NM_000051 1 #> ... ... ... ... #> 1615 rs1420101 NR_104167 1 #> 1616 rs1065656 NR_104318 1 #> 1617 rs2224391 NR_104417 1 #> 1618 rs2224391 NR_104418 1 #> 1619 rs41281112 NR_104592 1 ``` We can also generate 2bp splice sites on either side of the exon using `flank_left` and `flank_right`. We add a column indicating the side of flanking for illustrative purposes. The `interweave` function pairs the left and right ranges objects. ``` r left_ss <- flank_left(exons, 2L) right_ss <- flank_right(exons, 2L) all_ss <- interweave(left_ss, right_ss, .id = "side") all_ss #> GRanges object with 919504 ranges and 4 metadata columns: #> seqnames ranges strand | #> <Rle> <IRanges> <Rle> | #> [1] chr1 11872-11873 + | #> [2] chr1 12228-12229 + | #> [3] chr1 12611-12612 + | #> [4] chr1 12722-12723 + | #> [5] chr1 13219-13220 + | #> ... ... ... ... . #> [919500] chrY 59340279-59340280 + | #> [919501] chrY 59342485-59342486 + | #> [919502] chrY 59343489-59343490 + | #> [919503] chrY 59342485-59342486 + | #> [919504] chrY 59343489-59343490 + | #> name score tx_id #> <character> <numeric> <character> #> [1] NR_046018_exon_0_0_chr1_11874_f 0 NR_046018 #> [2] NR_046018_exon_0_0_chr1_11874_f 0 NR_046018 #> [3] NR_046018_exon_1_0_chr1_12613_f 0 NR_046018 #> [4] NR_046018_exon_1_0_chr1_12613_f 0 NR_046018 #> [5] NR_046018_exon_2_0_chr1_13221_f 0 NR_046018 #> ... ... ... ... #> [919500] NM_002186_exon_7_0_chrY_59340194_f 0 NM_002186 #> [919501] NM_002186_exon_8_0_chrY_59342487_f 0 NM_002186 #> [919502] NM_002186_exon_8_0_chrY_59342487_f 0 NM_002186 #> [919503] NM_176786_exon_8_0_chrY_59342487_f 0 NM_176786 #> [919504] NM_176786_exon_8_0_chrY_59342487_f 0 NM_176786 #> side #> <character> #> [1] left #> [2] right #> [3] left #> [4] right #> [5] left #> ... ... #> [919500] right #> [919501] left #> [919502] right #> [919503] left #> [919504] right #> ------- #> seqinfo: 93 sequences from an unspecified genome; no seqlengths ``` # Citation If you found `plyranges` useful for your work please cite our [paper](http://dx.doi.org/10.1186/s13059-018-1597-8): @ARTICLE{Lee2019, title = "plyranges: a grammar of genomic data transformation", author = "Lee, Stuart and Cook, Dianne and Lawrence, Michael", journal = "Genome Biol.", volume = 20, number = 1, pages = "4", month = jan, year = 2019, url = "http://dx.doi.org/10.1186/s13059-018-1597-8", doi = "10.1186/s13059-018-1597-8", pmc = "PMC6320618" } # Contributing We welcome contributions from the R/Bioconductor community. We ask that contributors follow the [code of conduct](CODE_OF_CONDUCT.md) and the guide outlined [here](CONTRIBUTING.md). # Learning more - The [introductory vignette](https://sa-lee.github.io/plyranges/articles/an-introduction.html) has an overview of plyranges features. - The [Bioc 2018 Workshop book](https://bioconductor.github.io/BiocWorkshops/fluent-genomic-data-analysis-with-plyranges.html) has worked examples of using `plyranges` to analyse publicly available genomics data. - The [extended vignette in the plyrangesWorkshops package](https://github.com/sa-lee/plyrangesWorkshops) has a detailed walk through of using plyranges for coverage analysis. - The [case study](https://github.com/mikelove/plyrangesTximetaCaseStudy) by Michael Love using plyranges with [tximeta](https://bioconductor.org/packages/release/bioc/html/tximeta.html) to follow up on interesting hits from a combined RNA-seq and ATAC-seq analysis. - The [journal article](https://genomebiology.biomedcentral.com/articles/10.1186/s13059-018-1597-8) ([preprint here](https://www.biorxiv.org/content/early/2018/05/23/327841)) has details about the overall philosophy and design of plyranges.