From 80cbe60aea34cb84cb24398b77c89cd278f656f9 Mon Sep 17 00:00:00 2001 From: fruce-ki Date: Tue, 8 Feb 2022 14:01:15 +0100 Subject: [PATCH 1/4] fixes #69 syntax bug --- R/input.R | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/R/input.R b/R/input.R index d8c06a1..be18ac5 100644 --- a/R/input.R +++ b/R/input.R @@ -127,21 +127,17 @@ annot2models <- function(annotfile, threads= 1L) #================================================================================ -#' Import abundances directly from salmon and kallisto output. +#' Import abundances directly from kallisto output. #' -#' Convert Salmon read counts format to Kallisto RHDF5 format, -#' then apply TPM normalisation using the info available from the abundance.h5 files. +#' Apply TPM normalisation using the info available from the abundance.h5 files. #' #' Converting, normalising and importing multiple bootstrapped abundance files takes a bit of time. #' IMPORTANT: This function is currently not intended to be used to import non-bootstrapped quantifications. #' -#' \code{wasabi} automatically skips format conversion if a folder already contains an \code{abundance.h5} file. -#' #' @param A_paths (character) A vector of strings, listing the directory paths to the quantifications for the first condition. One directory per replicate, without trailing path dividers. The directory name should be a unique identifier for the sample. #' @param B_paths (character) A vector of strings, listing the directory paths to the quantifications for the second condition. One directory per replicate, without trailing path dividers.. The directory name should be a unique identifier for the sample. #' @param annot (data.frame) A table matching transcript identifiers to gene identifiers. This should be the same that you used for quantification and that you will use with \code{call_DTU()}. It is used to order the transcripts consistently throughout RATs. #' @param scaleto (double) Scaling factor for normalised abundances. (Default 1000000 gives TPM). If a numeric vector is supplied instead, its length must match the total number of samples. The value order should correspond to the samples in group A followed by group B. This allows each sample to be scaled to its own actual library size, allowing higher-throughput samples to carry more weight in deciding DTU. -#' @param half_cooked (logical) If TRUE, input is already in \code{Kallisto} h5 format and \code{wasabi} conversion will be skipped. FALSE can also be used to force wasabi to repeat the conversion even if it exists. (Default FALSE) #' @param beartext (logical) Instead of importing bootstrap data from the \code{abundance.h5} file of each sample, import it from plaintext files in a \code{bootstrap} subdirectory created by running \code{kallisto}'s \code{h5dump} subcommand (Default FALSE). This workaround circumvents some mysterious .h5 parsing issues on certain systems. #' @param TARGET_COL The name of the column for the transcript identifiers in \code{annot}. (Default \code{"target_id"}) #' @param PARENT_COL The name of the column for the gene identifiers in \code{annot}. (Default \code{"parent_id"}) @@ -151,11 +147,10 @@ annot2models <- function(annotfile, threads= 1L) #' @import parallel #' @import data.table #' @import rhdf5 -#' @import wasabi #' #' @export -fish4rodents <- function(A_paths, B_paths, annot, TARGET_COL="target_id", PARENT_COL="parent_id", half_cooked=FALSE, beartext=FALSE, threads= 1L, scaleto= 1000000) +fish4rodents <- function(A_paths, B_paths, annot, TARGET_COL="target_id", PARENT_COL="parent_id", beartext=FALSE, threads= 1L, scaleto= 1000000) { threads <- as.integer(threads) # Can't be decimal. setDTthreads(threads, restore_after_fork = TRUE) @@ -163,15 +158,12 @@ fish4rodents <- function(A_paths, B_paths, annot, TARGET_COL="target_id", PARENT # Don't assume the annotation is ordered properly. annot <- tidy_annot(annot, TARGET_COL, PARENT_COL) - # Wasabi? - wasabi::prepare_fish_for_sleuth(c(A_paths, B_paths), force= !half_cooked) - # Sort out scaling factor per sample. lgth <- c("A"=length(A_paths), "B"=length(B_paths)) sfac <- list("A"=NA_real_, "B"=NA_real_) if (length(scaleto) == 1) { # uniform scaling - sfac$A <- rep(scaleto, lgth$A) - sfac$B <- rep(scaleto, lgth$B) + sfac$A <- rep(scaleto, lgth["A"]) + sfac$B <- rep(scaleto, lgth["B"]) } else { # individual scaling sfac$A <- scaleto[1:lgth$A] sfac$B <- scaleto[(1 + lgth$A):(lgth$A + lgth$B)] From e27c7393aa9369709fefeae78349d8552eac2024 Mon Sep 17 00:00:00 2001 From: fruce-ki Date: Wed, 1 Jun 2022 17:22:56 +0200 Subject: [PATCH 2/4] enable import of unbootstrapped kallisto drop support for automatic conversion of salmon to kallisto via {wasabi}. Integration is causing more problems than it is solving and conversion is easy for users to apply separately. --- NAMESPACE | 1 - R/input.R | 63 ++-- man/fish4rodents.Rd | 24 +- vignettes/input.R | 206 +++++++++++++ vignettes/input.html | 720 +++++++++++++++++++++++++++++++++++++++++++ vignettes/input.md | 596 +++++++++++++++++++++++++++++++++++ 6 files changed, 1580 insertions(+), 30 deletions(-) create mode 100644 vignettes/input.R create mode 100644 vignettes/input.html create mode 100644 vignettes/input.md diff --git a/NAMESPACE b/NAMESPACE index cfcfd2e..15047bf 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -30,7 +30,6 @@ import(matrixStats) import(parallel) import(rhdf5) import(utils) -import(wasabi) importFrom(GenomicRanges,makeGRangesListFromDataFrame) importFrom(GenomicRanges,mcols) importFrom(parallel,detectCores) diff --git a/R/input.R b/R/input.R index be18ac5..89510c6 100644 --- a/R/input.R +++ b/R/input.R @@ -142,7 +142,7 @@ annot2models <- function(annotfile, threads= 1L) #' @param TARGET_COL The name of the column for the transcript identifiers in \code{annot}. (Default \code{"target_id"}) #' @param PARENT_COL The name of the column for the gene identifiers in \code{annot}. (Default \code{"parent_id"}) #' @param threads (integer) For parallel processing. (Default 1) -#' @return A list of two, representing the TPM abundances per condition. These will be formatted in the RATs generic bootstrapped data input format. +#' @return A list of two, representing the TPM abundances per condition. These will be formatted in the RATs generic data input format, preferably for bootstrapped estimates (if bootstraps are available) or otherwise for plain count estimates. #' #' @import parallel #' @import data.table @@ -193,32 +193,59 @@ fish4rodents <- function(A_paths, B_paths, annot, TARGET_COL="target_id", PARENT # for consistency with the .h5 mode and to allow normalisation to other target sizes # If data from Salmon/Wasabi or Kallisto abundance.h5... } else { + content <- rhdf5::h5ls(file.path(fil, "abundance.h5")) meta <- as.data.table(list( target_id=as.character(rhdf5::h5read(file.path(fil, "abundance.h5"), "/aux/ids")), eff_length=as.numeric(rhdf5::h5read(file.path(fil, "abundance.h5"), "/aux/eff_lengths")) )) - counts <- as.data.table( rhdf5::h5read(file.path(fil, "abundance.h5"), "/bootstrap") ) + + if ('bootstrap' %in% content$name) { + counts <- as.data.table( rhdf5::h5read(file.path(fil, "abundance.h5"), "/bootstrap") ) + # Normalise raw counts. + tpm <- as.data.table( lapply(counts, function (y) { + cpb <- y / meta$eff_length + tcpb <- sf / sum(cpb) + return(cpb * tcpb) + }) ) + # Structure. + dt <- as.data.table( cbind(meta$target_id, tpm) ) + with(dt, setkey(dt, V1) ) + names(dt)[1] <- TARGET_COL + # Order transcripts to match annotation. + dt <- merge(annot[, c(TARGET_COL), with=FALSE], dt, by=TARGET_COL, all=TRUE) + + } else { + counts <- rhdf5::h5read(file.path(fil, "abundance.h5"), "/est_counts") + # Normalize. + cpb <- counts / meta$eff_length + tcpb <- sf / sum(cpb) + tpm <- cpb * tcpb + # Structure + dt <- as.data.table( cbind(meta$target_id, tpm) ) + with(dt, setkey(dt, V1) ) + names(dt)[1] <- TARGET_COL + names(dt)[2] <- basename(fil) + # Order transcripts to match annotation. + dt <- merge(annot[, c(TARGET_COL), with=FALSE], dt, by=TARGET_COL, all=TRUE) + } + + return (dt) } - - # Normalise raw counts. - tpm <- as.data.table( lapply(counts, function (y) { - cpb <- y / meta$eff_length - tcpb <- sf / sum(cpb) - return(cpb * tcpb) - }) ) - - # Structure. - dt <- as.data.table( cbind(meta$target_id, tpm) ) - with(dt, setkey(dt, V1) ) - names(dt)[1] <- TARGET_COL - # Order transcripts to match annotation. - dt <- merge(annot[, c(TARGET_COL), with=FALSE], dt, by=TARGET_COL, all=TRUE) - return (dt) }, mc.cores = min(threads,lgth[cond]), mc.preschedule = TRUE, mc.allow.recursive = FALSE) + # If single measurement for all samples, ie. est_counts instead of bootsraps, merge and unnest to meet un-bootsrapped format. + if( sum(vapply(boots, function(b){length(b)-1}, numeric(1))) == length(boots) ) { + boots <- Reduce(merge, boots) + } + return (boots) }) - names(res) <- c("boot_data_A", "boot_data_B") + if (is.data.table(res[[1]])) { + names(res) <- c("count_data_A", "count_data_B") + } else { + names(res) <- c("boot_data_A", "boot_data_B") + } + return(res) } diff --git a/man/fish4rodents.Rd b/man/fish4rodents.Rd index b1b7c6f..3c1af67 100644 --- a/man/fish4rodents.Rd +++ b/man/fish4rodents.Rd @@ -2,11 +2,18 @@ % Please edit documentation in R/input.R \name{fish4rodents} \alias{fish4rodents} -\title{Import abundances directly from salmon and kallisto output.} +\title{Import abundances directly from kallisto output.} \usage{ -fish4rodents(A_paths, B_paths, annot, TARGET_COL = "target_id", - PARENT_COL = "parent_id", half_cooked = FALSE, beartext = FALSE, - threads = 1L, scaleto = 1e+06) +fish4rodents( + A_paths, + B_paths, + annot, + TARGET_COL = "target_id", + PARENT_COL = "parent_id", + beartext = FALSE, + threads = 1L, + scaleto = 1e+06 +) } \arguments{ \item{A_paths}{(character) A vector of strings, listing the directory paths to the quantifications for the first condition. One directory per replicate, without trailing path dividers. The directory name should be a unique identifier for the sample.} @@ -19,8 +26,6 @@ fish4rodents(A_paths, B_paths, annot, TARGET_COL = "target_id", \item{PARENT_COL}{The name of the column for the gene identifiers in \code{annot}. (Default \code{"parent_id"})} -\item{half_cooked}{(logical) If TRUE, input is already in \code{Kallisto} h5 format and \code{wasabi} conversion will be skipped. FALSE can also be used to force wasabi to repeat the conversion even if it exists. (Default FALSE)} - \item{beartext}{(logical) Instead of importing bootstrap data from the \code{abundance.h5} file of each sample, import it from plaintext files in a \code{bootstrap} subdirectory created by running \code{kallisto}'s \code{h5dump} subcommand (Default FALSE). This workaround circumvents some mysterious .h5 parsing issues on certain systems.} \item{threads}{(integer) For parallel processing. (Default 1)} @@ -28,15 +33,12 @@ fish4rodents(A_paths, B_paths, annot, TARGET_COL = "target_id", \item{scaleto}{(double) Scaling factor for normalised abundances. (Default 1000000 gives TPM). If a numeric vector is supplied instead, its length must match the total number of samples. The value order should correspond to the samples in group A followed by group B. This allows each sample to be scaled to its own actual library size, allowing higher-throughput samples to carry more weight in deciding DTU.} } \value{ -A list of two, representing the TPM abundances per condition. These will be formatted in the RATs generic bootstrapped data input format. +A list of two, representing the TPM abundances per condition. These will be formatted in the RATs generic data input format, preferably for bootstrapped estimates (if bootstraps are available) or otherwise for plain count estimates. } \description{ -Convert Salmon read counts format to Kallisto RHDF5 format, -then apply TPM normalisation using the info available from the abundance.h5 files. +Apply TPM normalisation using the info available from the abundance.h5 files. } \details{ Converting, normalising and importing multiple bootstrapped abundance files takes a bit of time. IMPORTANT: This function is currently not intended to be used to import non-bootstrapped quantifications. - -\code{wasabi} automatically skips format conversion if a folder already contains an \code{abundance.h5} file. } diff --git a/vignettes/input.R b/vignettes/input.R new file mode 100644 index 0000000..c642cc7 --- /dev/null +++ b/vignettes/input.R @@ -0,0 +1,206 @@ +## ----setup, include=FALSE----------------------------------------------------- +knitr::opts_chunk$set(echo = TRUE) + +## ---- include=FALSE----------------------------------------------------------- +library(rats) + +## ---- echo=FALSE-------------------------------------------------------------- +# Show the first rows of the table corresponding to one sample, from emulated data. +head(sim_boot_data()[[2]][[1]]) + +## ---- echo=FALSE-------------------------------------------------------------- +# Show the first rows of the table corresponding to the annotation, from simulated data. +head(sim_count_data()[[1]]) + +## ---- eval=FALSE-------------------------------------------------------------- +# # Extract transcript ID to gene ID index from a GTF annotation. +# myannot <- gtf2ids("my_annotation_file.gtf") +# +# # Extract transcript ID and gene ID from a GRanges object. +# # It must have GTF-style metadata columns "gene_id" and "transcript_id". +# myannot <- granges2ids(mygranges) + +## ----eval=FALSE--------------------------------------------------------------- +# myannot <- select(mytxdb, keys(mytxdb), "GENEID", "TXNAME") +# # Rename the columns to match what RATs expects. +# names(myannot) <- c('gene_id', 'target_id') + +## ----------------------------------------------------------------------------- +# Simulate some data. +simdat <- sim_count_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated abundances for one condition. +mycond_B <- simdat[[3]] # Simulated abundances for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +## ----------------------------------------------------------------------------- +print( class(mycond_A) ) + +## ----------------------------------------------------------------------------- +# Find DTU between the simulated datasets. +mydtu <- call_DTU(annot= myannot, count_data_A= mycond_A, + count_data_B= mycond_B, verbose= FALSE, + scaling= 1, + name_A= "healthy", name_B= "patients", + varname= "My phenotype", + description="Comparison of two simulated counts datasets + for the tutorial. Simulated using built-in functionality + of RATs.") + +## ----------------------------------------------------------------------------- +# Simulate some data. (Notice it is a different function than before.) +simdat <- sim_boot_data(clean=TRUE) + +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +## ----------------------------------------------------------------------------- +print( class(mycond_A) ) +print( class(mycond_A[[1]]) ) + +## ----------------------------------------------------------------------------- +# Find DTU between conditions. +mydtu <- call_DTU(annot= myannot, boot_data_A= mycond_A, + boot_data_B= mycond_B, verbose= FALSE, + scaling= 1, + name_A= "wildtype", name_B= "some mutant", + varname = "My phenotype", description="Comparison of + two simulated datasets of bootstrapped counts for the + tutorial. Simulated using built-in functionality + of RATs.") + +## ---- eval=FALSE-------------------------------------------------------------- +# # Mock-up code, does not run. +# +# # 1. Collect your outputs into vectors. The end of each path should be a +# # directory with a unique name/identifier for one sample and containing +# # the respective output of Kallisto. +# samples_A <- c("your/path/SAMPLE1", "your/path/SAMPLE4","your/path/SAMPLE5") +# samples_B <- c("your/path/SAMPLE2", "your/path/SAMPLE3","your/path/SAMPLE7", "your/path/SAMPLE10") +# +# # 2. Calculate length- & library-normalised abundances. +# # Scale them to 1M reads for TPM values. +# mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, +# annot= myannot, scaleto=1e6) # scaling to TPM + +## ---- echo=FALSE-------------------------------------------------------------- +simdat <- sim_boot_data(clean=TRUE) +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +## ----------------------------------------------------------------------------- +# Calling DTU with custom thresholds. +mydtu <- call_DTU(annot= myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + p_thresh= 0.01, dprop_thres = 0.15, abund_thresh= 10, + verbose= FALSE) + +## ----------------------------------------------------------------------------- +# Do bootstrap (default). Do 100 iterations. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + qboot = TRUE, qbootnum = 100, qrep_thresh= 0.95, + verbose= FALSE) + +## ----------------------------------------------------------------------------- +# Bootstrap (default). +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + rboot = TRUE, qrep_thresh= 0.85, verbose= FALSE) + +## ----------------------------------------------------------------------------- +# Extra info on variance across iterations. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + lean = FALSE, verbose= FALSE) + +## ---- eval=FALSE-------------------------------------------------------------- +# # The following code is for demonstration only and won't run +# # without valid paths supplied to fish4rodents(). +# +# # The following are equivalent. +# +# # 1: +# # Scale to individual library sizes directly at the import step. +# mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, +# annot= myannot, +# scaleto= c(25123456, 2665431, 23131313, +# 5000000, 45123132, 48456654, 52363636), +# verbose= FALSE) +# # No additional scaling needed. +# mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, +# boot_data_B= mydata$boot_data_B, +# scaling= 1, # default +# verbose= FALSE) +# +# # 2: +# # Normalise quantifications but do not scale them at all. +# mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, +# annot= myannot, +# scaleto=1) +# # Scale library fractions to the library sizes. +# mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, +# boot_data_B= mydata$boot_data_B, +# scaling= c(25123456, 2665431, 23131313, 5000000, +# 45123132, 48456654, 52363636), +# verbose= FALSE) +# +# # 3: +# # Scale Kallisto quantifications to TPMs. +# mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, +# annot= myannot, +# scaleto= 1000000) # default +# # Scale TPMs to individual library sizes. +# mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, +# boot_data_B= mydata$boot_data_B, +# scaling=c(25.123456, 26.65431, 23.131313, 50.0, 45.123132, 48.456654, 52.363636), +# verbose= FALSE) + +## ---- eval=FALSE-------------------------------------------------------------- +# # Using 4 threads for parallel computing. +# mydtu <- call_DTU(annot = myannot, +# boot_data_A= mycond_A, boot_data_B= mycond_B, +# threads = 4, verbose= FALSE) + +## ----------------------------------------------------------------------------- +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + use_sums = TRUE, verbose= FALSE) + +## ----------------------------------------------------------------------------- +# Bonferroni correction. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + correction = "bonferroni", verbose= FALSE) + +## ----------------------------------------------------------------------------- +# Transcripts only. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + testmode="transc", verbose= FALSE) +# Genes only. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + testmode="genes", verbose= FALSE) + +## ---- echo=FALSE-------------------------------------------------------------- +simdat <- sim_boot_data(clean=TRUE, PARENT_COL='gene', TARGET_COL='transcript') +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +## ----------------------------------------------------------------------------- +# Call DTU using annotation with custom field names. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + TARGET_COL="transcript", PARENT_COL="gene", + verbose= FALSE) + +## ---- eval=FALSE-------------------------------------------------------------- +# mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, +# boot_data_B= mydata$boot_data_B, +# reckless=TRUE, verbose=TRUE) + diff --git a/vignettes/input.html b/vignettes/input.html new file mode 100644 index 0000000..a7ae091 --- /dev/null +++ b/vignettes/input.html @@ -0,0 +1,720 @@ + + + + + + + + + + + + + + + +RATs: Input and Settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ + + + + + + +
+
+

Input formats

+
+

Data

+

RATs can work with several input types:

+
    +
  1. Kallisto quantifications in plain-text or RHDF5 format.
  2. +
  3. Bootstrapped abundance estimates in lists of R data.tables.
  4. +
  5. Abundance estimates in R data.tables.
  6. +
+

For option 1, the function fish4rodents() will load the data into tables suitable for options 2 or 3 accordingly. Details in the respective section below. For options 2 and 3, the format of the tables is as in the example below. The first column contains the transcript identifiers and subsequent columns contain the abundances.

+
##    target  V1  V2  V3
+## 1: SOLO.1 100 100 100
+## 2: SAME_1 200 200 200
+## 3: SAME_2 300 300 300
+## 4: LONE.a 150 150 150
+## 5: D2TE_a 300 300 300
+## 6: D2TE_b 400 400 400
+
    +
  • In the case of option 3, each column represents a sample. Each condition is represented by a single such table.
  • +
  • In the case of option 2, each column represents a bootstrap iteration and each table represents a sample. Each condition is represented by a list of such tables.
  • +
+
+

Read counts, TPMs, etc

+

To get the best results, we recommend obtaining TPM abundances, so as to account for differing transcript lengths, and then scaling these values to your actual library sizes to regain count-like magnitudes. You can scale all libraries to the depth of your shallowest library for equal weight of all samples, or you can scale each sample to its own library if depths vary greatly and you want the deeper libraries to carry more weight.

+

RATs provides parameters to scale the length-normalized abundances per sample to meet this requirement.

+
+
+
+

Annotation

+

RATs also needs to know how to group transcripts together. This is achieved with a simple data.frame or data.table that matches transcript identifiers to gene identifiers. The expected column labels are target_id for the transcript IDs and parent_id for the gene IDs. Additional columns are allowed to be present but will be ignored. The minimal annotation table should look like this:

+
##   target_id parent_id
+## 1       SW2        SW
+## 2    D2TE_b      D2TE
+## 3    SAME_1      SAME
+## 4    SAME_2      SAME
+## 5    LONE.a      LONE
+## 6    D2TE_a      D2TE
+

RATs provides functionality to create this table from a GTF file or a GRanges object with GTF-style metadata columns. (Note: GFF3 is not supported for this)

+
# Extract transcript ID to gene ID index from a GTF annotation.
+myannot <- gtf2ids("my_annotation_file.gtf")
+
+# Extract transcript ID and gene ID from a GRanges object. 
+# It must have GTF-style metadata columns "gene_id" and "transcript_id".
+myannot <- granges2ids(mygranges)
+

Extracting the ID pairs from a TxDb object is simpler and does not require a dedicated helper function:

+
myannot <- select(mytxdb, keys(mytxdb), "GENEID", "TXNAME")
+# Rename the columns to match what RATs expects.
+names(myannot) <- c('gene_id', 'target_id')
+
+
+
+
+

Calling DTU

+

As input data, we will use the data emulators that RATs uses in its code tests. These “data” are extremely limited and completely fictional, but are adequate to demonstrate data format and command syntax. If RATs issues warnings about the emulated dataset being too small, disregard them for this tutorial, they are meant for real datasets.

+
+

DTU from abundance estimates, without bootstraps

+

This is the simplest usage case.

+

First, let’s emulate some data to work with:

+
# Simulate some data.
+simdat <- sim_count_data(clean=TRUE)
+# For convenience let's assign the contents of the list to separate variables
+mycond_A <- simdat[[2]]       # Simulated abundances for one condition.
+mycond_B <- simdat[[3]]       # Simulated abundances for other condition.
+myannot <- simdat[[1]]        # Transcript and gene IDs for the above data.
+

Each condition is a single data.table:

+
print( class(mycond_A) )
+
## [1] "data.table" "data.frame"
+

Now we can call DTU:

+
# Find DTU between the simulated datasets.
+mydtu <- call_DTU(annot= myannot, count_data_A= mycond_A, 
+                  count_data_B= mycond_B, verbose= FALSE,
+                  scaling= 1,
+                  name_A= "healthy", name_B= "patients", 
+                  varname= "My phenotype",
+                  description="Comparison of two simulated counts datasets 
+                  for the tutorial. Simulated using built-in functionality 
+                  of RATs.")
+
## Summarising bootstraps...
+
+

Mandatory arguments:

+
    +
  1. annot - An annotation data frame, as described in the Input formats section.
  2. +
  3. count_data_A and count_data_B - Each is a data.table of transcript abundances as described in the Input formats section. They should contain length-normalized values, like TPMs or pseudocounts by up-scaled TPMs.
  4. +
  5. scaling - A vector of scaling factors (one per sample), or a single scaling factor to be applied to all samples. This parameter is mandatory if input is TPM, but can be omitted if abundances are pre-scaled.
  6. +
+
+
+

Optional arguments (will be recorded in the output object, but have no effect on the run):

+
    +
  • name_A, name_B - A name for each conditon.
  • +
  • varname - The name of the variable/condition.
  • +
  • description - Free-text description.
  • +
+
+
+
+

DTU from bootstrapped abundance estimates

+

First, let’s emulate some data, as we did before.

+
# Simulate some data. (Notice it is a different function than before.)
+simdat <- sim_boot_data(clean=TRUE)
+
+# For convenience let's assign the contents of the list to separate variables
+mycond_A <- simdat[[2]]   # Simulated bootstrapped data for one condition.
+mycond_B <- simdat[[3]]   # Simulated bootstrapped data for other condition.
+myannot <- simdat[[1]]    # Transcript and gene IDs for the above data.
+

Each condition is a list of data.table objects:

+
print( class(mycond_A) )
+
## [1] "list"
+
print( class(mycond_A[[1]]) )
+
## [1] "data.table" "data.frame"
+

Now we can call DTU:

+
# Find DTU between conditions.
+mydtu <- call_DTU(annot= myannot, boot_data_A= mycond_A, 
+                  boot_data_B= mycond_B, verbose= FALSE, 
+                  scaling= 1,
+                  name_A= "wildtype", name_B= "some mutant", 
+                  varname = "My phenotype", description="Comparison of 
+                  two simulated datasets of bootstrapped counts for the 
+                  tutorial. Simulated using built-in functionality 
+                  of RATs.")
+
## Summarising bootstraps...
+
+

Mandatory arguments:

+
    +
  1. annot - An annotation data frame, as described in the Input formats section.
  2. +
  3. boot_data_A and boot_data_B - Each is a list of data.table objects, as described in the Input section. They should contain length-normalized values, like TPMs or pseudocounts by up-scaled TPMs.
  4. +
  5. scaling - A vector of scaling factors (one per sample), or a single scaling factor to be applied to all samples. This parameter is mandatory if input is TPM, but can be omitted if abundances are pre-scaled.
  6. +
+
+
+

Optional arguments (will be recorded in the output object, but have no effect on the run):

+
    +
  • name_A, name_B - A name for each condition.
  • +
  • varname - The name of the variable/condition.
  • +
  • description - Free-text description.
  • +
+
+
+
+

DTU with Kallisto output

+

The raw abundances are normalised to TPM (default). Consider instead providing the real depth of your libraries.

+
# Mock-up code, does not run.
+
+# 1. Collect your outputs into vectors. The end of each path should be a 
+#    directory with a unique name/identifier for one sample and containing
+#    the respective output of Kallisto.
+samples_A <- c("your/path/SAMPLE1", "your/path/SAMPLE4","your/path/SAMPLE5")
+samples_B <- c("your/path/SAMPLE2", "your/path/SAMPLE3","your/path/SAMPLE7", "your/path/SAMPLE10")
+
+# 2. Calculate length- & library-normalised abundances. 
+#    Scale them to 1M reads for TPM values.
+mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, 
+                       annot= myannot, scaleto=1e6) # scaling to TPM
+

The output is a list, containing either two lists of data.table objects of bootstrapped data or just two data.tables of non-bootstrapped data, as per the input formats specifications. Then follow the respective example for the data type, as already covered above.

+
+

Mandatory arguments (fish4rodents):

+
    +
  1. A_paths and B_paths - Two vectors containing the paths to the quantification output directories, one vector for each condition. The last segments of each path should be a directory with a unique identifying name for a single sample.
  2. +
  3. annot - An annotation data frame, as described in the Input formats section.
  4. +
+
+
+

Optional arguments (fish4rodents):

+
    +
  • scaleto - Library depth to aim for. (Default 1000000 gives TPM values).
  • +
  • beartext - directs fish4rodents() to read bootstrap data from plain-text files in a bootstraps subdirectory in each sample, instead of parsing the abundance.h5 file of the sample. (Default FALSE)
  • +
+
+
+
+
+
+

Advanced Parameters and Settings

+
+

Main Thresholds

+

The following three main thresholds are used in RATs:

+
# Calling DTU with custom thresholds.
+mydtu <- call_DTU(annot= myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  p_thresh= 0.01, dprop_thres = 0.15, abund_thresh= 10,
+                  verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. p_thresh - Statistical significance level. (Default 0.05, very permissive)
  2. +
  3. dprop_thresh - Effect size threshold: The minimum difference in the isoform’s proportion between the two conditions. (Default 0.20, quite strict)
  4. +
  5. abund_thresh - Noise threshold: (i) The minimum mean (across replicates) abundance, in at least one condition, for a transcript to be considered expressed. (ii) Also the minimum cumulative abundance of all isoforms of a gene in each of the two conditions. (Default 5, very permissive)
  6. +
+

Depending on the settings, additional thresholds are available and will be discussed in their respective sections below.

+
+
+

Bootstrapping

+

RATs offers two types of bootstrapping:

+
    +
  1. Bootstrapping of significance and effect size against the variability in the quantifications. This requires bootstrapped quantifications as input.
  2. +
  3. Bootstrapping of significance and effect size against the variability among replicates.
  4. +
+

Enabling these two procedures assesses the robustness of the DTU calls. In both cases, what is measured is the fraction of iterations in which the significance and effect size meet their respective thresholds. Note If bootstrapping is switched off, the respective fields will not be included in the output.

+
+

Quantification bootstraping

+

In this process, one quantification iteration will be randomly selected from each sample and DTU will be called on it. This will be repeated qbootnum times.

+

Three parameters control bootstrapping of DTU calls against the fluctuations in the quantification:

+
# Do bootstrap (default). Do 100 iterations.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  qboot = TRUE, qbootnum = 100, qrep_thresh= 0.95,
+                  verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. qboot - Whether to bootstrap against the quantifications. (Default TRUE)
  2. +
  3. qbootnum - Number of bootstrap iterations. Ignored if qboot=FALSE. 0 is a special value prompting RATs to infer a value from the data (currently equal to the number of bootstraps in the data). (Default 0)
  4. +
  5. qrep_thresh - Reproducibility threshold: The minimum fraction of the iterations that have to agree on a result to consider it confident. To calculate the reproducibility without factoring it into the DTU classification, set the threshold to 0. Ignored if qboot=FALSE. (Default 0.95)
  6. +
+
+
+

Replicate bootstraping

+

In this process, all the 1 vs. 1 combinations of samples, one from each condition, are used to bootstrap the variation across replicates.

+

Two parameters control bootstrapping of DTU calls against the samples:

+
# Bootstrap (default).
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  rboot = TRUE, qrep_thresh= 0.85, verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. rboot - Whether to bootstrap the replicates or not. (Default TRUE)
  2. +
  3. rrep_thresh - Reproducibility threshold: The minimum fraction of the iterations that have to agree on a result to consider it confident. Ignored if rboot=FALSE. To calculate the reproducibility without factoring it in the DTU classification, set the threshold to 0. (Default 0.85)
  4. +
+

Note that for few replicates per condition, the reproducibility values are highly discrete. For example, the number of iterations for 2 samples per condition is 2 * 2 = 4. So the minimum disagreement rate is 1 / 4 = 0.25, or conversely a reproducibility of 3/4 = 0.75. The default threshold value of 0.85 is based on 3 replicates per condition, meaning 9 iterations and aiming for 8/9=0.889 agreement.

+
+
+

Extra bootstrapping info

+

Additional information on the range, variance and centre of the effect size and p-value across bootstrap iterations can be calculated on request. This requires keeping the full raw results for every iteration in memory and can have a considerable footprint that scales with the number of transcripts and iterations. This is controlled by the lean parameter.

+
# Extra info on variance across iterations.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  lean = FALSE, verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. lean - Keep a light memory footprint but reporting only the reproducibility rate, without spread statistics. (Default TRUE)
  2. +
+
+
+
+

Abundance scaling and normalisation

+

Unlike Differential Transcript/Gene Expression, where libraries must be normalised for size so that expression values are comparable, abundances for Differential Transcript Usage are normalised to the expression of the respective individual gene. Therefore, RATs does not require the libraries to have the same size.

+

For flexibility with different types of input, scaling can be applied in either/both of two stages: The data import step by fish4rodents(), or/and the actual testing step by call_DTU(). The import applies length normalization and by default scales to 1 million. Such values are useful to have for use in other analyses. These TPMs can then be re-scaled to length-normalized pseudo-counts that reflect the library sizes.

+

Both fish4rodents() and call_DTU() support scaling by a single value or a vector of values.

+
# The following code is for demonstration only and won't run
+# without valid paths supplied to fish4rodents().
+
+# The following are equivalent.
+
+# 1:
+# Scale to individual library sizes directly at the import step.
+mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, 
+                       annot= myannot, 
+                       scaleto= c(25123456, 2665431, 23131313, 
+                                 5000000, 45123132, 48456654, 52363636),
+                       verbose= FALSE)
+# No additional scaling needed.
+mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, 
+                  boot_data_B= mydata$boot_data_B, 
+                  scaling= 1,  # default
+                  verbose= FALSE)  
+
+# 2:
+# Normalise quantifications but do not scale them at all.
+mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, 
+                       annot= myannot, 
+                       scaleto=1)
+# Scale library fractions to the library sizes.
+mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, 
+                  boot_data_B= mydata$boot_data_B,  
+                  scaling= c(25123456, 2665431, 23131313, 5000000, 
+                            45123132, 48456654, 52363636), 
+                  verbose= FALSE)
+
+# 3:
+# Scale Kallisto quantifications to TPMs.
+mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, 
+                       annot= myannot, 
+                       scaleto= 1000000)  # default
+# Scale TPMs to individual library sizes.
+mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, 
+                  boot_data_B= mydata$boot_data_B,
+                  scaling=c(25.123456, 26.65431, 23.131313, 50.0, 45.123132, 48.456654, 52.363636), 
+                  verbose= FALSE)
+

Take care to ensure that the scaling you apply is appropriate.

+

Note that if you simply run both methods with their respective scaling defaults, you’ll effectively run RATs on TPM values, which is extremely underpowered and not recommended.

+
+
+

Multi-threading

+

RATs completion time depends on the number of annotated and expressed transcripts. Single-threaded, RATs can take up to a few minutes per iteration, for large annotations. Fortunately, the task is parallelisable:

+
# Using 4 threads for parallel computing.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  threads = 4, verbose= FALSE)
+
    +
  1. threads - The number of threads to use. (Default 1)
  2. +
+

There are some limitations imposed by R. Refer to the parallel package for details (RATs uses the mclapply family of parallel functions).

+
+
+

Combining replicates

+

Up to and including version 0.6.5, RATs combined the isoform abundance values across replicates by summing them. The resulting values are thus larger and pass the significance test more easily, increasing sensitivity. But this can also boost false positives.

+

Now, instead, the user is given the choice between sums and means. By default RATs now uses the means instead of the sums.

+
mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  use_sums = TRUE, verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. use_sums - Whether to test the sum of abundances across replicates, instead of their mean. (Default FALSE)
  2. +
+
+
+

Correction for multiple testing

+

There are as many null hypotheses tested as there are genes (for the gene-level results) or transcripts (for the transcript-level results). The default correction method is BH (Benjamini-Hochberg). A full list of options is listed in R’s p.adjust.methods.

+
# Bonferroni correction.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  correction = "bonferroni", verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. correction - Type of multiple testing correction. (Default “BH”)
  2. +
+
+
+

Test selection

+

RATs runs both gene-level DTU calls and transcript-level DTU calls. They are independent from one another and we consider them complementary and recommend using them together, but the option to skip either is provided, for special use cases. The output fields of the skipped test will be filled with NA.

+
# Transcripts only.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  testmode="transc", verbose= FALSE)
+
## Summarising bootstraps...
+
# Genes only.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  testmode="genes", verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. testmode - Which test(s) to run {“transc”, “genes”, “both”}. (Default “both”)
  2. +
+
+
+

Input field names

+
+

Annotation field names

+

Although it is easy to rename the columns of a table to comply with the expected names, this may sometimes be undesireable, so RATs allows you to change the expected names instead.

+
# Call DTU using annotation with custom field names.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  TARGET_COL="transcript", PARENT_COL="gene",
+                  verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. TARGET_COL - The name of the field holding the transcript identifiers in the annotation data frame. (Default “target_id”)
  2. +
  3. PARENT_COL - The name of the field holding the respective gene identifiers in the annotation data frame. (Default “parent_id”)
  4. +
+

The TARGET_COL and PARENT_COL parameters are also available for fish4rodents().

+
+
+
+

Annotation discrepancies

+

RATs will abort the run if the set of feature IDs in the provided annotation does not match fully the set of IDs in the quantifications. If this happens, ensure you are using the exact same annotation throughout your workflow.

+

For special use cases, RATs provides the option to ignore the discrepancy and pretend everything is OK. Do this at your own risk.

+
mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, 
+                  boot_data_B= mydata$boot_data_B,
+                  reckless=TRUE, verbose=TRUE)
+
    +
  1. reckless - Ignore inconsistent set of IDs between annotation and quantifications. (Default FALSE)
  2. +
+

In reckless mode, all internal operations and the output of RATs are based on the annotation provided:

+
    +
  • Any transcript IDs present in the data but missing from the annotation will be ignored and will not show up in the output at all, as they cannot be matched to the gene IDs.
  • +
  • Any transcript ID present in the annotation but missing from the data will be included in the output as zero expression. They can be identified later as NA values in $Transcripts[, .(stdevA, stdevB)] as these fields are not used downstream by RATs. NA values in other numeric fields are explicitly overwritten with 0 to allow downstream interoperability.
  • +
+
+
+
+
+

Contact information

+

The rats R package was developed within The Barton Group at The University of Dundee by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch.

+

To report problems or ask for assistance, please raise a new issue on the project’s support forum. Providing a reproducible working example that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure to read the vignette(s), and browse/search the support forum before posting a new issue, in case your question is already answered there.

+

Enjoy!

+

+
+ + + +
+
+ +
+ + + + + + + + + + + + + + + + diff --git a/vignettes/input.md b/vignettes/input.md new file mode 100644 index 0000000..daf1515 --- /dev/null +++ b/vignettes/input.md @@ -0,0 +1,596 @@ +--- +title: 'RATs: Input and Settings' +author: "Kimon Froussios" +date: "31 MAR 2022" +output: + html_document: + keep_md: yes + theme: readable + toc: yes + toc_float: yes +vignette: > + \usepackage[utf8]{inputenc} + %\VignetteIndexEntry{RATs 1: Input & Settings} + %\VignetteEngine{knitr::rmarkdown} +--- + + + + + + +*** + +# Input formats + +## Data + +RATs can work with several input types: + +1. [Kallisto](http://pachterlab.github.io/kallisto/) quantifications in plain-text or RHDF5 format. +2. Bootstrapped abundance estimates in lists of R `data.table`s. +3. Abundance estimates in R `data.table`s. + +For option 1, the function `fish4rodents()` will load the data into tables suitable for options 2 or 3 accordingly. +Details in the respective section below. For options 2 and 3, the format of the tables is as in the example below. +The first column contains the transcript identifiers and subsequent columns contain the abundances. + + +``` +## target V1 V2 V3 +## 1: SOLO.1 100 100 100 +## 2: SAME_1 200 200 200 +## 3: SAME_2 300 300 300 +## 4: LONE.a 150 150 150 +## 5: D2TE_a 300 300 300 +## 6: D2TE_b 400 400 400 +``` + +* In the case of option 3, each column represents a sample. Each condition is represented by a single such table. +* In the case of option 2, each column represents a bootstrap iteration and each table represents a sample. Each +condition is represented by a list of such tables. + +### Read counts, TPMs, etc + +To get the best results, we recommend obtaining TPM abundances, so as to account for differing transcript lengths, and then scaling these values to your actual library sizes to regain count-like magnitudes. +You can scale all libraries to the depth of your shallowest library for equal weight of all samples, or you can scale each sample to its own library if depths vary greatly and you want the deeper libraries to carry more weight. + +RATs provides parameters to scale the length-normalized abundances per sample to meet this requirement. + +## Annotation + +RATs also needs to know how to group transcripts together. This is achieved with a simple `data.frame` or `data.table` that matches transcript identifiers to gene identifiers. The expected column labels are `target_id` for the transcript IDs and `parent_id` for the gene IDs. Additional columns are allowed to be present but will be ignored. The minimal annotation table should look like this: + + +``` +## target_id parent_id +## 1 SW2 SW +## 2 D2TE_b D2TE +## 3 SAME_1 SAME +## 4 SAME_2 SAME +## 5 LONE.a LONE +## 6 D2TE_a D2TE +``` + +RATs provides functionality to create this table from a GTF file or a `GRanges` object with GTF-style metadata columns. +(**Note:** GFF3 is not supported for this) + + +```r +# Extract transcript ID to gene ID index from a GTF annotation. +myannot <- gtf2ids("my_annotation_file.gtf") + +# Extract transcript ID and gene ID from a GRanges object. +# It must have GTF-style metadata columns "gene_id" and "transcript_id". +myannot <- granges2ids(mygranges) +``` + +Extracting the ID pairs from a `TxDb` object is simpler and does not require a dedicated helper function: + + +```r +myannot <- select(mytxdb, keys(mytxdb), "GENEID", "TXNAME") +# Rename the columns to match what RATs expects. +names(myannot) <- c('gene_id', 'target_id') +``` + + +*** + + +# Calling DTU + + +As input data, we will use the data emulators that RATs uses in its code tests. +These "data" are extremely limited and completely fictional, but are adequate to demonstrate data format and command syntax. +If RATs issues *warnings* about the emulated dataset being too small, disregard them for this tutorial, they are meant for real datasets. + +### DTU from abundance estimates, without bootstraps + +This is the simplest usage case. + +First, let's emulate some data to work with: + + +```r +# Simulate some data. +simdat <- sim_count_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated abundances for one condition. +mycond_B <- simdat[[3]] # Simulated abundances for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. +``` + +Each condition is a single data.table: + + +```r +print( class(mycond_A) ) +``` + +``` +## [1] "data.table" "data.frame" +``` + +Now we can call DTU: + + +```r +# Find DTU between the simulated datasets. +mydtu <- call_DTU(annot= myannot, count_data_A= mycond_A, + count_data_B= mycond_B, verbose= FALSE, + scaling= 1, + name_A= "healthy", name_B= "patients", + varname= "My phenotype", + description="Comparison of two simulated counts datasets + for the tutorial. Simulated using built-in functionality + of RATs.") +``` + +``` +## Summarising bootstraps... +``` + +#### Mandatory arguments: + +1. `annot` - An annotation data frame, as described in the Input formats section. +2. `count_data_A` and `count_data_B` - Each is a `data.table` of transcript abundances as described in the Input formats section. They should contain length-normalized values, like TPMs or pseudocounts by up-scaled TPMs. +3. `scaling` - A vector of scaling factors (one per sample), or a single scaling factor to be applied to all samples. This parameter is mandatory if input is TPM, but can be omitted if abundances are pre-scaled. + +#### Optional arguments (will be recorded in the output object, but have no effect on the run): + +* `name_A`, `name_B` - A name for each conditon. +* `varname` - The name of the variable/condition. +* `description` - Free-text description. + + + +### DTU from bootstrapped abundance estimates + +First, let's emulate some data, as we did before. + + +```r +# Simulate some data. (Notice it is a different function than before.) +simdat <- sim_boot_data(clean=TRUE) + +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. +``` + +Each condition is a list of `data.table` objects: + + +```r +print( class(mycond_A) ) +``` + +``` +## [1] "list" +``` + +```r +print( class(mycond_A[[1]]) ) +``` + +``` +## [1] "data.table" "data.frame" +``` + +Now we can call DTU: + + +```r +# Find DTU between conditions. +mydtu <- call_DTU(annot= myannot, boot_data_A= mycond_A, + boot_data_B= mycond_B, verbose= FALSE, + scaling= 1, + name_A= "wildtype", name_B= "some mutant", + varname = "My phenotype", description="Comparison of + two simulated datasets of bootstrapped counts for the + tutorial. Simulated using built-in functionality + of RATs.") +``` + +``` +## Summarising bootstraps... +``` + +#### Mandatory arguments: + +1. `annot` - An annotation data frame, as described in the *Input formats* section. +2. `boot_data_A` and `boot_data_B` - Each is a list of `data.table` objects, as described in the Input section. They should contain length-normalized values, like TPMs or pseudocounts by up-scaled TPMs. +3. `scaling` - A vector of scaling factors (one per sample), or a single scaling factor to be applied to all samples. This parameter is mandatory if input is TPM, but can be omitted if abundances are pre-scaled. + +#### Optional arguments (will be recorded in the output object, but have no effect on the run): + +* `name_A`, `name_B` - A name for each condition. +* `varname` - The name of the variable/condition. +* `description` - Free-text description. + + +### DTU with Kallisto output + +The raw abundances are normalised to TPM (default). Consider instead providing the real depth of your libraries. + + +```r +# Mock-up code, does not run. + +# 1. Collect your outputs into vectors. The end of each path should be a +# directory with a unique name/identifier for one sample and containing +# the respective output of Kallisto. +samples_A <- c("your/path/SAMPLE1", "your/path/SAMPLE4","your/path/SAMPLE5") +samples_B <- c("your/path/SAMPLE2", "your/path/SAMPLE3","your/path/SAMPLE7", "your/path/SAMPLE10") + +# 2. Calculate length- & library-normalised abundances. +# Scale them to 1M reads for TPM values. +mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, + annot= myannot, scaleto=1e6) # scaling to TPM +``` + +The output is a list, containing either two lists of `data.table` objects of bootstrapped data or just two `data.table`s of non-bootstrapped data, as per the input formats specifications. Then follow the respective example for the data type, as already covered above. + +#### Mandatory arguments (`fish4rodents`): + +1. `A_paths` and `B_paths` - Two vectors containing the paths to the quantification output directories, one vector for each condition. The +last segments of each path should be a directory with a unique identifying name for a single sample. +2. `annot` - An annotation data frame, as described in the Input formats section. + +#### Optional arguments (`fish4rodents`): + +* `scaleto` - Library depth to aim for. (Default 1000000 gives TPM values). +* `beartext` - directs `fish4rodents()` to read bootstrap data from plain-text files in a `bootstraps` subdirectory in each sample, instead of parsing the abundance.h5 file of the sample. (Default FALSE) + + + +*** + + +# Advanced Parameters and Settings + + + +## Main Thresholds + +The following three main thresholds are used in RATs: + + +```r +# Calling DTU with custom thresholds. +mydtu <- call_DTU(annot= myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + p_thresh= 0.01, dprop_thres = 0.15, abund_thresh= 10, + verbose= FALSE) +``` + +``` +## Summarising bootstraps... +``` + +1. `p_thresh` - Statistical significance level. (Default 0.05, very permissive) +2. `dprop_thresh` - Effect size threshold: The minimum difference in the isoform's proportion between the two conditions. (Default 0.20, quite strict) +3. `abund_thresh` - Noise threshold: (i) The minimum mean (across replicates) abundance, in at least one condition, for a transcript to be considered expressed. (ii) Also the minimum cumulative abundance of all isoforms of a gene in each of the two conditions. (Default 5, very permissive) + +Depending on the settings, *additional thresholds* are available and will be discussed in their respective sections below. + + +## Bootstrapping + +RATs offers two types of bootstrapping: + +1. Bootstrapping of significance and effect size against the variability in the quantifications. +This requires bootstrapped quantifications as input. +2. Bootstrapping of significance and effect size against the variability among replicates. + +Enabling these two procedures assesses the robustness of the DTU calls. In both cases, what is measured +is the fraction of iterations in which the significance and effect size meet their respective thresholds. +**Note** If bootstrapping is switched off, the respective fields will not be included in the output. + +### Quantification bootstraping + +In this process, one quantification iteration will be randomly selected from each sample and DTU will be called on it. +This will be repeated `qbootnum` times. + +Three parameters control bootstrapping of DTU calls against the fluctuations in the quantification: + + +```r +# Do bootstrap (default). Do 100 iterations. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + qboot = TRUE, qbootnum = 100, qrep_thresh= 0.95, + verbose= FALSE) +``` + +``` +## Summarising bootstraps... +``` + +1. `qboot` - Whether to bootstrap against the quantifications. (Default TRUE) +2. `qbootnum` - Number of bootstrap iterations. Ignored if `qboot=FALSE`. 0 is a special value prompting RATs to infer a value from the data (currently equal to the number of bootstraps in the data). (Default 0) +3. `qrep_thresh` - Reproducibility threshold: The minimum fraction of the iterations that have to agree on a result to consider it confident. To calculate the reproducibility without factoring it into the DTU classification, set the threshold to 0. Ignored if `qboot=FALSE`. (Default 0.95) + +### Replicate bootstraping + +In this process, all the 1 vs. 1 combinations of samples, one from each condition, are used to bootstrap the variation across replicates. + +Two parameters control bootstrapping of DTU calls against the samples: + + +```r +# Bootstrap (default). +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + rboot = TRUE, qrep_thresh= 0.85, verbose= FALSE) +``` + +``` +## Summarising bootstraps... +``` + +1. `rboot` - Whether to bootstrap the replicates or not. (Default TRUE) +2. `rrep_thresh` - Reproducibility threshold: The minimum fraction of the iterations that have to agree on a result to consider it confident. Ignored if `rboot=FALSE`. To calculate the reproducibility without factoring it in the DTU classification, set the threshold to 0. (Default 0.85) + +**Note** that for few replicates per condition, the reproducibility values are highly discrete. +For example, the number of iterations for 2 samples per condition is `2 * 2 = 4`. +So the minimum disagreement rate is `1 / 4 = 0.25`, or conversely a reproducibility of `3/4 = 0.75`. +The default threshold value of 0.85 is based on 3 replicates per condition, meaning 9 iterations and aiming for `8/9=0.889` agreement. + +### Extra bootstrapping info + +Additional information on the range, variance and centre of the effect size and p-value across bootstrap iterations can be calculated on request. This requires keeping the full raw results for every iteration in memory and can have a considerable footprint that scales with the number of transcripts and iterations. This is controlled by the `lean` parameter. + + +```r +# Extra info on variance across iterations. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + lean = FALSE, verbose= FALSE) +``` + +``` +## Summarising bootstraps... +``` + +1. `lean` - Keep a light memory footprint but reporting only the reproducibility rate, without spread statistics. (Default TRUE) + + +## Abundance scaling and normalisation + +Unlike Differential Transcript/Gene Expression, where libraries must be normalised for size so that expression values are comparable, abundances for Differential Transcript Usage are normalised to the expression of the respective individual gene. Therefore, RATs does not require the libraries to have the same size. + +For flexibility with different types of input, scaling can be applied in either/both of two stages: The data import step by +`fish4rodents()`, or/and the actual testing step by `call_DTU()`. The import applies length normalization and by default scales to 1 million. Such values are useful to have for use in other analyses. These TPMs can then be re-scaled to length-normalized pseudo-counts that reflect the library sizes. + +Both `fish4rodents()` and `call_DTU()` support scaling by a single value or a vector of values. + + +```r +# The following code is for demonstration only and won't run +# without valid paths supplied to fish4rodents(). + +# The following are equivalent. + +# 1: +# Scale to individual library sizes directly at the import step. +mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, + annot= myannot, + scaleto= c(25123456, 2665431, 23131313, + 5000000, 45123132, 48456654, 52363636), + verbose= FALSE) +# No additional scaling needed. +mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, + boot_data_B= mydata$boot_data_B, + scaling= 1, # default + verbose= FALSE) + +# 2: +# Normalise quantifications but do not scale them at all. +mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, + annot= myannot, + scaleto=1) +# Scale library fractions to the library sizes. +mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, + boot_data_B= mydata$boot_data_B, + scaling= c(25123456, 2665431, 23131313, 5000000, + 45123132, 48456654, 52363636), + verbose= FALSE) + +# 3: +# Scale Kallisto quantifications to TPMs. +mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, + annot= myannot, + scaleto= 1000000) # default +# Scale TPMs to individual library sizes. +mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, + boot_data_B= mydata$boot_data_B, + scaling=c(25.123456, 26.65431, 23.131313, 50.0, 45.123132, 48.456654, 52.363636), + verbose= FALSE) +``` + +Take care to ensure that the scaling you apply is appropriate. + +**Note** that if you simply run both methods with their respective scaling defaults, you'll effectively run RATs +on TPM values, which is extremely underpowered and not recommended. + + +## Multi-threading + +RATs completion time depends on the number of annotated and expressed transcripts. Single-threaded, RATs can take up to +a few minutes per iteration, for large annotations. Fortunately, the task is parallelisable: + + +```r +# Using 4 threads for parallel computing. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + threads = 4, verbose= FALSE) +``` + +1. `threads` - The number of threads to use. (Default 1) + +There are some limitations imposed by R. Refer to the `parallel` package for details (RATs uses the `mclapply` family of +parallel functions). + + +## Combining replicates + +Up to and including version `0.6.5`, RATs combined the isoform abundance values across replicates by summing them. +The resulting values are thus larger and pass the significance test more easily, increasing sensitivity. +But this can also boost false positives. + +Now, instead, the user is given the choice between sums and means. By default RATs now uses the means instead of the sums. + + +```r +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + use_sums = TRUE, verbose= FALSE) +``` + +``` +## Summarising bootstraps... +``` + +1. `use_sums` - Whether to test the sum of abundances across replicates, instead of their mean. (Default FALSE) + +## Correction for multiple testing + +There are as many null hypotheses tested as there are genes (for the gene-level results) or transcripts (for the transcript-level results). +The default correction method is `BH` (Benjamini-Hochberg). A full list of options is listed in R's `p.adjust.methods`. + + +```r +# Bonferroni correction. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + correction = "bonferroni", verbose= FALSE) +``` + +``` +## Summarising bootstraps... +``` + +1. `correction` - Type of multiple testing correction. (Default "BH") + + +## Test selection + +RATs runs both gene-level DTU calls and transcript-level DTU calls. They are independent from one another and we consider +them complementary and recommend using them together, but the option to skip either is provided, for special use cases. +The output fields of the skipped test will be filled with `NA`. + + +```r +# Transcripts only. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + testmode="transc", verbose= FALSE) +``` + +``` +## Summarising bootstraps... +``` + +```r +# Genes only. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + testmode="genes", verbose= FALSE) +``` + +``` +## Summarising bootstraps... +``` + +1. `testmode` - Which test(s) to run {"transc", "genes", "both"}. (Default "both") + + +## Input field names + +### Annotation field names + +Although it is easy to rename the columns of a table to comply with the expected names, this may sometimes be undesireable, so RATs +allows you to change the expected names instead. + + + + + +```r +# Call DTU using annotation with custom field names. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + TARGET_COL="transcript", PARENT_COL="gene", + verbose= FALSE) +``` + +``` +## Summarising bootstraps... +``` + +1. `TARGET_COL` - The name of the field holding the transcript identifiers in the annotation data frame. (Default "target_id") +2. `PARENT_COL` - The name of the field holding the respective gene identifiers in the annotation data frame. (Default "parent_id") + +The `TARGET_COL` and `PARENT_COL` parameters are also available for `fish4rodents()`. + + +## Annotation discrepancies + +RATs will abort the run if the set of feature IDs in the provided annotation does not match fully the set of IDs in the quantifications. +If this happens, ensure you are using the exact same annotation throughout your workflow. + +For special use cases, RATs provides the option to ignore the discrepancy and pretend everything is OK. Do this at your own risk. + + +```r +mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, + boot_data_B= mydata$boot_data_B, + reckless=TRUE, verbose=TRUE) +``` + +1. `reckless` - Ignore inconsistent set of IDs between annotation and quantifications. (Default FALSE) + +In reckless mode, all internal operations and the output of RATs are based on the annotation provided: + +* Any transcript IDs present in the data but missing from the annotation will be ignored and will not show up in the output at all, as they cannot be matched to the gene IDs. +* Any transcript ID present in the annotation but missing from the data will be included in the output as zero expression. They can be identified later as `NA` values in `$Transcripts[, .(stdevA, stdevB)]` as these fields are not used downstream by RATs. `NA` values in other numeric fields are explicitly overwritten with `0` to allow downstream interoperability. + +*** + + +# Contact information + +The `rats` R package was developed within [The Barton Group](http://www.compbio.dundee.ac.uk) at [The University of Dundee](http://www.dundee.ac.uk) +by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch. + +To **report problems** or **ask for assistance**, please raise a new issue [on the project's support forum](https://github.com/bartongroup/Rats/issues). +Providing a *reproducible working example* that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure +to **read the vignette(s)**, and browse/search the support forum before posting a new issue, in case your question is already answered there. + +Enjoy! + +![](./figs/rats_logo.png) From d03d92cddf3c84e4840e249cc822c0bae2b68eec Mon Sep 17 00:00:00 2001 From: fruce-ki Date: Wed, 1 Jun 2022 17:23:52 +0200 Subject: [PATCH 3/4] touch up docs and find vignette placement --- .gitignore | 3 - Meta/vignette.rds | Bin 269 -> 269 bytes README.md | 3 + doc/input.R | 101 +-- doc/input.Rmd | 118 +-- doc/input.html | 296 ++++--- doc/output.R | 68 ++ doc/output.Rmd | 291 +++++++ doc/output.html | 624 +++++++++++++++ doc/plots.R | 62 ++ doc/plots.Rmd | 214 ++++++ doc/plots.html | 458 +++++++++++ inst/doc/input.R | 206 +++++ inst/doc/input.Rmd | 516 +++++++++++++ inst/doc/input.html | 720 ++++++++++++++++++ inst/doc/output.R | 68 ++ inst/doc/output.Rmd | 291 +++++++ inst/doc/output.html | 624 +++++++++++++++ inst/doc/plots.R | 62 ++ inst/doc/plots.Rmd | 214 ++++++ inst/doc/plots.html | 458 +++++++++++ man/annot2ids.Rd | 3 +- man/calculate_DTU.Rd | 17 +- man/call_DTU.Rd | 40 +- man/denest_sleuth_boots.Rd | 13 +- man/do_boot.Rd | 20 +- man/granges2ids.Rd | 3 +- man/gtf2ids.Rd | 3 +- man/parameters_are_good.Rd | 30 +- man/plot_gene.Rd | 18 +- man/scale_data.Rd | 11 +- man/sim_boot_data.Rd | 3 +- man/sim_count_data.Rd | 7 +- man/structure_data.Rd | 11 +- vignettes/input.Rmd | 118 +-- vignettes/output.R | 68 ++ vignettes/output.Rmd | 2 +- vignettes/output.html | 624 +++++++++++++++ vignettes/output.md | 441 +++++++++++ vignettes/plots.R | 62 ++ vignettes/plots.html | 458 +++++++++++ vignettes/plots.md | 225 ++++++ .../figure-html/unnamed-chunk-3-1.png | Bin 0 -> 59705 bytes .../figure-html/unnamed-chunk-4-1.png | Bin 0 -> 39399 bytes .../figure-html/unnamed-chunk-9-1.png | Bin 0 -> 30088 bytes 45 files changed, 7156 insertions(+), 418 deletions(-) create mode 100644 doc/output.R create mode 100644 doc/output.Rmd create mode 100644 doc/output.html create mode 100644 doc/plots.R create mode 100644 doc/plots.Rmd create mode 100644 doc/plots.html create mode 100644 inst/doc/input.R create mode 100644 inst/doc/input.Rmd create mode 100644 inst/doc/input.html create mode 100644 inst/doc/output.R create mode 100644 inst/doc/output.Rmd create mode 100644 inst/doc/output.html create mode 100644 inst/doc/plots.R create mode 100644 inst/doc/plots.Rmd create mode 100644 inst/doc/plots.html create mode 100644 vignettes/output.R create mode 100644 vignettes/output.html create mode 100644 vignettes/output.md create mode 100644 vignettes/plots.R create mode 100644 vignettes/plots.html create mode 100644 vignettes/plots.md create mode 100644 vignettes/plots_files/figure-html/unnamed-chunk-3-1.png create mode 100644 vignettes/plots_files/figure-html/unnamed-chunk-4-1.png create mode 100644 vignettes/plots_files/figure-html/unnamed-chunk-9-1.png diff --git a/.gitignore b/.gitignore index 5f4d00d..bff7dc9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,4 @@ .Rhistory .RData *.Rproj - .DS_Store -doc -Meta diff --git a/Meta/vignette.rds b/Meta/vignette.rds index a021e9651b01ea8b82e1b96c7a54556b8d6b27d0..7b9d12e7570259925d114564eeb3a71af105d206 100644 GIT binary patch delta 255 zcmV z+6TB1!lB+r%eW1+Q{`&iTz%QN`NMZ8bzT2FCpyNw)QL1nLoT^{D!>ou_Yd!=x}YNh F001XGen9{L delta 255 zcmV - + - + - + RATs: Input and Settings - + + - - - - - - - - - - + + + + + + + + + + + - + code{white-space: pre-wrap;} + span.smallcaps{font-variant: small-caps;} + span.underline{text-decoration: underline;} + div.column{display: inline-block; vertical-align: top; width: 50%;} + div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} + ul.task-list{list-style: none;} + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ + + + + + + +
+
library(rats)
+library(data.table)
+

Let’s set up an example, using RAT’s data emulator (used for code testing, not suitable for data simulations).

+
# Simulate some data.
+simdat <- sim_boot_data(clean=TRUE) 
+# For convenience let's assign the contents of the list to separate variables
+mycond_A <- simdat[[2]]   # Simulated bootstrapped data for one condition.
+mycond_B <- simdat[[3]]   # Simulated bootstrapped data for other condition.
+myannot <- simdat[[1]]    # Transcript and gene IDs for the above data.
+
+# Call DTU
+mydtu <- call_DTU(annot= myannot, verbose= FALSE,
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  dprop_thresh=0.1, qboot=TRUE, rboot=FALSE)
+
+
+

Output structure

+

The output of RATs is a list containing 4 elements:

+
print( names(mydtu) )
+
## [1] "Parameters"  "Genes"       "Transcripts" "Abundances"
+
+

Parameters

+

Parameters is a list that contains information about the data and the settings for a particular run.

+
# Parameter list's elements.
+print( names(mydtu$Parameters) )
+
##  [1] "description"         "time"                "rats_version"       
+##  [4] "R_version"           "var_name"            "cond_A"             
+##  [7] "cond_B"              "data_type"           "num_replic_A"       
+## [10] "num_replic_B"        "num_genes"           "num_transc"         
+## [13] "tests"               "use_sums"            "correction"         
+## [16] "p_thresh"            "abund_thresh"        "dprop_thresh"       
+## [19] "abund_scaling"       "quant_boot"          "quant_reprod_thresh"
+## [22] "quant_bootnum"       "rep_boot"            "rep_reprod_thresh"  
+## [25] "rep_bootnum"         "seed"                "reckless"           
+## [28] "lean"
+
    +
  • description - (str) Free-text description of the run. It is useful to record data sources, annotation source and version, experimental parameters, etc…
  • +
  • time - (str) Date and time for the run. This does not represent the exact time the run started.
  • +
  • rats_version - (str) The version of RATs.
  • +
  • R_version - (str) The version of R (including OS architecture).
  • +
  • var_name - (str) The value passed to the varname parameter.
  • +
  • cond_A & cond_B - (str) The values passed to the name_A and name_B parameters.
  • +
  • data_type - (str) The format of the input data.
  • +
  • num_replic_A & num_replic_B - (int) The number of samples in each condition.
  • +
  • num_genes - (int) The number of genes in the provided annotation.
  • +
  • num_transc - (int) The number of transcripts in the provided annotation.
  • +
  • tests - (str) The value passed to the testmode parameter.
  • +
  • use_sums - (bool) Sum the replicates instead of averaging them (pre-0.7.0 RATs always summed).
  • +
  • p_thresh - (num) The value passed to the p_thresh parameter.
  • +
  • abund_thresh - (num) The value passed to the abund_thresh parameter.
  • +
  • dprop_thresh - (num) The value passed to the dprop_thresh parameter.
  • +
  • correction - (str) Multiple testing correction method.
  • +
  • abund_scaling - (num) The value(s) passed to the scaling parameter. It will be either a single numeric value or a named vector of values.
  • +
  • quant_boot - (bool) The value passed to the qboots parameter.
  • +
  • quant_reprod_thresh - (num) The value passed to the qrep_thresh parameter, if qboot==TRUE.
  • +
  • quant_bootnum - (int) The value passed to the qbootnum parameter, if qboot==TRUE.
  • +
  • rep_boot - (bool) The value passed to the rboot parameter.
  • +
  • rep_reprod_thresh - (num) The value passed to the rrep_thresh parameter, if rboot==TRUE.
  • +
  • rep_bootnum - (int) The number of replicate bootstrapping iterations (currently M*N, where M and N are the numbers of samples in the two conditions), if rboot==TRUE.
  • +
  • seed - (int) Custom seed for the random generator. NA if none was specified.
  • +
  • reckless - (bool) The value passed to the reckless parameter.
  • +
  • lean - (bool) The value passed to the lean parameter.
  • +
+

Note: If bootstraps are disabled, the bootstrap-related fields may be NA, regardless of supplied values, to reflect the fact that they were not used.

+
+
+

Genes

+

Genes is a data.table listing results at the gene level. For your convenience, the respective aggregated transcript-level DTU calls are also included here (defined as at least one isoform being called DTU individually).

+
# Genes table's fields.
+print( names(mydtu$Genes) )
+
##  [1] "parent_id"      "elig"           "sig"            "elig_fx"       
+##  [5] "quant_reprod"   "DTU"            "transc_DTU"     "known_transc"  
+##  [9] "detect_transc"  "elig_transc"    "maxDprop"       "pval"          
+## [13] "pval_corr"      "quant_na_freq"  "quant_dtu_freq"
+

The first few columns show the result of each decision step in a boolean manner, allowing easy filtering of the table. The remaining columns list the values based on which these decisions were made. Pseudo-code formulas are shown here to help understand how the different fields interact when making decisions.

+
    +
  • parent_id - (str) Gene identifier.
  • +
  • elig - (bool) Eligible for testing. Whether the gene met the pre-filtering criteria. = (elig_transc >= 2).
  • +
  • sig - (bool) Statistically significant. = (pval_corr < Parameters$p_thresh).
  • +
  • elig_fx - (bool) Eligible effect size. Whether at least one of the isoforms meets the effect size criterion. = any(Transcript[parent_id, elig_fx]).
  • +
  • quant_reprod - (bool) Result reproducible across quantification iterations. For positive DTU, = (quant_dtu_freq >= Parameters$quant_reprod_thresh), for non-DTU = (quant_dtu_freq <= 1 - Parameters$quant_reprod_thresh).
  • +
  • rep_reprod - (bool) Result reproducible across replicates. For positive DTU, = (rep_dtu_freq >= Parameters$rep_reprod_thresh), for non-DTU = (rep_dtu_freq <= 1 - Parameters$rep_reprod_thresh).
  • +
  • DTU - (bool) Gene-level Differential Transcript Usage. = (sig & elig_fx & quant_reprod & rep_reprod).
  • +
  • transc_DTU - (bool) Aggregated from Transcripts$DTU: At least one isoform was individually reported as DTU. = (Transcript[ , any(DTU), by=parent_id]).
  • +
  • known_transc - (int) Number of known trascripts for this gene according to the given annotation.
  • +
  • detect_trancs - (int) Number of detected (expressed) transcripts in the given dataset.
  • +
  • elig_transc - (int) Number of eligible transcripts, aggregated from Transcripts$elig.
  • +
  • pval - (num) G test of independence p-value for the isoform ratios of the gene.
  • +
  • pval_corr - (num) Multiple testing corrected p-value. pval_corr= p.adjust(pval, Parameters$correction).
  • +
  • quant_p_median - (num) Median of corrected p-values across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_min - (num) Minimum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_max - (num) Maximum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_na_freq - (num) Fraction of quantification iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • quant_dtu_freq - (num) Fraction of replicate iterations that support a positive DTU classification.
  • +
  • rep_p_median - (num) Median p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_min - (num) Minimum observed p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_max - (num) Maximum observed p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_na_freq - (num) Fraction of replication iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • rep_dtu_freq - (num) Fraction of replication iterations that support a positive DTU classification.
  • +
+

Note: The fields reporting on the bootstraps will not be shown when bootstrapping is disabled.

+
+
+

Transcripts

+

Transcripts is a data.table listing results at the transcript level. For your convenience, the respective gene-level DTU calls are also included here.

+
# Transcripts table's fields.
+print( names(mydtu$Transcripts) )
+
##  [1] "target_id"      "parent_id"      "elig_xp"        "elig"          
+##  [5] "sig"            "elig_fx"        "quant_reprod"   "DTU"           
+##  [9] "gene_DTU"       "abundA"         "abundB"         "stdevA"        
+## [13] "stdevB"         "log2FC"         "totalA"         "totalB"        
+## [17] "propA"          "propB"          "Dprop"          "pval"          
+## [21] "pval_corr"      "quant_na_freq"  "quant_dtu_freq"
+

The first few columns show the result of each decision step in a boolean manner, allowing easy filtering of the table. The remaining columns list the values based on which these decisions were made. Pseudo-code formulas are shown here to help understand how the different fields interact when making decisions.

+
    +
  • target_id - (str) Transcript identifier.
  • +
  • parent_id - (str) Gene identifier.
  • +
  • elig_xp - (bool) Eligible expression level. = (meanA >= Parameters$abund_thresh | meanB >= Parameters$abund_thresh).
  • +
  • elig - (bool) Eligible for testing (meets the noise threshold and at least one other isoform is expressed). = (elig_xp & totalA != 0 & totalB != 0 & (abundA != totalA | abundB != totalB)).
  • +
  • sig - (bool) Statistically significant. = (pval_corr < Parameters$p_thresh).
  • +
  • elig_fx - (bool) Eligible effect size. Proxy for biological significance. = (Dprop > Parameters$dprop_thresh). *. quant_reprod - (bool) Quantification reproducible. For positive DTU, = (quant_dtu_freq >= Parameters$quant_reprod_thresh), for non-DTU = (quant_dtu_freq <= 1 - Parameters$quant_reprod_thresh).
  • +
  • rep_reprod - (bool) Replication reproducible. For positive DTU, = (rep_dtu_freq >= Parameters$rep_reprod_thresh), for non-DTU = (rep_dtu_freq <= 1 - Parameters$rep_reprod_thresh).
  • +
  • DTU - (bool) The Transcript is Differentially Used. = (sig & elig_fx & quant_reprod & rep_reprod).
  • +
  • gene_DTU - (bool) Expanded from Genes$DTU. Indicates that the gene as a whole shows significant change in isoform ratios. = (Genes[parent_id, DTU]).
  • +
  • abundA and abundB - (num) Either the mean or the sum of the abundances across replicates, depending on what is indicated by Parameters$use_sums. This is the value used for the tests.
  • +
  • stdevA and stdevB - (num) The standard deviation of the abundance across the replicates.
  • +
  • log2FC - (num) log2 of fold-change of transcript abundance: = log2(abundB / abundA). abundA and abundB are not internally normalised for library size, so care must be taken when interpreting log2FC.
  • +
  • totalA and totalB - (num) The total abundance for the gene: totalA= sum(transcripts[parent_id, abundA]).
  • +
  • propA and propB - (num) The proportion of the gene expression owed to this transcript. propA= abundA / totalA.
  • +
  • Dprop - (num) The difference in the proportion of the transcript between the two conditions (effect size). = (probB - propA).
  • +
  • pval - (num) The proportion equality test P-value for the transcript.
  • +
  • pval_corr - (num) Multiple testing corrected p-value. = p.adjust(pval, Parameters$correction).
  • +
  • quant_p_median - (num) Median of corrected p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_min - (num) Minimum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_max - (num) Maximum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_mean - (num) Mean effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_stdev - (num) Standard deviation of effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_min - (num) Minimum observed effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_max - (num) Maximum observed effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_na_freq - (num) Fraction of quantification iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • quant_dtu_freq - (num) Fraction of quantification iterations that support a positive DTU classification.
  • +
  • rep_p_median - (num) Median of corrected p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_min - (num) Minimum observed (corrected) p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_max - (num) Maximum observed (corrected) p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_mean - (num) Mean effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_stdev - (num) Standard deviation of effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_min - (num) Minimum observed effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_max - (num) Maximum observed effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_na_freq - (num) Fraction of replication iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • rep_dtu_freq - (num) Fraction of replication iterations that support a positive DTU classification.
  • +
+

Note: The fields reporting on the bootstraps will not be shown when bootstrapping is disabled.

+
+
+

Abundances

+

Abundances is a list of two data.tables, one for each condition. Each transcript is represented by a single abundance value per replicate, so if bootstrapped data was used, these values are the means across iterations. If plain abundances were provided as input, then Abundances essentially contains the input data. These abundances are included in the output because they are required for some of RATs’ plotting options.

+
# Elements of Abundances.
+print( names(mydtu$Abundances) )
+
## [1] "condA" "condB"
+
    +
  1. condA - (num) The transcript abundances in the first condition.
  2. +
  3. condB - (num) The transcript abundances in the second condition.
  4. +
+
# Abundance table for first condition.
+print( head(mydtu$Abundances[[1]]) )
+
##     V1  V2 target_id parent_id
+## 1: 100 115    ALLA:1      ALLA
+## 2:  40  30    ALLA:2      ALLA
+## 3: 300 400    D2TE_a      D2TE
+## 4: 400 500    D2TE_b      D2TE
+## 5: 250 270     1D2TU      D2TU
+## 6: 250 300     2D2TU      D2TU
+
+
+
+
+

Quick results

+

For your convenience, RATs provides a few functions to give you a quick summary of the run. They all follow the same style.

+

These reports should not be seen as a substitute for the detailed RATs output.

+
+

Summary of DTU

+

The dtu_summary() function lists the total number of genes and transcripts for each of 3 categories:

+
    +
  • DTU: There is significant change in isoform ratios (in terms of both effect size and statistical significance).
  • +
  • non-DTU: No significant change.
  • +
  • ineligible: Ineligible for testing. Genes/transcripts with read count below the set threshold, or where the gene has only one known transcript.
  • +
+
# A tally of the outcome.
+print( dtu_summary(mydtu) )
+
##                           category tally
+## 1            DTU genes (gene test)     6
+## 2        non-DTU genes (gene test)     3
+## 3     ineligible genes (gene test)     3
+## 4         DTU genes (transc. test)     6
+## 5     non-DTU genes (transc. test)     3
+## 6  ineligible genes (transc. test)     3
+## 7           DTU genes (both tests)     6
+## 8       non-DTU genes (both tests)     3
+## 9    ineligible genes (both tests)     3
+## 10                 DTU transcripts    14
+## 11             non-DTU transcripts     7
+## 12          ineligible transcripts     5
+

The get_dtu_ids() function lists the coresponding identifiers per category. The ID lists obtained are ordered by effect size (Dprop).

+
# Gene and transcript IDs corresponding to the tally above.
+ids <- get_dtu_ids(mydtu)
+print( names(ids) )
+
##  [1] "DTU genes (gene test)"           "non-DTU genes (gene test)"      
+##  [3] "ineligible genes (gene test)"    "DTU genes (transc. test)"       
+##  [5] "non-DTU genes (transc. test)"    "ineligible genes (transc. test)"
+##  [7] "DTU genes (both tests)"          "non-DTU genes (both tests)"     
+##  [9] "ineligible genes (both tests)"   "DTU transcripts"                
+## [11] "non-DTU transcripts"             "ineligible transcripts"
+
print( ids )
+
## $`DTU genes (gene test)`
+## [1] "XSW"  "MIX"  "SW"   "LC"   "ALLA" "D2TU"
+## 
+## $`non-DTU genes (gene test)`
+## [1] "D2TE" "SAME" "FAKE"
+## 
+## $`ineligible genes (gene test)`
+## [1] "LONE" "SOLO" "NN"  
+## 
+## $`DTU genes (transc. test)`
+## [1] "XSW"  "MIX"  "SW"   "LC"   "ALLA" "D2TU"
+## 
+## $`non-DTU genes (transc. test)`
+## [1] "D2TE" "SAME" "FAKE"
+## 
+## $`ineligible genes (transc. test)`
+## [1] "LONE" "SOLO" "NN"  
+## 
+## $`DTU genes (both tests)`
+## [1] "XSW"  "MIX"  "SW"   "LC"   "ALLA" "D2TU"
+## 
+## $`non-DTU genes (both tests)`
+## [1] "D2TE" "SAME" "FAKE"
+## 
+## $`ineligible genes (both tests)`
+## [1] "LONE" "SOLO" "NN"  
+## 
+## $`DTU transcripts`
+##  [1] "XSW:one" "XSW:two" "MIX.b"   "SW1"     "SW2"     "MIX.a"   "LC1"    
+##  [8] "LC2"     "ALLA:1"  "ALLA:2"  "MIX.ab"  "2D2TU"   "1D2TU"   "MIX.l2" 
+## 
+## $`non-DTU transcripts`
+## [1] "D2TE_b" "D2TE_a" "SAME_1" "SAME_2" "FAKE-2" "FAKE-1" "MIX.l1"
+## 
+## $`ineligible transcripts`
+## [1] "LONE.a" "MIX.n"  "SOLO.1" "NNa"    "NNb"
+
+
+

Summary of isoform switching

+

Isoform switching is a subset of DTU. Primary isoform switching is often considered the most likely type of DTU to have an effect. The following two functions summarise the extent of isoform switching in the results:

+
# A tally of genes switching isoform ranks.
+print( dtu_switch_summary(mydtu) )
+
##                            category genes
+## 1        Primary switch (gene test)     4
+## 2    Non-primary switch (gene test)     1
+## 3     Primary switch (transc. test)     4
+## 4 Non-primary switch (transc. test)     1
+## 5       Primary switch (both tests)     4
+## 6   Non-primary switch (both tests)     1
+
# The gene IDs displaying isoform switching.
+ids <- get_switch_ids(mydtu)
+print( names(ids) )
+
## [1] "Primary switch (gene test)"        "Non-primary switch (gene test)"   
+## [3] "Primary switch (transc. test)"     "Non-primary switch (transc. test)"
+## [5] "Primary switch (both tests)"       "Non-primary switch (both tests)"
+
+
+

Summary of DTU plurality

+

In case you want to know how many isoforms are affected per gene.

+
# A tally of genes switching isoform ranks.
+print( dtu_plurality_summary(mydtu) )
+
##   isof_affected num_of_genes
+## 1             2            5
+## 2             4            1
+
# The gene IDs displaying isoform switching.
+ids <- get_plurality_ids(mydtu)
+

These give you the number and IDs of genes in which 2, 3, etc… isoforms show DTU.

+
+
+
+
+

Contact information

+

The rats R package was developed within The Barton Group at The University of Dundee by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch.

+

To report problems or ask for assistance, please raise a new issue on the project’s support forum. Providing a reproducible working example that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure to read the vignette(s), and browse/search the support forum before posting a new issue, in case your question is already answered there.

+

Enjoy!

+

+
+ + + +
+
+ +
+ + + + + + + + + + + + + + + + diff --git a/doc/plots.R b/doc/plots.R new file mode 100644 index 0000000..4ce996e --- /dev/null +++ b/doc/plots.R @@ -0,0 +1,62 @@ +## ----setup, include=FALSE----------------------------------------------------- +knitr::opts_chunk$set(echo = TRUE) + +## ---- include=FALSE----------------------------------------------------------- +library(rats) + +## ----------------------------------------------------------------------------- +# Simulate some data. +simdat <- sim_boot_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +# Call DTU +mydtu <- call_DTU(annot= myannot, verbose= FALSE, + boot_data_A= mycond_A, boot_data_B= mycond_B, + dprop_thresh=0.1, qboot=TRUE, rboot=FALSE) + +## ----------------------------------------------------------------------------- +# Grouping by condition (DEFAULT): +plot_gene(mydtu, "MIX", style="bycondition") + +## ----------------------------------------------------------------------------- +# Grouping by isoform: +plot_gene(mydtu, "MIX", style="byisoform") + +## ----eval=FALSE--------------------------------------------------------------- +# models <- annot2models('/my/annotation/file.gtf') +# library(ggbio) +# # This will plot the structure of all isoforms for the given gene ID. +# autoplot(models[['mygeneID']]) + +## ---- eval=FALSE-------------------------------------------------------------- +# # Proportion change VS transcript-level significance. Each point is a transcript +# plot_overview(mydtu, type="tvolcano") +# +# # This can also be plotted for genes, by using the largest isoform effect size as proxy. +# plot_overview(mydtu, type="gvolcano") + +## ---- eval=FALSE-------------------------------------------------------------- +# # Distribution of proportion change. +# plot_overview(mydtu, type="dprop") +# +# # Distribution of largest isoform proportion change per gene. +# plot_overview(mydtu, type="maxdprop") + +## ---- eval=FALSE-------------------------------------------------------------- +# # Proportion change VS transcript-level significance. Each point is a transcript +# plot_overview(mydtu, type="fcvolcano") +# +# # This can also be plotted for genes, by using the largest isoform effect size as proxy. +# plot_overview(mydtu, type="fcVSdprop") + +## ----------------------------------------------------------------------------- +# Pairwise Pearson's correlations among samples. +plot_diagnostics(mydtu, type='cormat') # Default type. + +## ---- eval=FALSE-------------------------------------------------------------- +# # Start the interactive volcano plot. +# plot_shiny_volcano(mydtu) + diff --git a/doc/plots.Rmd b/doc/plots.Rmd new file mode 100644 index 0000000..136b08d --- /dev/null +++ b/doc/plots.Rmd @@ -0,0 +1,214 @@ +--- +title: 'RATs: Plots' +author: "Kimon Froussios" +date: "08 JUL 2019" +output: + html_document: + keep_md: yes + theme: readable + toc: yes + toc_float: yes +vignette: > + \usepackage[utf8]{inputenc} + %\VignetteIndexEntry{RATs 3: Plots} + %\VignetteEngine{knitr::rmarkdown} +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = TRUE) +``` + +*** + +```{r, include=FALSE} +library(rats) +``` + +Set up an example. + +```{r} +# Simulate some data. +simdat <- sim_boot_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +# Call DTU +mydtu <- call_DTU(annot= myannot, verbose= FALSE, + boot_data_A= mycond_A, boot_data_B= mycond_B, + dprop_thresh=0.1, qboot=TRUE, rboot=FALSE) +``` + + +*** + + +# Visualisation of results + + +The RATs output object provides a host of information and we encourage users to familiarize themselves with it. +But a good plot is worth a thousand numbers. RATs provides a non-exhaustive set of basic visualisation options for the results. + +The plotting functions return a `ggplot2` object. You can just `print()` it, or assign it to a variable, further customise it with standard [ggplot2](http://ggplot2.org) operations, or even pass it on to other viewing functions, like `plotly::ggplotly()`. + +## Inspection of a given gene + +### Isoform abundances + +This is a very useful function for inspecting a gene of interest. It enables quick visual evaluation of the dispersion of the replicate measurements, the magnitude of the absolute and proportion changes, the presence of outliers, and the consistency among the replicates. + +```{r} +# Grouping by condition (DEFAULT): +plot_gene(mydtu, "MIX", style="bycondition") +``` + +* The top two facets show the absolute abundances (counts) of the isoforms as supplied in the input. +* The bottom two facets show the correspondng relative abundances (proportions). +* The facets on the left ocrrespond to one condition, the facets on the right correspond to the other condition. +* The boxplots describe the abundance distribution of each isoform across replicates. +* The actual abundance measurements are overlayed as points. +* The set of abundances obtained in each replicate is shown by the lines connecting the points. This highlights the level of consistency between the replicates. +* The presence of DTU for each transcript is encoded in the fill and shape of the abundance points. +* The points and lines are placed slightly off-centre to prevent replicates masking one another when the measurements are very similar. +* The colours of the replicates are recycled between the two conditions. So in the example, there are 4 samples: controls-1, controls-2, patients-1 and patients-2. + +When there are many replicates or many isoforms, it may be preferable to group abundances by isoform, making individual comparisons easier: + +```{r} +# Grouping by isoform: +plot_gene(mydtu, "MIX", style="byisoform") +``` + +### Customisation of the abundances plot + +#### Change information layers + +The `fillby`, `colourby` and `shapeby` parameters of `plot_gene()` can be respectively used to control which information layers +are encoded as fill, line/point colour, and point shape. Possible values are `c("isoform", "condition", "DTU", "none", "replicate")`. +Be aware that some combinations of plot style and information layers are not possible. + +#### Change colour code + +Colour codes can be customised by specifying new values to the corresponding parameters of `plot_gene()`: + +* `isofcolvec` - Colour vector for isoform highlighting. Used to build a colorRampPalette. +* `dtucolvec` - Colour vector for DTU highlighting. +* `condcolvec` - Colour vector for condition highlighting. +* `replcolvec` - Colour vector for replicate highlighting. Used to build a colorRampPalette. +* `nonecol` - Colour to use when no colour coding is wanted. + +An example of a colour vector, using standard R colour aliases, would be `c('blue', darkred', 'gold')`. + + +### Structure of the given gene + +With the use of the third-party Bioconductor package [ggbio](https://bioconductor.org/packages/release/bioc/html/ggbio.html), one can plot gene models from `GRanges`/`GRangesList` objects. This can be useful in interpreting transcript expression and DTU. + +Therefore RATs offers a helper function to create an appropriate collection of `GRanges`/`GRangesList` objects from a GTF file. The collection is structured as a list, indexed by the GTF `gene ID` values. Each list element is a `GRangesList` object with the annotated transcripts for that gene. + +```{r eval=FALSE} +models <- annot2models('/my/annotation/file.gtf') +library(ggbio) +# This will plot the structure of all isoforms for the given gene ID. +autoplot(models[['mygeneID']]) +``` + +For more options and more refined plots, refer to the `ggbio` documentation. + + +## Overview plots + +Our simulated dataset is too small to properly demonstrate what these plots might look like. +So, instead, each one is accompanied by a static image of the plot created with a real and much larger dataset. + +Possibly the most common plot in differential expression is the volcano plot, which plots the effect size against +the statistical significance. The thresholds are also shown, although the default significance threshold of 0.05 +is very low (hint: no lines are drawn for the axes). + +```{r, eval=FALSE} +# Proportion change VS transcript-level significance. Each point is a transcript +plot_overview(mydtu, type="tvolcano") + +# This can also be plotted for genes, by using the largest isoform effect size as proxy. +plot_overview(mydtu, type="gvolcano") +``` + +This is what these look like on a larger dataset: +![Transcript significance VS effect size](./figs/tvolcano.jpg) + +You can also get density histograms for the volcanos (the Y axis is square-root compressed): + +```{r, eval=FALSE} +# Distribution of proportion change. +plot_overview(mydtu, type="dprop") + +# Distribution of largest isoform proportion change per gene. +plot_overview(mydtu, type="maxdprop") +``` + +This is what these look like on a larger dataset: +![Effect size distribution](./figs/dprop.jpg) + +Although fold-changes of transcript expression are not tied to DTU, you can plot the traditional FC volcano and the relationship between FC and proportion change. Bear in mind that the FCs will be based on the abundances provided as input, *without any adjustments* such as library size normalization. + +```{r, eval=FALSE} +# Proportion change VS transcript-level significance. Each point is a transcript +plot_overview(mydtu, type="fcvolcano") + +# This can also be plotted for genes, by using the largest isoform effect size as proxy. +plot_overview(mydtu, type="fcVSdprop") +``` + +![Fold change VS significance](./figs/fcvolcano.jpg) +![Fold change VS proportion change](./figs/fcvsdprop.jpg) + + +## Diagnostic plots + +Currently there is only one plot type in this category. + +```{r} +# Pairwise Pearson's correlations among samples. +plot_diagnostics(mydtu, type='cormat') # Default type. +``` + +What you want to see here, is a nice separation between the samples of different conditions. +Anomalies in this plot may indicate batch effects or mislabelled samples. + + +## Interactive plots + +If you prefer picking points from a plot rather than sorting through tables, the gene-level volcano plot is also available through +an interactive `shiny` app, that pulls up the relevant `Gene` and `Transcript` results and the isoform abundance plot +for any volcano point you select. + +```{r, eval=FALSE} +# Start the interactive volcano plot. +plot_shiny_volcano(mydtu) +``` + +1. Hovering over a point (or cluster of points) will show the gene IDs and some summary info. +2. Clicking on a point will display the all the available information calculated for the gene and its isoforms, as +well as draw the isoform abundance plot for the gene. + +When you finish exploring the volcano plot, close the popup window or stop the shiny runtime in order to return to your R terminal. + + +*** + + +# Contact information + +The `rats` R package was developed within [The Barton Group](http://www.compbio.dundee.ac.uk) at [The University of Dundee](http://www.dundee.ac.uk) +by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch. + +To **report problems** or **ask for assistance**, please raise a new issue [on the project's support forum](https://github.com/bartongroup/Rats/issues). +Providing a *reproducible working example* that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure +to **read the vignette(s)**, and browse/search the support forum before posting a new issue, in case your question is already answered there. + +Enjoy! + +![](./figs/rats_logo.png) + + diff --git a/doc/plots.html b/doc/plots.html new file mode 100644 index 0000000..04d7f9b --- /dev/null +++ b/doc/plots.html @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + +RATs: Plots + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ + + + + + + +
+

Set up an example.

+
# Simulate some data.
+simdat <- sim_boot_data(clean=TRUE) 
+# For convenience let's assign the contents of the list to separate variables
+mycond_A <- simdat[[2]]   # Simulated bootstrapped data for one condition.
+mycond_B <- simdat[[3]]   # Simulated bootstrapped data for other condition.
+myannot <- simdat[[1]]    # Transcript and gene IDs for the above data.
+
+# Call DTU
+mydtu <- call_DTU(annot= myannot, verbose= FALSE,
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  dprop_thresh=0.1, qboot=TRUE, rboot=FALSE)
+
+
+

Visualisation of results

+

The RATs output object provides a host of information and we encourage users to familiarize themselves with it. But a good plot is worth a thousand numbers. RATs provides a non-exhaustive set of basic visualisation options for the results.

+

The plotting functions return a ggplot2 object. You can just print() it, or assign it to a variable, further customise it with standard ggplot2 operations, or even pass it on to other viewing functions, like plotly::ggplotly().

+
+

Inspection of a given gene

+
+

Isoform abundances

+

This is a very useful function for inspecting a gene of interest. It enables quick visual evaluation of the dispersion of the replicate measurements, the magnitude of the absolute and proportion changes, the presence of outliers, and the consistency among the replicates.

+
# Grouping by condition (DEFAULT):
+plot_gene(mydtu, "MIX", style="bycondition")
+

+
    +
  • The top two facets show the absolute abundances (counts) of the isoforms as supplied in the input.
  • +
  • The bottom two facets show the correspondng relative abundances (proportions).
  • +
  • The facets on the left ocrrespond to one condition, the facets on the right correspond to the other condition.
  • +
  • The boxplots describe the abundance distribution of each isoform across replicates.
  • +
  • The actual abundance measurements are overlayed as points.
  • +
  • The set of abundances obtained in each replicate is shown by the lines connecting the points. This highlights the level of consistency between the replicates.
  • +
  • The presence of DTU for each transcript is encoded in the fill and shape of the abundance points.
  • +
  • The points and lines are placed slightly off-centre to prevent replicates masking one another when the measurements are very similar.
  • +
  • The colours of the replicates are recycled between the two conditions. So in the example, there are 4 samples: controls-1, controls-2, patients-1 and patients-2.
  • +
+

When there are many replicates or many isoforms, it may be preferable to group abundances by isoform, making individual comparisons easier:

+
# Grouping by isoform:
+plot_gene(mydtu, "MIX", style="byisoform")
+

+
+
+

Customisation of the abundances plot

+
+

Change information layers

+

The fillby, colourby and shapeby parameters of plot_gene() can be respectively used to control which information layers are encoded as fill, line/point colour, and point shape. Possible values are c("isoform", "condition", "DTU", "none", "replicate"). Be aware that some combinations of plot style and information layers are not possible.

+
+
+

Change colour code

+

Colour codes can be customised by specifying new values to the corresponding parameters of plot_gene():

+
    +
  • isofcolvec - Colour vector for isoform highlighting. Used to build a colorRampPalette.
  • +
  • dtucolvec - Colour vector for DTU highlighting.
  • +
  • condcolvec - Colour vector for condition highlighting.
  • +
  • replcolvec - Colour vector for replicate highlighting. Used to build a colorRampPalette.
  • +
  • nonecol - Colour to use when no colour coding is wanted.
  • +
+

An example of a colour vector, using standard R colour aliases, would be c('blue', darkred', 'gold').

+
+
+
+

Structure of the given gene

+

With the use of the third-party Bioconductor package ggbio, one can plot gene models from GRanges/GRangesList objects. This can be useful in interpreting transcript expression and DTU.

+

Therefore RATs offers a helper function to create an appropriate collection of GRanges/GRangesList objects from a GTF file. The collection is structured as a list, indexed by the GTF gene ID values. Each list element is a GRangesList object with the annotated transcripts for that gene.

+
models <- annot2models('/my/annotation/file.gtf')
+library(ggbio)
+# This will plot the structure of all isoforms for the given gene ID.
+autoplot(models[['mygeneID']])
+

For more options and more refined plots, refer to the ggbio documentation.

+
+
+
+

Overview plots

+

Our simulated dataset is too small to properly demonstrate what these plots might look like. So, instead, each one is accompanied by a static image of the plot created with a real and much larger dataset.

+

Possibly the most common plot in differential expression is the volcano plot, which plots the effect size against the statistical significance. The thresholds are also shown, although the default significance threshold of 0.05 is very low (hint: no lines are drawn for the axes).

+
# Proportion change VS transcript-level significance. Each point is a transcript
+plot_overview(mydtu, type="tvolcano")
+
+# This can also be plotted for genes, by using the largest isoform effect size as proxy.
+plot_overview(mydtu, type="gvolcano")
+

This is what these look like on a larger dataset: Transcript significance VS effect size

+

You can also get density histograms for the volcanos (the Y axis is square-root compressed):

+
# Distribution of proportion change.
+plot_overview(mydtu, type="dprop")
+
+# Distribution of largest isoform proportion change per gene.
+plot_overview(mydtu, type="maxdprop")
+

This is what these look like on a larger dataset: Effect size distribution

+

Although fold-changes of transcript expression are not tied to DTU, you can plot the traditional FC volcano and the relationship between FC and proportion change. Bear in mind that the FCs will be based on the abundances provided as input, without any adjustments such as library size normalization.

+
# Proportion change VS transcript-level significance. Each point is a transcript
+plot_overview(mydtu, type="fcvolcano")
+
+# This can also be plotted for genes, by using the largest isoform effect size as proxy.
+plot_overview(mydtu, type="fcVSdprop")
+

Fold change VS significance Fold change VS proportion change

+
+
+

Diagnostic plots

+

Currently there is only one plot type in this category.

+
# Pairwise Pearson's correlations among samples.
+plot_diagnostics(mydtu, type='cormat') # Default type.
+

+

What you want to see here, is a nice separation between the samples of different conditions. Anomalies in this plot may indicate batch effects or mislabelled samples.

+
+
+

Interactive plots

+

If you prefer picking points from a plot rather than sorting through tables, the gene-level volcano plot is also available through an interactive shiny app, that pulls up the relevant Gene and Transcript results and the isoform abundance plot for any volcano point you select.

+
# Start the interactive volcano plot.
+plot_shiny_volcano(mydtu)
+
    +
  1. Hovering over a point (or cluster of points) will show the gene IDs and some summary info.
  2. +
  3. Clicking on a point will display the all the available information calculated for the gene and its isoforms, as well as draw the isoform abundance plot for the gene.
  4. +
+

When you finish exploring the volcano plot, close the popup window or stop the shiny runtime in order to return to your R terminal.

+
+
+
+
+

Contact information

+

The rats R package was developed within The Barton Group at The University of Dundee by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch.

+

To report problems or ask for assistance, please raise a new issue on the project’s support forum. Providing a reproducible working example that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure to read the vignette(s), and browse/search the support forum before posting a new issue, in case your question is already answered there.

+

Enjoy!

+

+
+ + + +
+
+ +
+ + + + + + + + + + + + + + + + diff --git a/inst/doc/input.R b/inst/doc/input.R new file mode 100644 index 0000000..c642cc7 --- /dev/null +++ b/inst/doc/input.R @@ -0,0 +1,206 @@ +## ----setup, include=FALSE----------------------------------------------------- +knitr::opts_chunk$set(echo = TRUE) + +## ---- include=FALSE----------------------------------------------------------- +library(rats) + +## ---- echo=FALSE-------------------------------------------------------------- +# Show the first rows of the table corresponding to one sample, from emulated data. +head(sim_boot_data()[[2]][[1]]) + +## ---- echo=FALSE-------------------------------------------------------------- +# Show the first rows of the table corresponding to the annotation, from simulated data. +head(sim_count_data()[[1]]) + +## ---- eval=FALSE-------------------------------------------------------------- +# # Extract transcript ID to gene ID index from a GTF annotation. +# myannot <- gtf2ids("my_annotation_file.gtf") +# +# # Extract transcript ID and gene ID from a GRanges object. +# # It must have GTF-style metadata columns "gene_id" and "transcript_id". +# myannot <- granges2ids(mygranges) + +## ----eval=FALSE--------------------------------------------------------------- +# myannot <- select(mytxdb, keys(mytxdb), "GENEID", "TXNAME") +# # Rename the columns to match what RATs expects. +# names(myannot) <- c('gene_id', 'target_id') + +## ----------------------------------------------------------------------------- +# Simulate some data. +simdat <- sim_count_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated abundances for one condition. +mycond_B <- simdat[[3]] # Simulated abundances for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +## ----------------------------------------------------------------------------- +print( class(mycond_A) ) + +## ----------------------------------------------------------------------------- +# Find DTU between the simulated datasets. +mydtu <- call_DTU(annot= myannot, count_data_A= mycond_A, + count_data_B= mycond_B, verbose= FALSE, + scaling= 1, + name_A= "healthy", name_B= "patients", + varname= "My phenotype", + description="Comparison of two simulated counts datasets + for the tutorial. Simulated using built-in functionality + of RATs.") + +## ----------------------------------------------------------------------------- +# Simulate some data. (Notice it is a different function than before.) +simdat <- sim_boot_data(clean=TRUE) + +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +## ----------------------------------------------------------------------------- +print( class(mycond_A) ) +print( class(mycond_A[[1]]) ) + +## ----------------------------------------------------------------------------- +# Find DTU between conditions. +mydtu <- call_DTU(annot= myannot, boot_data_A= mycond_A, + boot_data_B= mycond_B, verbose= FALSE, + scaling= 1, + name_A= "wildtype", name_B= "some mutant", + varname = "My phenotype", description="Comparison of + two simulated datasets of bootstrapped counts for the + tutorial. Simulated using built-in functionality + of RATs.") + +## ---- eval=FALSE-------------------------------------------------------------- +# # Mock-up code, does not run. +# +# # 1. Collect your outputs into vectors. The end of each path should be a +# # directory with a unique name/identifier for one sample and containing +# # the respective output of Kallisto. +# samples_A <- c("your/path/SAMPLE1", "your/path/SAMPLE4","your/path/SAMPLE5") +# samples_B <- c("your/path/SAMPLE2", "your/path/SAMPLE3","your/path/SAMPLE7", "your/path/SAMPLE10") +# +# # 2. Calculate length- & library-normalised abundances. +# # Scale them to 1M reads for TPM values. +# mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, +# annot= myannot, scaleto=1e6) # scaling to TPM + +## ---- echo=FALSE-------------------------------------------------------------- +simdat <- sim_boot_data(clean=TRUE) +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +## ----------------------------------------------------------------------------- +# Calling DTU with custom thresholds. +mydtu <- call_DTU(annot= myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + p_thresh= 0.01, dprop_thres = 0.15, abund_thresh= 10, + verbose= FALSE) + +## ----------------------------------------------------------------------------- +# Do bootstrap (default). Do 100 iterations. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + qboot = TRUE, qbootnum = 100, qrep_thresh= 0.95, + verbose= FALSE) + +## ----------------------------------------------------------------------------- +# Bootstrap (default). +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + rboot = TRUE, qrep_thresh= 0.85, verbose= FALSE) + +## ----------------------------------------------------------------------------- +# Extra info on variance across iterations. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + lean = FALSE, verbose= FALSE) + +## ---- eval=FALSE-------------------------------------------------------------- +# # The following code is for demonstration only and won't run +# # without valid paths supplied to fish4rodents(). +# +# # The following are equivalent. +# +# # 1: +# # Scale to individual library sizes directly at the import step. +# mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, +# annot= myannot, +# scaleto= c(25123456, 2665431, 23131313, +# 5000000, 45123132, 48456654, 52363636), +# verbose= FALSE) +# # No additional scaling needed. +# mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, +# boot_data_B= mydata$boot_data_B, +# scaling= 1, # default +# verbose= FALSE) +# +# # 2: +# # Normalise quantifications but do not scale them at all. +# mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, +# annot= myannot, +# scaleto=1) +# # Scale library fractions to the library sizes. +# mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, +# boot_data_B= mydata$boot_data_B, +# scaling= c(25123456, 2665431, 23131313, 5000000, +# 45123132, 48456654, 52363636), +# verbose= FALSE) +# +# # 3: +# # Scale Kallisto quantifications to TPMs. +# mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, +# annot= myannot, +# scaleto= 1000000) # default +# # Scale TPMs to individual library sizes. +# mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, +# boot_data_B= mydata$boot_data_B, +# scaling=c(25.123456, 26.65431, 23.131313, 50.0, 45.123132, 48.456654, 52.363636), +# verbose= FALSE) + +## ---- eval=FALSE-------------------------------------------------------------- +# # Using 4 threads for parallel computing. +# mydtu <- call_DTU(annot = myannot, +# boot_data_A= mycond_A, boot_data_B= mycond_B, +# threads = 4, verbose= FALSE) + +## ----------------------------------------------------------------------------- +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + use_sums = TRUE, verbose= FALSE) + +## ----------------------------------------------------------------------------- +# Bonferroni correction. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + correction = "bonferroni", verbose= FALSE) + +## ----------------------------------------------------------------------------- +# Transcripts only. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + testmode="transc", verbose= FALSE) +# Genes only. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + testmode="genes", verbose= FALSE) + +## ---- echo=FALSE-------------------------------------------------------------- +simdat <- sim_boot_data(clean=TRUE, PARENT_COL='gene', TARGET_COL='transcript') +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +## ----------------------------------------------------------------------------- +# Call DTU using annotation with custom field names. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + TARGET_COL="transcript", PARENT_COL="gene", + verbose= FALSE) + +## ---- eval=FALSE-------------------------------------------------------------- +# mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, +# boot_data_B= mydata$boot_data_B, +# reckless=TRUE, verbose=TRUE) + diff --git a/inst/doc/input.Rmd b/inst/doc/input.Rmd new file mode 100644 index 0000000..1b95c87 --- /dev/null +++ b/inst/doc/input.Rmd @@ -0,0 +1,516 @@ +--- +title: 'RATs: Input and Settings' +author: "Kimon Froussios" +date: "31 MAR 2022" +output: + html_document: + keep_md: yes + theme: readable + toc: yes + toc_float: yes +vignette: > + \usepackage[utf8]{inputenc} + %\VignetteIndexEntry{RATs 1: Input & Settings} + %\VignetteEngine{knitr::rmarkdown} +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = TRUE) +``` + + +```{r, include=FALSE} +library(rats) +``` + +*** + +# Input formats + +## Data + +RATs can work with several input types: + +1. [Kallisto](http://pachterlab.github.io/kallisto/) quantifications in plain-text or RHDF5 format. +2. Bootstrapped abundance estimates in lists of R `data.table`s. +3. Abundance estimates in R `data.table`s. + +For option 1, the function `fish4rodents()` will load the data into tables suitable for options 2 or 3 accordingly. +Details in the respective section below. For options 2 and 3, the format of the tables is as in the example below. +The first column contains the transcript identifiers and subsequent columns contain the abundances. + +```{r, echo=FALSE} +# Show the first rows of the table corresponding to one sample, from emulated data. +head(sim_boot_data()[[2]][[1]]) +``` + +* In the case of option 3, each column represents a sample. Each condition is represented by a single such table. +* In the case of option 2, each column represents a bootstrap iteration and each table represents a sample. Each +condition is represented by a list of such tables. + +### Read counts, TPMs, etc + +To get the best results, we recommend obtaining TPM abundances, so as to account for differing transcript lengths, and then scaling these values to your actual library sizes to regain count-like magnitudes. +You can scale all libraries to the depth of your shallowest library for equal weight of all samples, or you can scale each sample to its own library if depths vary greatly and you want the deeper libraries to carry more weight. + +RATs provides parameters to scale the length-normalized abundances per sample to meet this requirement. + +## Annotation + +RATs also needs to know how to group transcripts together. This is achieved with a simple `data.frame` or `data.table` that matches transcript identifiers to gene identifiers. The expected column labels are `target_id` for the transcript IDs and `parent_id` for the gene IDs. Additional columns are allowed to be present but will be ignored. The minimal annotation table should look like this: + +```{r, echo=FALSE} +# Show the first rows of the table corresponding to the annotation, from simulated data. +head(sim_count_data()[[1]]) +``` + +RATs provides functionality to create this table from a GTF file or a `GRanges` object with GTF-style metadata columns. +(**Note:** GFF3 is not supported for this) + +```{r, eval=FALSE} +# Extract transcript ID to gene ID index from a GTF annotation. +myannot <- gtf2ids("my_annotation_file.gtf") + +# Extract transcript ID and gene ID from a GRanges object. +# It must have GTF-style metadata columns "gene_id" and "transcript_id". +myannot <- granges2ids(mygranges) +``` + +Extracting the ID pairs from a `TxDb` object is simpler and does not require a dedicated helper function: + +```{r eval=FALSE} +myannot <- select(mytxdb, keys(mytxdb), "GENEID", "TXNAME") +# Rename the columns to match what RATs expects. +names(myannot) <- c('gene_id', 'target_id') +``` + + +*** + + +# Calling DTU + + +As input data, we will use the data emulators that RATs uses in its code tests. +These "data" are extremely limited and completely fictional, but are adequate to demonstrate data format and command syntax. +If RATs issues *warnings* about the emulated dataset being too small, disregard them for this tutorial, they are meant for real datasets. + +### DTU from abundance estimates, without bootstraps + +This is the simplest usage case. + +First, let's emulate some data to work with: + +```{r} +# Simulate some data. +simdat <- sim_count_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated abundances for one condition. +mycond_B <- simdat[[3]] # Simulated abundances for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. +``` + +Each condition is a single data.table: + +```{r} +print( class(mycond_A) ) +``` + +Now we can call DTU: + +```{r} +# Find DTU between the simulated datasets. +mydtu <- call_DTU(annot= myannot, count_data_A= mycond_A, + count_data_B= mycond_B, verbose= FALSE, + scaling= 1, + name_A= "healthy", name_B= "patients", + varname= "My phenotype", + description="Comparison of two simulated counts datasets + for the tutorial. Simulated using built-in functionality + of RATs.") +``` + +#### Mandatory arguments: + +1. `annot` - An annotation data frame, as described in the Input formats section. +2. `count_data_A` and `count_data_B` - Each is a `data.table` of transcript abundances as described in the Input formats section. They should contain length-normalized values, like TPMs or pseudocounts by up-scaled TPMs. +3. `scaling` - A vector of scaling factors (one per sample), or a single scaling factor to be applied to all samples. This parameter is mandatory if input is TPM, but can be omitted if abundances are pre-scaled. + +#### Optional arguments (will be recorded in the output object, but have no effect on the run): + +* `name_A`, `name_B` - A name for each conditon. +* `varname` - The name of the variable/condition. +* `description` - Free-text description. + + + +### DTU from bootstrapped abundance estimates + +First, let's emulate some data, as we did before. + +```{r} +# Simulate some data. (Notice it is a different function than before.) +simdat <- sim_boot_data(clean=TRUE) + +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. +``` + +Each condition is a list of `data.table` objects: + +```{r} +print( class(mycond_A) ) +print( class(mycond_A[[1]]) ) +``` + +Now we can call DTU: + +```{r} +# Find DTU between conditions. +mydtu <- call_DTU(annot= myannot, boot_data_A= mycond_A, + boot_data_B= mycond_B, verbose= FALSE, + scaling= 1, + name_A= "wildtype", name_B= "some mutant", + varname = "My phenotype", description="Comparison of + two simulated datasets of bootstrapped counts for the + tutorial. Simulated using built-in functionality + of RATs.") +``` + +#### Mandatory arguments: + +1. `annot` - An annotation data frame, as described in the *Input formats* section. +2. `boot_data_A` and `boot_data_B` - Each is a list of `data.table` objects, as described in the Input section. They should contain length-normalized values, like TPMs or pseudocounts by up-scaled TPMs. +3. `scaling` - A vector of scaling factors (one per sample), or a single scaling factor to be applied to all samples. This parameter is mandatory if input is TPM, but can be omitted if abundances are pre-scaled. + +#### Optional arguments (will be recorded in the output object, but have no effect on the run): + +* `name_A`, `name_B` - A name for each condition. +* `varname` - The name of the variable/condition. +* `description` - Free-text description. + + +### DTU with Kallisto output + +The raw abundances are normalised to TPM (default). Consider instead providing the real depth of your libraries. + +```{r, eval=FALSE} +# Mock-up code, does not run. + +# 1. Collect your outputs into vectors. The end of each path should be a +# directory with a unique name/identifier for one sample and containing +# the respective output of Kallisto. +samples_A <- c("your/path/SAMPLE1", "your/path/SAMPLE4","your/path/SAMPLE5") +samples_B <- c("your/path/SAMPLE2", "your/path/SAMPLE3","your/path/SAMPLE7", "your/path/SAMPLE10") + +# 2. Calculate length- & library-normalised abundances. +# Scale them to 1M reads for TPM values. +mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, + annot= myannot, scaleto=1e6) # scaling to TPM +``` + +The output is a list, containing either two lists of `data.table` objects of bootstrapped data or just two `data.table`s of non-bootstrapped data, as per the input formats specifications. Then follow the respective example for the data type, as already covered above. + +#### Mandatory arguments (`fish4rodents`): + +1. `A_paths` and `B_paths` - Two vectors containing the paths to the quantification output directories, one vector for each condition. The +last segments of each path should be a directory with a unique identifying name for a single sample. +2. `annot` - An annotation data frame, as described in the Input formats section. + +#### Optional arguments (`fish4rodents`): + +* `scaleto` - Library depth to aim for. (Default 1000000 gives TPM values). +* `beartext` - directs `fish4rodents()` to read bootstrap data from plain-text files in a `bootstraps` subdirectory in each sample, instead of parsing the abundance.h5 file of the sample. (Default FALSE) + + + +*** + + +# Advanced Parameters and Settings + +```{r, echo=FALSE} +simdat <- sim_boot_data(clean=TRUE) +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. +``` + +## Main Thresholds + +The following three main thresholds are used in RATs: + +```{r} +# Calling DTU with custom thresholds. +mydtu <- call_DTU(annot= myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + p_thresh= 0.01, dprop_thres = 0.15, abund_thresh= 10, + verbose= FALSE) +``` + +1. `p_thresh` - Statistical significance level. (Default 0.05, very permissive) +2. `dprop_thresh` - Effect size threshold: The minimum difference in the isoform's proportion between the two conditions. (Default 0.20, quite strict) +3. `abund_thresh` - Noise threshold: (i) The minimum mean (across replicates) abundance, in at least one condition, for a transcript to be considered expressed. (ii) Also the minimum cumulative abundance of all isoforms of a gene in each of the two conditions. (Default 5, very permissive) + +Depending on the settings, *additional thresholds* are available and will be discussed in their respective sections below. + + +## Bootstrapping + +RATs offers two types of bootstrapping: + +1. Bootstrapping of significance and effect size against the variability in the quantifications. +This requires bootstrapped quantifications as input. +2. Bootstrapping of significance and effect size against the variability among replicates. + +Enabling these two procedures assesses the robustness of the DTU calls. In both cases, what is measured +is the fraction of iterations in which the significance and effect size meet their respective thresholds. +**Note** If bootstrapping is switched off, the respective fields will not be included in the output. + +### Quantification bootstraping + +In this process, one quantification iteration will be randomly selected from each sample and DTU will be called on it. +This will be repeated `qbootnum` times. + +Three parameters control bootstrapping of DTU calls against the fluctuations in the quantification: + +```{r} +# Do bootstrap (default). Do 100 iterations. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + qboot = TRUE, qbootnum = 100, qrep_thresh= 0.95, + verbose= FALSE) +``` + +1. `qboot` - Whether to bootstrap against the quantifications. (Default TRUE) +2. `qbootnum` - Number of bootstrap iterations. Ignored if `qboot=FALSE`. 0 is a special value prompting RATs to infer a value from the data (currently equal to the number of bootstraps in the data). (Default 0) +3. `qrep_thresh` - Reproducibility threshold: The minimum fraction of the iterations that have to agree on a result to consider it confident. To calculate the reproducibility without factoring it into the DTU classification, set the threshold to 0. Ignored if `qboot=FALSE`. (Default 0.95) + +### Replicate bootstraping + +In this process, all the 1 vs. 1 combinations of samples, one from each condition, are used to bootstrap the variation across replicates. + +Two parameters control bootstrapping of DTU calls against the samples: + +```{r} +# Bootstrap (default). +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + rboot = TRUE, qrep_thresh= 0.85, verbose= FALSE) +``` + +1. `rboot` - Whether to bootstrap the replicates or not. (Default TRUE) +2. `rrep_thresh` - Reproducibility threshold: The minimum fraction of the iterations that have to agree on a result to consider it confident. Ignored if `rboot=FALSE`. To calculate the reproducibility without factoring it in the DTU classification, set the threshold to 0. (Default 0.85) + +**Note** that for few replicates per condition, the reproducibility values are highly discrete. +For example, the number of iterations for 2 samples per condition is `2 * 2 = 4`. +So the minimum disagreement rate is `1 / 4 = 0.25`, or conversely a reproducibility of `3/4 = 0.75`. +The default threshold value of 0.85 is based on 3 replicates per condition, meaning 9 iterations and aiming for `8/9=0.889` agreement. + +### Extra bootstrapping info + +Additional information on the range, variance and centre of the effect size and p-value across bootstrap iterations can be calculated on request. This requires keeping the full raw results for every iteration in memory and can have a considerable footprint that scales with the number of transcripts and iterations. This is controlled by the `lean` parameter. + +```{r} +# Extra info on variance across iterations. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + lean = FALSE, verbose= FALSE) +``` + +1. `lean` - Keep a light memory footprint but reporting only the reproducibility rate, without spread statistics. (Default TRUE) + + +## Abundance scaling and normalisation + +Unlike Differential Transcript/Gene Expression, where libraries must be normalised for size so that expression values are comparable, abundances for Differential Transcript Usage are normalised to the expression of the respective individual gene. Therefore, RATs does not require the libraries to have the same size. + +For flexibility with different types of input, scaling can be applied in either/both of two stages: The data import step by +`fish4rodents()`, or/and the actual testing step by `call_DTU()`. The import applies length normalization and by default scales to 1 million. Such values are useful to have for use in other analyses. These TPMs can then be re-scaled to length-normalized pseudo-counts that reflect the library sizes. + +Both `fish4rodents()` and `call_DTU()` support scaling by a single value or a vector of values. + +```{r, eval=FALSE} +# The following code is for demonstration only and won't run +# without valid paths supplied to fish4rodents(). + +# The following are equivalent. + +# 1: +# Scale to individual library sizes directly at the import step. +mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, + annot= myannot, + scaleto= c(25123456, 2665431, 23131313, + 5000000, 45123132, 48456654, 52363636), + verbose= FALSE) +# No additional scaling needed. +mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, + boot_data_B= mydata$boot_data_B, + scaling= 1, # default + verbose= FALSE) + +# 2: +# Normalise quantifications but do not scale them at all. +mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, + annot= myannot, + scaleto=1) +# Scale library fractions to the library sizes. +mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, + boot_data_B= mydata$boot_data_B, + scaling= c(25123456, 2665431, 23131313, 5000000, + 45123132, 48456654, 52363636), + verbose= FALSE) + +# 3: +# Scale Kallisto quantifications to TPMs. +mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, + annot= myannot, + scaleto= 1000000) # default +# Scale TPMs to individual library sizes. +mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, + boot_data_B= mydata$boot_data_B, + scaling=c(25.123456, 26.65431, 23.131313, 50.0, 45.123132, 48.456654, 52.363636), + verbose= FALSE) +``` + +Take care to ensure that the scaling you apply is appropriate. + +**Note** that if you simply run both methods with their respective scaling defaults, you'll effectively run RATs +on TPM values, which is extremely underpowered and not recommended. + + +## Multi-threading + +RATs completion time depends on the number of annotated and expressed transcripts. Single-threaded, RATs can take up to +a few minutes per iteration, for large annotations. Fortunately, the task is parallelisable: + +```{r, eval=FALSE} +# Using 4 threads for parallel computing. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + threads = 4, verbose= FALSE) +``` + +1. `threads` - The number of threads to use. (Default 1) + +There are some limitations imposed by R. Refer to the `parallel` package for details (RATs uses the `mclapply` family of +parallel functions). + + +## Combining replicates + +Up to and including version `0.6.5`, RATs combined the isoform abundance values across replicates by summing them. +The resulting values are thus larger and pass the significance test more easily, increasing sensitivity. +But this can also boost false positives. + +Now, instead, the user is given the choice between sums and means. By default RATs now uses the means instead of the sums. + +```{r} +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + use_sums = TRUE, verbose= FALSE) +``` + +1. `use_sums` - Whether to test the sum of abundances across replicates, instead of their mean. (Default FALSE) + +## Correction for multiple testing + +There are as many null hypotheses tested as there are genes (for the gene-level results) or transcripts (for the transcript-level results). +The default correction method is `BH` (Benjamini-Hochberg). A full list of options is listed in R's `p.adjust.methods`. + +```{r} +# Bonferroni correction. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + correction = "bonferroni", verbose= FALSE) +``` + +1. `correction` - Type of multiple testing correction. (Default "BH") + + +## Test selection + +RATs runs both gene-level DTU calls and transcript-level DTU calls. They are independent from one another and we consider +them complementary and recommend using them together, but the option to skip either is provided, for special use cases. +The output fields of the skipped test will be filled with `NA`. + +```{r} +# Transcripts only. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + testmode="transc", verbose= FALSE) +# Genes only. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + testmode="genes", verbose= FALSE) +``` + +1. `testmode` - Which test(s) to run {"transc", "genes", "both"}. (Default "both") + + +## Input field names + +### Annotation field names + +Although it is easy to rename the columns of a table to comply with the expected names, this may sometimes be undesireable, so RATs +allows you to change the expected names instead. + +```{r, echo=FALSE} +simdat <- sim_boot_data(clean=TRUE, PARENT_COL='gene', TARGET_COL='transcript') +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. +``` + + +```{r} +# Call DTU using annotation with custom field names. +mydtu <- call_DTU(annot = myannot, + boot_data_A= mycond_A, boot_data_B= mycond_B, + TARGET_COL="transcript", PARENT_COL="gene", + verbose= FALSE) +``` + +1. `TARGET_COL` - The name of the field holding the transcript identifiers in the annotation data frame. (Default "target_id") +2. `PARENT_COL` - The name of the field holding the respective gene identifiers in the annotation data frame. (Default "parent_id") + +The `TARGET_COL` and `PARENT_COL` parameters are also available for `fish4rodents()`. + + +## Annotation discrepancies + +RATs will abort the run if the set of feature IDs in the provided annotation does not match fully the set of IDs in the quantifications. +If this happens, ensure you are using the exact same annotation throughout your workflow. + +For special use cases, RATs provides the option to ignore the discrepancy and pretend everything is OK. Do this at your own risk. + +```{r, eval=FALSE} +mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, + boot_data_B= mydata$boot_data_B, + reckless=TRUE, verbose=TRUE) +``` + +1. `reckless` - Ignore inconsistent set of IDs between annotation and quantifications. (Default FALSE) + +In reckless mode, all internal operations and the output of RATs are based on the annotation provided: + +* Any transcript IDs present in the data but missing from the annotation will be ignored and will not show up in the output at all, as they cannot be matched to the gene IDs. +* Any transcript ID present in the annotation but missing from the data will be included in the output as zero expression. They can be identified later as `NA` values in `$Transcripts[, .(stdevA, stdevB)]` as these fields are not used downstream by RATs. `NA` values in other numeric fields are explicitly overwritten with `0` to allow downstream interoperability. + +*** + + +# Contact information + +The `rats` R package was developed within [The Barton Group](http://www.compbio.dundee.ac.uk) at [The University of Dundee](http://www.dundee.ac.uk) +by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch. + +To **report problems** or **ask for assistance**, please raise a new issue [on the project's support forum](https://github.com/bartongroup/Rats/issues). +Providing a *reproducible working example* that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure +to **read the vignette(s)**, and browse/search the support forum before posting a new issue, in case your question is already answered there. + +Enjoy! + +![](./figs/rats_logo.png) diff --git a/inst/doc/input.html b/inst/doc/input.html new file mode 100644 index 0000000..a7ae091 --- /dev/null +++ b/inst/doc/input.html @@ -0,0 +1,720 @@ + + + + + + + + + + + + + + + +RATs: Input and Settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ + + + + + + +
+
+

Input formats

+
+

Data

+

RATs can work with several input types:

+
    +
  1. Kallisto quantifications in plain-text or RHDF5 format.
  2. +
  3. Bootstrapped abundance estimates in lists of R data.tables.
  4. +
  5. Abundance estimates in R data.tables.
  6. +
+

For option 1, the function fish4rodents() will load the data into tables suitable for options 2 or 3 accordingly. Details in the respective section below. For options 2 and 3, the format of the tables is as in the example below. The first column contains the transcript identifiers and subsequent columns contain the abundances.

+
##    target  V1  V2  V3
+## 1: SOLO.1 100 100 100
+## 2: SAME_1 200 200 200
+## 3: SAME_2 300 300 300
+## 4: LONE.a 150 150 150
+## 5: D2TE_a 300 300 300
+## 6: D2TE_b 400 400 400
+
    +
  • In the case of option 3, each column represents a sample. Each condition is represented by a single such table.
  • +
  • In the case of option 2, each column represents a bootstrap iteration and each table represents a sample. Each condition is represented by a list of such tables.
  • +
+
+

Read counts, TPMs, etc

+

To get the best results, we recommend obtaining TPM abundances, so as to account for differing transcript lengths, and then scaling these values to your actual library sizes to regain count-like magnitudes. You can scale all libraries to the depth of your shallowest library for equal weight of all samples, or you can scale each sample to its own library if depths vary greatly and you want the deeper libraries to carry more weight.

+

RATs provides parameters to scale the length-normalized abundances per sample to meet this requirement.

+
+
+
+

Annotation

+

RATs also needs to know how to group transcripts together. This is achieved with a simple data.frame or data.table that matches transcript identifiers to gene identifiers. The expected column labels are target_id for the transcript IDs and parent_id for the gene IDs. Additional columns are allowed to be present but will be ignored. The minimal annotation table should look like this:

+
##   target_id parent_id
+## 1       SW2        SW
+## 2    D2TE_b      D2TE
+## 3    SAME_1      SAME
+## 4    SAME_2      SAME
+## 5    LONE.a      LONE
+## 6    D2TE_a      D2TE
+

RATs provides functionality to create this table from a GTF file or a GRanges object with GTF-style metadata columns. (Note: GFF3 is not supported for this)

+
# Extract transcript ID to gene ID index from a GTF annotation.
+myannot <- gtf2ids("my_annotation_file.gtf")
+
+# Extract transcript ID and gene ID from a GRanges object. 
+# It must have GTF-style metadata columns "gene_id" and "transcript_id".
+myannot <- granges2ids(mygranges)
+

Extracting the ID pairs from a TxDb object is simpler and does not require a dedicated helper function:

+
myannot <- select(mytxdb, keys(mytxdb), "GENEID", "TXNAME")
+# Rename the columns to match what RATs expects.
+names(myannot) <- c('gene_id', 'target_id')
+
+
+
+
+

Calling DTU

+

As input data, we will use the data emulators that RATs uses in its code tests. These “data” are extremely limited and completely fictional, but are adequate to demonstrate data format and command syntax. If RATs issues warnings about the emulated dataset being too small, disregard them for this tutorial, they are meant for real datasets.

+
+

DTU from abundance estimates, without bootstraps

+

This is the simplest usage case.

+

First, let’s emulate some data to work with:

+
# Simulate some data.
+simdat <- sim_count_data(clean=TRUE)
+# For convenience let's assign the contents of the list to separate variables
+mycond_A <- simdat[[2]]       # Simulated abundances for one condition.
+mycond_B <- simdat[[3]]       # Simulated abundances for other condition.
+myannot <- simdat[[1]]        # Transcript and gene IDs for the above data.
+

Each condition is a single data.table:

+
print( class(mycond_A) )
+
## [1] "data.table" "data.frame"
+

Now we can call DTU:

+
# Find DTU between the simulated datasets.
+mydtu <- call_DTU(annot= myannot, count_data_A= mycond_A, 
+                  count_data_B= mycond_B, verbose= FALSE,
+                  scaling= 1,
+                  name_A= "healthy", name_B= "patients", 
+                  varname= "My phenotype",
+                  description="Comparison of two simulated counts datasets 
+                  for the tutorial. Simulated using built-in functionality 
+                  of RATs.")
+
## Summarising bootstraps...
+
+

Mandatory arguments:

+
    +
  1. annot - An annotation data frame, as described in the Input formats section.
  2. +
  3. count_data_A and count_data_B - Each is a data.table of transcript abundances as described in the Input formats section. They should contain length-normalized values, like TPMs or pseudocounts by up-scaled TPMs.
  4. +
  5. scaling - A vector of scaling factors (one per sample), or a single scaling factor to be applied to all samples. This parameter is mandatory if input is TPM, but can be omitted if abundances are pre-scaled.
  6. +
+
+
+

Optional arguments (will be recorded in the output object, but have no effect on the run):

+
    +
  • name_A, name_B - A name for each conditon.
  • +
  • varname - The name of the variable/condition.
  • +
  • description - Free-text description.
  • +
+
+
+
+

DTU from bootstrapped abundance estimates

+

First, let’s emulate some data, as we did before.

+
# Simulate some data. (Notice it is a different function than before.)
+simdat <- sim_boot_data(clean=TRUE)
+
+# For convenience let's assign the contents of the list to separate variables
+mycond_A <- simdat[[2]]   # Simulated bootstrapped data for one condition.
+mycond_B <- simdat[[3]]   # Simulated bootstrapped data for other condition.
+myannot <- simdat[[1]]    # Transcript and gene IDs for the above data.
+

Each condition is a list of data.table objects:

+
print( class(mycond_A) )
+
## [1] "list"
+
print( class(mycond_A[[1]]) )
+
## [1] "data.table" "data.frame"
+

Now we can call DTU:

+
# Find DTU between conditions.
+mydtu <- call_DTU(annot= myannot, boot_data_A= mycond_A, 
+                  boot_data_B= mycond_B, verbose= FALSE, 
+                  scaling= 1,
+                  name_A= "wildtype", name_B= "some mutant", 
+                  varname = "My phenotype", description="Comparison of 
+                  two simulated datasets of bootstrapped counts for the 
+                  tutorial. Simulated using built-in functionality 
+                  of RATs.")
+
## Summarising bootstraps...
+
+

Mandatory arguments:

+
    +
  1. annot - An annotation data frame, as described in the Input formats section.
  2. +
  3. boot_data_A and boot_data_B - Each is a list of data.table objects, as described in the Input section. They should contain length-normalized values, like TPMs or pseudocounts by up-scaled TPMs.
  4. +
  5. scaling - A vector of scaling factors (one per sample), or a single scaling factor to be applied to all samples. This parameter is mandatory if input is TPM, but can be omitted if abundances are pre-scaled.
  6. +
+
+
+

Optional arguments (will be recorded in the output object, but have no effect on the run):

+
    +
  • name_A, name_B - A name for each condition.
  • +
  • varname - The name of the variable/condition.
  • +
  • description - Free-text description.
  • +
+
+
+
+

DTU with Kallisto output

+

The raw abundances are normalised to TPM (default). Consider instead providing the real depth of your libraries.

+
# Mock-up code, does not run.
+
+# 1. Collect your outputs into vectors. The end of each path should be a 
+#    directory with a unique name/identifier for one sample and containing
+#    the respective output of Kallisto.
+samples_A <- c("your/path/SAMPLE1", "your/path/SAMPLE4","your/path/SAMPLE5")
+samples_B <- c("your/path/SAMPLE2", "your/path/SAMPLE3","your/path/SAMPLE7", "your/path/SAMPLE10")
+
+# 2. Calculate length- & library-normalised abundances. 
+#    Scale them to 1M reads for TPM values.
+mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, 
+                       annot= myannot, scaleto=1e6) # scaling to TPM
+

The output is a list, containing either two lists of data.table objects of bootstrapped data or just two data.tables of non-bootstrapped data, as per the input formats specifications. Then follow the respective example for the data type, as already covered above.

+
+

Mandatory arguments (fish4rodents):

+
    +
  1. A_paths and B_paths - Two vectors containing the paths to the quantification output directories, one vector for each condition. The last segments of each path should be a directory with a unique identifying name for a single sample.
  2. +
  3. annot - An annotation data frame, as described in the Input formats section.
  4. +
+
+
+

Optional arguments (fish4rodents):

+
    +
  • scaleto - Library depth to aim for. (Default 1000000 gives TPM values).
  • +
  • beartext - directs fish4rodents() to read bootstrap data from plain-text files in a bootstraps subdirectory in each sample, instead of parsing the abundance.h5 file of the sample. (Default FALSE)
  • +
+
+
+
+
+
+

Advanced Parameters and Settings

+
+

Main Thresholds

+

The following three main thresholds are used in RATs:

+
# Calling DTU with custom thresholds.
+mydtu <- call_DTU(annot= myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  p_thresh= 0.01, dprop_thres = 0.15, abund_thresh= 10,
+                  verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. p_thresh - Statistical significance level. (Default 0.05, very permissive)
  2. +
  3. dprop_thresh - Effect size threshold: The minimum difference in the isoform’s proportion between the two conditions. (Default 0.20, quite strict)
  4. +
  5. abund_thresh - Noise threshold: (i) The minimum mean (across replicates) abundance, in at least one condition, for a transcript to be considered expressed. (ii) Also the minimum cumulative abundance of all isoforms of a gene in each of the two conditions. (Default 5, very permissive)
  6. +
+

Depending on the settings, additional thresholds are available and will be discussed in their respective sections below.

+
+
+

Bootstrapping

+

RATs offers two types of bootstrapping:

+
    +
  1. Bootstrapping of significance and effect size against the variability in the quantifications. This requires bootstrapped quantifications as input.
  2. +
  3. Bootstrapping of significance and effect size against the variability among replicates.
  4. +
+

Enabling these two procedures assesses the robustness of the DTU calls. In both cases, what is measured is the fraction of iterations in which the significance and effect size meet their respective thresholds. Note If bootstrapping is switched off, the respective fields will not be included in the output.

+
+

Quantification bootstraping

+

In this process, one quantification iteration will be randomly selected from each sample and DTU will be called on it. This will be repeated qbootnum times.

+

Three parameters control bootstrapping of DTU calls against the fluctuations in the quantification:

+
# Do bootstrap (default). Do 100 iterations.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  qboot = TRUE, qbootnum = 100, qrep_thresh= 0.95,
+                  verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. qboot - Whether to bootstrap against the quantifications. (Default TRUE)
  2. +
  3. qbootnum - Number of bootstrap iterations. Ignored if qboot=FALSE. 0 is a special value prompting RATs to infer a value from the data (currently equal to the number of bootstraps in the data). (Default 0)
  4. +
  5. qrep_thresh - Reproducibility threshold: The minimum fraction of the iterations that have to agree on a result to consider it confident. To calculate the reproducibility without factoring it into the DTU classification, set the threshold to 0. Ignored if qboot=FALSE. (Default 0.95)
  6. +
+
+
+

Replicate bootstraping

+

In this process, all the 1 vs. 1 combinations of samples, one from each condition, are used to bootstrap the variation across replicates.

+

Two parameters control bootstrapping of DTU calls against the samples:

+
# Bootstrap (default).
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  rboot = TRUE, qrep_thresh= 0.85, verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. rboot - Whether to bootstrap the replicates or not. (Default TRUE)
  2. +
  3. rrep_thresh - Reproducibility threshold: The minimum fraction of the iterations that have to agree on a result to consider it confident. Ignored if rboot=FALSE. To calculate the reproducibility without factoring it in the DTU classification, set the threshold to 0. (Default 0.85)
  4. +
+

Note that for few replicates per condition, the reproducibility values are highly discrete. For example, the number of iterations for 2 samples per condition is 2 * 2 = 4. So the minimum disagreement rate is 1 / 4 = 0.25, or conversely a reproducibility of 3/4 = 0.75. The default threshold value of 0.85 is based on 3 replicates per condition, meaning 9 iterations and aiming for 8/9=0.889 agreement.

+
+
+

Extra bootstrapping info

+

Additional information on the range, variance and centre of the effect size and p-value across bootstrap iterations can be calculated on request. This requires keeping the full raw results for every iteration in memory and can have a considerable footprint that scales with the number of transcripts and iterations. This is controlled by the lean parameter.

+
# Extra info on variance across iterations.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  lean = FALSE, verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. lean - Keep a light memory footprint but reporting only the reproducibility rate, without spread statistics. (Default TRUE)
  2. +
+
+
+
+

Abundance scaling and normalisation

+

Unlike Differential Transcript/Gene Expression, where libraries must be normalised for size so that expression values are comparable, abundances for Differential Transcript Usage are normalised to the expression of the respective individual gene. Therefore, RATs does not require the libraries to have the same size.

+

For flexibility with different types of input, scaling can be applied in either/both of two stages: The data import step by fish4rodents(), or/and the actual testing step by call_DTU(). The import applies length normalization and by default scales to 1 million. Such values are useful to have for use in other analyses. These TPMs can then be re-scaled to length-normalized pseudo-counts that reflect the library sizes.

+

Both fish4rodents() and call_DTU() support scaling by a single value or a vector of values.

+
# The following code is for demonstration only and won't run
+# without valid paths supplied to fish4rodents().
+
+# The following are equivalent.
+
+# 1:
+# Scale to individual library sizes directly at the import step.
+mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, 
+                       annot= myannot, 
+                       scaleto= c(25123456, 2665431, 23131313, 
+                                 5000000, 45123132, 48456654, 52363636),
+                       verbose= FALSE)
+# No additional scaling needed.
+mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, 
+                  boot_data_B= mydata$boot_data_B, 
+                  scaling= 1,  # default
+                  verbose= FALSE)  
+
+# 2:
+# Normalise quantifications but do not scale them at all.
+mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, 
+                       annot= myannot, 
+                       scaleto=1)
+# Scale library fractions to the library sizes.
+mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, 
+                  boot_data_B= mydata$boot_data_B,  
+                  scaling= c(25123456, 2665431, 23131313, 5000000, 
+                            45123132, 48456654, 52363636), 
+                  verbose= FALSE)
+
+# 3:
+# Scale Kallisto quantifications to TPMs.
+mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, 
+                       annot= myannot, 
+                       scaleto= 1000000)  # default
+# Scale TPMs to individual library sizes.
+mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, 
+                  boot_data_B= mydata$boot_data_B,
+                  scaling=c(25.123456, 26.65431, 23.131313, 50.0, 45.123132, 48.456654, 52.363636), 
+                  verbose= FALSE)
+

Take care to ensure that the scaling you apply is appropriate.

+

Note that if you simply run both methods with their respective scaling defaults, you’ll effectively run RATs on TPM values, which is extremely underpowered and not recommended.

+
+
+

Multi-threading

+

RATs completion time depends on the number of annotated and expressed transcripts. Single-threaded, RATs can take up to a few minutes per iteration, for large annotations. Fortunately, the task is parallelisable:

+
# Using 4 threads for parallel computing.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  threads = 4, verbose= FALSE)
+
    +
  1. threads - The number of threads to use. (Default 1)
  2. +
+

There are some limitations imposed by R. Refer to the parallel package for details (RATs uses the mclapply family of parallel functions).

+
+
+

Combining replicates

+

Up to and including version 0.6.5, RATs combined the isoform abundance values across replicates by summing them. The resulting values are thus larger and pass the significance test more easily, increasing sensitivity. But this can also boost false positives.

+

Now, instead, the user is given the choice between sums and means. By default RATs now uses the means instead of the sums.

+
mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  use_sums = TRUE, verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. use_sums - Whether to test the sum of abundances across replicates, instead of their mean. (Default FALSE)
  2. +
+
+
+

Correction for multiple testing

+

There are as many null hypotheses tested as there are genes (for the gene-level results) or transcripts (for the transcript-level results). The default correction method is BH (Benjamini-Hochberg). A full list of options is listed in R’s p.adjust.methods.

+
# Bonferroni correction.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  correction = "bonferroni", verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. correction - Type of multiple testing correction. (Default “BH”)
  2. +
+
+
+

Test selection

+

RATs runs both gene-level DTU calls and transcript-level DTU calls. They are independent from one another and we consider them complementary and recommend using them together, but the option to skip either is provided, for special use cases. The output fields of the skipped test will be filled with NA.

+
# Transcripts only.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  testmode="transc", verbose= FALSE)
+
## Summarising bootstraps...
+
# Genes only.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  testmode="genes", verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. testmode - Which test(s) to run {“transc”, “genes”, “both”}. (Default “both”)
  2. +
+
+
+

Input field names

+
+

Annotation field names

+

Although it is easy to rename the columns of a table to comply with the expected names, this may sometimes be undesireable, so RATs allows you to change the expected names instead.

+
# Call DTU using annotation with custom field names.
+mydtu <- call_DTU(annot = myannot, 
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  TARGET_COL="transcript", PARENT_COL="gene",
+                  verbose= FALSE)
+
## Summarising bootstraps...
+
    +
  1. TARGET_COL - The name of the field holding the transcript identifiers in the annotation data frame. (Default “target_id”)
  2. +
  3. PARENT_COL - The name of the field holding the respective gene identifiers in the annotation data frame. (Default “parent_id”)
  4. +
+

The TARGET_COL and PARENT_COL parameters are also available for fish4rodents().

+
+
+
+

Annotation discrepancies

+

RATs will abort the run if the set of feature IDs in the provided annotation does not match fully the set of IDs in the quantifications. If this happens, ensure you are using the exact same annotation throughout your workflow.

+

For special use cases, RATs provides the option to ignore the discrepancy and pretend everything is OK. Do this at your own risk.

+
mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, 
+                  boot_data_B= mydata$boot_data_B,
+                  reckless=TRUE, verbose=TRUE)
+
    +
  1. reckless - Ignore inconsistent set of IDs between annotation and quantifications. (Default FALSE)
  2. +
+

In reckless mode, all internal operations and the output of RATs are based on the annotation provided:

+
    +
  • Any transcript IDs present in the data but missing from the annotation will be ignored and will not show up in the output at all, as they cannot be matched to the gene IDs.
  • +
  • Any transcript ID present in the annotation but missing from the data will be included in the output as zero expression. They can be identified later as NA values in $Transcripts[, .(stdevA, stdevB)] as these fields are not used downstream by RATs. NA values in other numeric fields are explicitly overwritten with 0 to allow downstream interoperability.
  • +
+
+
+
+
+

Contact information

+

The rats R package was developed within The Barton Group at The University of Dundee by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch.

+

To report problems or ask for assistance, please raise a new issue on the project’s support forum. Providing a reproducible working example that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure to read the vignette(s), and browse/search the support forum before posting a new issue, in case your question is already answered there.

+

Enjoy!

+

+
+ + + +
+
+ +
+ + + + + + + + + + + + + + + + diff --git a/inst/doc/output.R b/inst/doc/output.R new file mode 100644 index 0000000..a1cfbf8 --- /dev/null +++ b/inst/doc/output.R @@ -0,0 +1,68 @@ +## ----setup, include=FALSE----------------------------------------------------- +knitr::opts_chunk$set(echo = TRUE) + +## ----------------------------------------------------------------------------- +library(rats) +library(data.table) + +## ----------------------------------------------------------------------------- +# Simulate some data. +simdat <- sim_boot_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +# Call DTU +mydtu <- call_DTU(annot= myannot, verbose= FALSE, + boot_data_A= mycond_A, boot_data_B= mycond_B, + dprop_thresh=0.1, qboot=TRUE, rboot=FALSE) + +## ----------------------------------------------------------------------------- +print( names(mydtu) ) + +## ----------------------------------------------------------------------------- +# Parameter list's elements. +print( names(mydtu$Parameters) ) + +## ----------------------------------------------------------------------------- +# Genes table's fields. +print( names(mydtu$Genes) ) + +## ----------------------------------------------------------------------------- +# Transcripts table's fields. +print( names(mydtu$Transcripts) ) + +## ----------------------------------------------------------------------------- +# Elements of Abundances. +print( names(mydtu$Abundances) ) + +## ----------------------------------------------------------------------------- +# Abundance table for first condition. +print( head(mydtu$Abundances[[1]]) ) + +## ----------------------------------------------------------------------------- +# A tally of the outcome. +print( dtu_summary(mydtu) ) + +## ----------------------------------------------------------------------------- +# Gene and transcript IDs corresponding to the tally above. +ids <- get_dtu_ids(mydtu) +print( names(ids) ) +print( ids ) + +## ----------------------------------------------------------------------------- +# A tally of genes switching isoform ranks. +print( dtu_switch_summary(mydtu) ) + +# The gene IDs displaying isoform switching. +ids <- get_switch_ids(mydtu) +print( names(ids) ) + +## ----------------------------------------------------------------------------- +# A tally of genes switching isoform ranks. +print( dtu_plurality_summary(mydtu) ) + +# The gene IDs displaying isoform switching. +ids <- get_plurality_ids(mydtu) + diff --git a/inst/doc/output.Rmd b/inst/doc/output.Rmd new file mode 100644 index 0000000..6224e84 --- /dev/null +++ b/inst/doc/output.Rmd @@ -0,0 +1,291 @@ +--- +title: 'RATs: Raw Output' +author: "Kimon Froussios" +date: "08 JUL 2019" +output: + html_document: + keep_md: yes + theme: readable + toc: yes + toc_float: yes +vignette: > + \usepackage[utf8]{inputenc} + %\VignetteIndexEntry{RATs 2: Raw Output} + %\VignetteEngine{knitr::rmarkdown} +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = TRUE) +``` + +*** + +```{r} +library(rats) +library(data.table) +``` + + +Let's set up an example, using RAT's data emulator (used for code testing, not suitable for data simulations). + +```{r} +# Simulate some data. +simdat <- sim_boot_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +# Call DTU +mydtu <- call_DTU(annot= myannot, verbose= FALSE, + boot_data_A= mycond_A, boot_data_B= mycond_B, + dprop_thresh=0.1, qboot=TRUE, rboot=FALSE) +``` + + +*** + + +# Output structure + +The output of RATs is a list containing 4 elements: + +```{r} +print( names(mydtu) ) +``` + + +## Parameters + +`Parameters` is a list that contains information about the data and the settings for a particular run. + +```{r} +# Parameter list's elements. +print( names(mydtu$Parameters) ) +``` + +* `description` - (str) Free-text description of the run. It is useful to record data sources, annotation source and version, experimental parameters, etc... +* `time` - (str) Date and time for the run. This does not represent the exact time the run started. +* `rats_version` - (str) The version of RATs. +* `R_version` - (str) The version of R (including OS architecture). +* `var_name` - (str) The value passed to the `varname` parameter. +* `cond_A` & `cond_B` - (str) The values passed to the `name_A` and `name_B` parameters. +* `data_type` - (str) The format of the input data. +* `num_replic_A` & `num_replic_B` - (int) The number of samples in each condition. +* `num_genes` - (int) The number of genes in the provided annotation. +* `num_transc` - (int) The number of transcripts in the provided annotation. +* `tests` - (str) The value passed to the `testmode` parameter. +* `use_sums` - (bool) Sum the replicates instead of averaging them (pre-0.7.0 RATs always summed). +* `p_thresh` - (num) The value passed to the `p_thresh` parameter. +* `abund_thresh` - (num) The value passed to the `abund_thresh` parameter. +* `dprop_thresh` - (num) The value passed to the `dprop_thresh` parameter. +* `correction` - (str) Multiple testing correction method. +* `abund_scaling` - (num) The value(s) passed to the `scaling` parameter. It will be either a single numeric value or a named vector of values. +* `quant_boot` - (bool) The value passed to the `qboots` parameter. +* `quant_reprod_thresh` - (num) The value passed to the `qrep_thresh` parameter, if `qboot==TRUE`. +* `quant_bootnum` - (int) The value passed to the `qbootnum` parameter, if `qboot==TRUE`. +* `rep_boot` - (bool) The value passed to the `rboot` parameter. +* `rep_reprod_thresh` - (num) The value passed to the `rrep_thresh` parameter, if `rboot==TRUE`. +* `rep_bootnum` - (int) The number of replicate bootstrapping iterations (currently M*N, where M and N are the numbers of samples in the two conditions), if `rboot==TRUE`. +* `seed` - (int) Custom seed for the random generator. `NA` if none was specified. +* `reckless` - (bool) The value passed to the `reckless` parameter. +* `lean` - (bool) The value passed to the `lean` parameter. + +**Note:** If bootstraps are disabled, the bootstrap-related fields may be `NA`, regardless of supplied values, to reflect the fact that they were not used. + + +## Genes + +`Genes` is a [data.table](https://cran.r-project.org/web/packages/data.table/) listing +results at the gene level. For your convenience, the respective aggregated transcript-level DTU calls are +also included here (defined as at least one isoform being called DTU individually). + +```{r} +# Genes table's fields. +print( names(mydtu$Genes) ) +``` + +The first few columns show the result of each decision step in a boolean manner, allowing easy filtering of the table. +The remaining columns list the values based on which these decisions were made. +Pseudo-code formulas are shown here to help understand how the different fields interact when making decisions. + +* `parent_id` - (str) Gene identifier. +* `elig` - (bool) Eligible for testing. Whether the gene met the pre-filtering criteria. `= (elig_transc >= 2)`. +* `sig` - (bool) Statistically significant. `= (pval_corr < Parameters$p_thresh)`. +* `elig_fx` - (bool) Eligible effect size. Whether at least one of the isoforms meets the effect size criterion. `= any(Transcript[parent_id, elig_fx])`. +* `quant_reprod` - (bool) Result reproducible across quantification iterations. +For positive DTU, `= (quant_dtu_freq >= Parameters$quant_reprod_thresh)`, for non-DTU `= (quant_dtu_freq <= 1 - Parameters$quant_reprod_thresh)`. +* `rep_reprod` - (bool) Result reproducible across replicates. +For positive DTU, `= (rep_dtu_freq >= Parameters$rep_reprod_thresh)`, for non-DTU `= (rep_dtu_freq <= 1 - Parameters$rep_reprod_thresh)`. +* `DTU` - (bool) Gene-level Differential Transcript Usage. `= (sig & elig_fx & quant_reprod & rep_reprod)`. +* `transc_DTU` - (bool) Aggregated from `Transcripts$DTU`: At least one isoform was individually reported as DTU. `= (Transcript[ , any(DTU), by=parent_id])`. +* `known_transc` - (int) Number of known trascripts for this gene according to the given annotation. +* `detect_trancs` - (int) Number of detected (expressed) transcripts in the given dataset. +* `elig_transc` - (int) Number of eligible transcripts, aggregated from `Transcripts$elig`. +* `pval` - (num) G test of independence p-value for the isoform ratios of the gene. +* `pval_corr` - (num) Multiple testing corrected p-value. `pval_corr= p.adjust(pval, Parameters$correction)`. +* `quant_p_median` - (num) Median of corrected p-values across quantification bootstraps (not available in `lean` mode). +* `quant_p_min` - (num) Minimum observed (corrected) p-value across quantification bootstraps (not available in `lean` mode). +* `quant_p_max` - (num) Maximum observed (corrected) p-value across quantification bootstraps (not available in `lean` mode). +* `quant_na_freq` - (num) Fraction of quantification iterations in which `DTU` could not be determined (not meeting pre-filtering criteria). +* `quant_dtu_freq` - (num) Fraction of replicate iterations that support a positive `DTU` classification. +* `rep_p_median` - (num) Median p-value across replication bootstraps (not available in `lean` mode). +* `rep_p_min` - (num) Minimum observed p-value across replication bootstraps (not available in `lean` mode). +* `rep_p_max` - (num) Maximum observed p-value across replication bootstraps (not available in `lean` mode). +* `rep_na_freq` - (num) Fraction of replication iterations in which `DTU` could not be determined (not meeting pre-filtering criteria). +* `rep_dtu_freq` - (num) Fraction of replication iterations that support a positive `DTU` classification. + +**Note:** The fields reporting on the bootstraps will not be shown when bootstrapping is disabled. + + +## Transcripts + +`Transcripts` is a [data.table](https://cran.r-project.org/web/packages/data.table/) listing +results at the transcript level. For your convenience, the respective gene-level DTU calls are also included here. + +```{r} +# Transcripts table's fields. +print( names(mydtu$Transcripts) ) +``` + +The first few columns show the result of each decision step in a boolean manner, allowing easy filtering of the table. +The remaining columns list the values based on which these decisions were made. +Pseudo-code formulas are shown here to help understand how the different fields interact when making decisions. + +* `target_id` - (str) Transcript identifier. +* `parent_id` - (str) Gene identifier. +* `elig_xp` - (bool) Eligible expression level. `= (meanA >= Parameters$abund_thresh | meanB >= Parameters$abund_thresh)`. +* `elig` - (bool) Eligible for testing (meets the noise threshold and at least one other isoform is expressed). `= (elig_xp & totalA != 0 & totalB != 0 & (abundA != totalA | abundB != totalB))`. +* `sig` - (bool) Statistically significant. `= (pval_corr < Parameters$p_thresh)`. +* `elig_fx` - (bool) Eligible effect size. Proxy for biological significance. `= (Dprop > Parameters$dprop_thresh)`. +*. `quant_reprod` - (bool) Quantification reproducible. +For positive DTU, `= (quant_dtu_freq >= Parameters$quant_reprod_thresh)`, for non-DTU `= (quant_dtu_freq <= 1 - Parameters$quant_reprod_thresh)`. +* `rep_reprod` - (bool) Replication reproducible. +For positive DTU, `= (rep_dtu_freq >= Parameters$rep_reprod_thresh)`, for non-DTU `= (rep_dtu_freq <= 1 - Parameters$rep_reprod_thresh)`. +* `DTU` - (bool) The Transcript is Differentially Used. `= (sig & elig_fx & quant_reprod & rep_reprod)`. +* `gene_DTU` - (bool) Expanded from `Genes$DTU`. Indicates that the gene as a whole shows significant change in isoform ratios. `= (Genes[parent_id, DTU])`. +* `abundA` and `abundB` - (num) Either the mean or the sum of the abundances across replicates, depending on what is indicated by `Parameters$use_sums`. This is the value used for the tests. +* `stdevA` and `stdevB` - (num) The standard deviation of the abundance across the replicates. +* `log2FC` - (num) log2 of fold-change of transcript abundance: `= log2(abundB / abundA)`. `abundA` and `abundB` are not internally normalised for library size, so care must be taken when interpreting `log2FC`. +* `totalA` and `totalB` - (num) The total abundance for the gene: `totalA= sum(transcripts[parent_id, abundA])`. +* `propA` and `propB` - (num) The proportion of the gene expression owed to this transcript. `propA= abundA / totalA`. +* `Dprop` - (num) The difference in the proportion of the transcript between the two conditions (effect size). `= (probB - propA)`. +* `pval` - (num) The proportion equality test P-value for the transcript. +* `pval_corr` - (num) Multiple testing corrected p-value. `= p.adjust(pval, Parameters$correction)`. +* `quant_p_median` - (num) Median of corrected p-value across quantification bootstraps (not available in `lean` mode). +* `quant_p_min` - (num) Minimum observed (corrected) p-value across quantification bootstraps (not available in `lean` mode). +* `quant_p_max` - (num) Maximum observed (corrected) p-value across quantification bootstraps (not available in `lean` mode). +* `quant_Dprop_mean` - (num) Mean effect size across quantification bootstraps (not available in `lean` mode). +* `quant_Dprop_stdev` - (num) Standard deviation of effect size across quantification bootstraps (not available in `lean` mode). +* `quant_Dprop_min` - (num) Minimum observed effect size across quantification bootstraps (not available in `lean` mode). +* `quant_Dprop_max` - (num) Maximum observed effect size across quantification bootstraps (not available in `lean` mode). +* `quant_na_freq` - (num) Fraction of quantification iterations in which `DTU` could not be determined (not meeting pre-filtering criteria). +* `quant_dtu_freq` - (num) Fraction of quantification iterations that support a positive `DTU` classification. +* `rep_p_median` - (num) Median of corrected p-value across replication bootstraps (not available in `lean` mode). +* `rep_p_min` - (num) Minimum observed (corrected) p-value across replication bootstraps (not available in `lean` mode). +* `rep_p_max` - (num) Maximum observed (corrected) p-value across replication bootstraps (not available in `lean` mode). +* `rep_Dprop_mean` - (num) Mean effect size across replication bootstraps (not available in `lean` mode). +* `rep_Dprop_stdev` - (num) Standard deviation of effect size across replication bootstraps (not available in `lean` mode). +* `rep_Dprop_min` - (num) Minimum observed effect size across replication bootstraps (not available in `lean` mode). +* `rep_Dprop_max` - (num) Maximum observed effect size across replication bootstraps (not available in `lean` mode). +* `rep_na_freq` - (num) Fraction of replication iterations in which `DTU` could not be determined (not meeting pre-filtering criteria). +* `rep_dtu_freq` - (num) Fraction of replication iterations that support a positive `DTU` classification. + +**Note:** The fields reporting on the bootstraps will not be shown when bootstrapping is disabled. + + +## Abundances + +`Abundances` is a list of two `data.table`s, one for each condition. +Each transcript is represented by a single abundance value per replicate, so if bootstrapped data was used, these values are the means across iterations. If plain abundances were provided as input, then `Abundances` essentially contains the input data. These abundances are included in the output because they are required for some of RATs' plotting options. + +```{r} +# Elements of Abundances. +print( names(mydtu$Abundances) ) +``` + +1. `condA` - (num) The transcript abundances in the first condition. +2. `condB` - (num) The transcript abundances in the second condition. + +```{r} +# Abundance table for first condition. +print( head(mydtu$Abundances[[1]]) ) +``` + +*** + +# Quick results + +For your convenience, RATs provides a few functions to give you a quick summary of the run. They all follow the same style. + +These reports should not be seen as a substitute for the detailed RATs output. + +## Summary of DTU + +The `dtu_summary()` function lists the total number of genes and transcripts for each of 3 categories: + +* DTU: There is significant change in isoform ratios (in terms of both effect size and statistical significance). +* non-DTU: No significant change. +* ineligible: Ineligible for testing. Genes/transcripts with read count below the set threshold, or where the gene has only one known transcript. + +```{r} +# A tally of the outcome. +print( dtu_summary(mydtu) ) +``` + +The `get_dtu_ids()` function lists the coresponding identifiers per category. +The ID lists obtained are ordered by effect size (`Dprop`). + +```{r} +# Gene and transcript IDs corresponding to the tally above. +ids <- get_dtu_ids(mydtu) +print( names(ids) ) +print( ids ) +``` + +## Summary of isoform switching + +Isoform switching is a subset of DTU. Primary isoform switching is often considered the most likely +type of DTU to have an effect. The following two functions summarise the extent of isoform switching +in the results: + +```{r} +# A tally of genes switching isoform ranks. +print( dtu_switch_summary(mydtu) ) + +# The gene IDs displaying isoform switching. +ids <- get_switch_ids(mydtu) +print( names(ids) ) +``` + +## Summary of DTU plurality + +In case you want to know how many isoforms are affected per gene. + +```{r} +# A tally of genes switching isoform ranks. +print( dtu_plurality_summary(mydtu) ) + +# The gene IDs displaying isoform switching. +ids <- get_plurality_ids(mydtu) +``` + +These give you the number and IDs of genes in which 2, 3, etc... isoforms show DTU. + + +*** + +# Contact information + +The `rats` R package was developed within [The Barton Group](http://www.compbio.dundee.ac.uk) at [The University of Dundee](http://www.dundee.ac.uk) +by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch. + +To **report problems** or **ask for assistance**, please raise a new issue [on the project's support forum](https://github.com/bartongroup/Rats/issues). +Providing a *reproducible working example* that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure +to **read the vignette(s)**, and browse/search the support forum before posting a new issue, in case your question is already answered there. + +Enjoy! + +![](./figs/rats_logo.png) + + diff --git a/inst/doc/output.html b/inst/doc/output.html new file mode 100644 index 0000000..2f7f1e7 --- /dev/null +++ b/inst/doc/output.html @@ -0,0 +1,624 @@ + + + + + + + + + + + + + + + +RATs: Raw Output + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ + + + + + + +
+
library(rats)
+library(data.table)
+

Let’s set up an example, using RAT’s data emulator (used for code testing, not suitable for data simulations).

+
# Simulate some data.
+simdat <- sim_boot_data(clean=TRUE) 
+# For convenience let's assign the contents of the list to separate variables
+mycond_A <- simdat[[2]]   # Simulated bootstrapped data for one condition.
+mycond_B <- simdat[[3]]   # Simulated bootstrapped data for other condition.
+myannot <- simdat[[1]]    # Transcript and gene IDs for the above data.
+
+# Call DTU
+mydtu <- call_DTU(annot= myannot, verbose= FALSE,
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  dprop_thresh=0.1, qboot=TRUE, rboot=FALSE)
+
+
+

Output structure

+

The output of RATs is a list containing 4 elements:

+
print( names(mydtu) )
+
## [1] "Parameters"  "Genes"       "Transcripts" "Abundances"
+
+

Parameters

+

Parameters is a list that contains information about the data and the settings for a particular run.

+
# Parameter list's elements.
+print( names(mydtu$Parameters) )
+
##  [1] "description"         "time"                "rats_version"       
+##  [4] "R_version"           "var_name"            "cond_A"             
+##  [7] "cond_B"              "data_type"           "num_replic_A"       
+## [10] "num_replic_B"        "num_genes"           "num_transc"         
+## [13] "tests"               "use_sums"            "correction"         
+## [16] "p_thresh"            "abund_thresh"        "dprop_thresh"       
+## [19] "abund_scaling"       "quant_boot"          "quant_reprod_thresh"
+## [22] "quant_bootnum"       "rep_boot"            "rep_reprod_thresh"  
+## [25] "rep_bootnum"         "seed"                "reckless"           
+## [28] "lean"
+
    +
  • description - (str) Free-text description of the run. It is useful to record data sources, annotation source and version, experimental parameters, etc…
  • +
  • time - (str) Date and time for the run. This does not represent the exact time the run started.
  • +
  • rats_version - (str) The version of RATs.
  • +
  • R_version - (str) The version of R (including OS architecture).
  • +
  • var_name - (str) The value passed to the varname parameter.
  • +
  • cond_A & cond_B - (str) The values passed to the name_A and name_B parameters.
  • +
  • data_type - (str) The format of the input data.
  • +
  • num_replic_A & num_replic_B - (int) The number of samples in each condition.
  • +
  • num_genes - (int) The number of genes in the provided annotation.
  • +
  • num_transc - (int) The number of transcripts in the provided annotation.
  • +
  • tests - (str) The value passed to the testmode parameter.
  • +
  • use_sums - (bool) Sum the replicates instead of averaging them (pre-0.7.0 RATs always summed).
  • +
  • p_thresh - (num) The value passed to the p_thresh parameter.
  • +
  • abund_thresh - (num) The value passed to the abund_thresh parameter.
  • +
  • dprop_thresh - (num) The value passed to the dprop_thresh parameter.
  • +
  • correction - (str) Multiple testing correction method.
  • +
  • abund_scaling - (num) The value(s) passed to the scaling parameter. It will be either a single numeric value or a named vector of values.
  • +
  • quant_boot - (bool) The value passed to the qboots parameter.
  • +
  • quant_reprod_thresh - (num) The value passed to the qrep_thresh parameter, if qboot==TRUE.
  • +
  • quant_bootnum - (int) The value passed to the qbootnum parameter, if qboot==TRUE.
  • +
  • rep_boot - (bool) The value passed to the rboot parameter.
  • +
  • rep_reprod_thresh - (num) The value passed to the rrep_thresh parameter, if rboot==TRUE.
  • +
  • rep_bootnum - (int) The number of replicate bootstrapping iterations (currently M*N, where M and N are the numbers of samples in the two conditions), if rboot==TRUE.
  • +
  • seed - (int) Custom seed for the random generator. NA if none was specified.
  • +
  • reckless - (bool) The value passed to the reckless parameter.
  • +
  • lean - (bool) The value passed to the lean parameter.
  • +
+

Note: If bootstraps are disabled, the bootstrap-related fields may be NA, regardless of supplied values, to reflect the fact that they were not used.

+
+
+

Genes

+

Genes is a data.table listing results at the gene level. For your convenience, the respective aggregated transcript-level DTU calls are also included here (defined as at least one isoform being called DTU individually).

+
# Genes table's fields.
+print( names(mydtu$Genes) )
+
##  [1] "parent_id"      "elig"           "sig"            "elig_fx"       
+##  [5] "quant_reprod"   "DTU"            "transc_DTU"     "known_transc"  
+##  [9] "detect_transc"  "elig_transc"    "maxDprop"       "pval"          
+## [13] "pval_corr"      "quant_na_freq"  "quant_dtu_freq"
+

The first few columns show the result of each decision step in a boolean manner, allowing easy filtering of the table. The remaining columns list the values based on which these decisions were made. Pseudo-code formulas are shown here to help understand how the different fields interact when making decisions.

+
    +
  • parent_id - (str) Gene identifier.
  • +
  • elig - (bool) Eligible for testing. Whether the gene met the pre-filtering criteria. = (elig_transc >= 2).
  • +
  • sig - (bool) Statistically significant. = (pval_corr < Parameters$p_thresh).
  • +
  • elig_fx - (bool) Eligible effect size. Whether at least one of the isoforms meets the effect size criterion. = any(Transcript[parent_id, elig_fx]).
  • +
  • quant_reprod - (bool) Result reproducible across quantification iterations. For positive DTU, = (quant_dtu_freq >= Parameters$quant_reprod_thresh), for non-DTU = (quant_dtu_freq <= 1 - Parameters$quant_reprod_thresh).
  • +
  • rep_reprod - (bool) Result reproducible across replicates. For positive DTU, = (rep_dtu_freq >= Parameters$rep_reprod_thresh), for non-DTU = (rep_dtu_freq <= 1 - Parameters$rep_reprod_thresh).
  • +
  • DTU - (bool) Gene-level Differential Transcript Usage. = (sig & elig_fx & quant_reprod & rep_reprod).
  • +
  • transc_DTU - (bool) Aggregated from Transcripts$DTU: At least one isoform was individually reported as DTU. = (Transcript[ , any(DTU), by=parent_id]).
  • +
  • known_transc - (int) Number of known trascripts for this gene according to the given annotation.
  • +
  • detect_trancs - (int) Number of detected (expressed) transcripts in the given dataset.
  • +
  • elig_transc - (int) Number of eligible transcripts, aggregated from Transcripts$elig.
  • +
  • pval - (num) G test of independence p-value for the isoform ratios of the gene.
  • +
  • pval_corr - (num) Multiple testing corrected p-value. pval_corr= p.adjust(pval, Parameters$correction).
  • +
  • quant_p_median - (num) Median of corrected p-values across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_min - (num) Minimum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_max - (num) Maximum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_na_freq - (num) Fraction of quantification iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • quant_dtu_freq - (num) Fraction of replicate iterations that support a positive DTU classification.
  • +
  • rep_p_median - (num) Median p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_min - (num) Minimum observed p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_max - (num) Maximum observed p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_na_freq - (num) Fraction of replication iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • rep_dtu_freq - (num) Fraction of replication iterations that support a positive DTU classification.
  • +
+

Note: The fields reporting on the bootstraps will not be shown when bootstrapping is disabled.

+
+
+

Transcripts

+

Transcripts is a data.table listing results at the transcript level. For your convenience, the respective gene-level DTU calls are also included here.

+
# Transcripts table's fields.
+print( names(mydtu$Transcripts) )
+
##  [1] "target_id"      "parent_id"      "elig_xp"        "elig"          
+##  [5] "sig"            "elig_fx"        "quant_reprod"   "DTU"           
+##  [9] "gene_DTU"       "abundA"         "abundB"         "stdevA"        
+## [13] "stdevB"         "log2FC"         "totalA"         "totalB"        
+## [17] "propA"          "propB"          "Dprop"          "pval"          
+## [21] "pval_corr"      "quant_na_freq"  "quant_dtu_freq"
+

The first few columns show the result of each decision step in a boolean manner, allowing easy filtering of the table. The remaining columns list the values based on which these decisions were made. Pseudo-code formulas are shown here to help understand how the different fields interact when making decisions.

+
    +
  • target_id - (str) Transcript identifier.
  • +
  • parent_id - (str) Gene identifier.
  • +
  • elig_xp - (bool) Eligible expression level. = (meanA >= Parameters$abund_thresh | meanB >= Parameters$abund_thresh).
  • +
  • elig - (bool) Eligible for testing (meets the noise threshold and at least one other isoform is expressed). = (elig_xp & totalA != 0 & totalB != 0 & (abundA != totalA | abundB != totalB)).
  • +
  • sig - (bool) Statistically significant. = (pval_corr < Parameters$p_thresh).
  • +
  • elig_fx - (bool) Eligible effect size. Proxy for biological significance. = (Dprop > Parameters$dprop_thresh). *. quant_reprod - (bool) Quantification reproducible. For positive DTU, = (quant_dtu_freq >= Parameters$quant_reprod_thresh), for non-DTU = (quant_dtu_freq <= 1 - Parameters$quant_reprod_thresh).
  • +
  • rep_reprod - (bool) Replication reproducible. For positive DTU, = (rep_dtu_freq >= Parameters$rep_reprod_thresh), for non-DTU = (rep_dtu_freq <= 1 - Parameters$rep_reprod_thresh).
  • +
  • DTU - (bool) The Transcript is Differentially Used. = (sig & elig_fx & quant_reprod & rep_reprod).
  • +
  • gene_DTU - (bool) Expanded from Genes$DTU. Indicates that the gene as a whole shows significant change in isoform ratios. = (Genes[parent_id, DTU]).
  • +
  • abundA and abundB - (num) Either the mean or the sum of the abundances across replicates, depending on what is indicated by Parameters$use_sums. This is the value used for the tests.
  • +
  • stdevA and stdevB - (num) The standard deviation of the abundance across the replicates.
  • +
  • log2FC - (num) log2 of fold-change of transcript abundance: = log2(abundB / abundA). abundA and abundB are not internally normalised for library size, so care must be taken when interpreting log2FC.
  • +
  • totalA and totalB - (num) The total abundance for the gene: totalA= sum(transcripts[parent_id, abundA]).
  • +
  • propA and propB - (num) The proportion of the gene expression owed to this transcript. propA= abundA / totalA.
  • +
  • Dprop - (num) The difference in the proportion of the transcript between the two conditions (effect size). = (probB - propA).
  • +
  • pval - (num) The proportion equality test P-value for the transcript.
  • +
  • pval_corr - (num) Multiple testing corrected p-value. = p.adjust(pval, Parameters$correction).
  • +
  • quant_p_median - (num) Median of corrected p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_min - (num) Minimum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_max - (num) Maximum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_mean - (num) Mean effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_stdev - (num) Standard deviation of effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_min - (num) Minimum observed effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_max - (num) Maximum observed effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_na_freq - (num) Fraction of quantification iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • quant_dtu_freq - (num) Fraction of quantification iterations that support a positive DTU classification.
  • +
  • rep_p_median - (num) Median of corrected p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_min - (num) Minimum observed (corrected) p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_max - (num) Maximum observed (corrected) p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_mean - (num) Mean effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_stdev - (num) Standard deviation of effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_min - (num) Minimum observed effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_max - (num) Maximum observed effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_na_freq - (num) Fraction of replication iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • rep_dtu_freq - (num) Fraction of replication iterations that support a positive DTU classification.
  • +
+

Note: The fields reporting on the bootstraps will not be shown when bootstrapping is disabled.

+
+
+

Abundances

+

Abundances is a list of two data.tables, one for each condition. Each transcript is represented by a single abundance value per replicate, so if bootstrapped data was used, these values are the means across iterations. If plain abundances were provided as input, then Abundances essentially contains the input data. These abundances are included in the output because they are required for some of RATs’ plotting options.

+
# Elements of Abundances.
+print( names(mydtu$Abundances) )
+
## [1] "condA" "condB"
+
    +
  1. condA - (num) The transcript abundances in the first condition.
  2. +
  3. condB - (num) The transcript abundances in the second condition.
  4. +
+
# Abundance table for first condition.
+print( head(mydtu$Abundances[[1]]) )
+
##     V1  V2 target_id parent_id
+## 1: 100 115    ALLA:1      ALLA
+## 2:  40  30    ALLA:2      ALLA
+## 3: 300 400    D2TE_a      D2TE
+## 4: 400 500    D2TE_b      D2TE
+## 5: 250 270     1D2TU      D2TU
+## 6: 250 300     2D2TU      D2TU
+
+
+
+
+

Quick results

+

For your convenience, RATs provides a few functions to give you a quick summary of the run. They all follow the same style.

+

These reports should not be seen as a substitute for the detailed RATs output.

+
+

Summary of DTU

+

The dtu_summary() function lists the total number of genes and transcripts for each of 3 categories:

+
    +
  • DTU: There is significant change in isoform ratios (in terms of both effect size and statistical significance).
  • +
  • non-DTU: No significant change.
  • +
  • ineligible: Ineligible for testing. Genes/transcripts with read count below the set threshold, or where the gene has only one known transcript.
  • +
+
# A tally of the outcome.
+print( dtu_summary(mydtu) )
+
##                           category tally
+## 1            DTU genes (gene test)     6
+## 2        non-DTU genes (gene test)     3
+## 3     ineligible genes (gene test)     3
+## 4         DTU genes (transc. test)     6
+## 5     non-DTU genes (transc. test)     3
+## 6  ineligible genes (transc. test)     3
+## 7           DTU genes (both tests)     6
+## 8       non-DTU genes (both tests)     3
+## 9    ineligible genes (both tests)     3
+## 10                 DTU transcripts    14
+## 11             non-DTU transcripts     7
+## 12          ineligible transcripts     5
+

The get_dtu_ids() function lists the coresponding identifiers per category. The ID lists obtained are ordered by effect size (Dprop).

+
# Gene and transcript IDs corresponding to the tally above.
+ids <- get_dtu_ids(mydtu)
+print( names(ids) )
+
##  [1] "DTU genes (gene test)"           "non-DTU genes (gene test)"      
+##  [3] "ineligible genes (gene test)"    "DTU genes (transc. test)"       
+##  [5] "non-DTU genes (transc. test)"    "ineligible genes (transc. test)"
+##  [7] "DTU genes (both tests)"          "non-DTU genes (both tests)"     
+##  [9] "ineligible genes (both tests)"   "DTU transcripts"                
+## [11] "non-DTU transcripts"             "ineligible transcripts"
+
print( ids )
+
## $`DTU genes (gene test)`
+## [1] "XSW"  "MIX"  "SW"   "LC"   "ALLA" "D2TU"
+## 
+## $`non-DTU genes (gene test)`
+## [1] "D2TE" "SAME" "FAKE"
+## 
+## $`ineligible genes (gene test)`
+## [1] "LONE" "SOLO" "NN"  
+## 
+## $`DTU genes (transc. test)`
+## [1] "XSW"  "MIX"  "SW"   "LC"   "ALLA" "D2TU"
+## 
+## $`non-DTU genes (transc. test)`
+## [1] "D2TE" "SAME" "FAKE"
+## 
+## $`ineligible genes (transc. test)`
+## [1] "LONE" "SOLO" "NN"  
+## 
+## $`DTU genes (both tests)`
+## [1] "XSW"  "MIX"  "SW"   "LC"   "ALLA" "D2TU"
+## 
+## $`non-DTU genes (both tests)`
+## [1] "D2TE" "SAME" "FAKE"
+## 
+## $`ineligible genes (both tests)`
+## [1] "LONE" "SOLO" "NN"  
+## 
+## $`DTU transcripts`
+##  [1] "XSW:one" "XSW:two" "MIX.b"   "SW1"     "SW2"     "MIX.a"   "LC1"    
+##  [8] "LC2"     "ALLA:1"  "ALLA:2"  "MIX.ab"  "2D2TU"   "1D2TU"   "MIX.l2" 
+## 
+## $`non-DTU transcripts`
+## [1] "D2TE_b" "D2TE_a" "SAME_1" "SAME_2" "FAKE-2" "FAKE-1" "MIX.l1"
+## 
+## $`ineligible transcripts`
+## [1] "LONE.a" "MIX.n"  "SOLO.1" "NNa"    "NNb"
+
+
+

Summary of isoform switching

+

Isoform switching is a subset of DTU. Primary isoform switching is often considered the most likely type of DTU to have an effect. The following two functions summarise the extent of isoform switching in the results:

+
# A tally of genes switching isoform ranks.
+print( dtu_switch_summary(mydtu) )
+
##                            category genes
+## 1        Primary switch (gene test)     4
+## 2    Non-primary switch (gene test)     1
+## 3     Primary switch (transc. test)     4
+## 4 Non-primary switch (transc. test)     1
+## 5       Primary switch (both tests)     4
+## 6   Non-primary switch (both tests)     1
+
# The gene IDs displaying isoform switching.
+ids <- get_switch_ids(mydtu)
+print( names(ids) )
+
## [1] "Primary switch (gene test)"        "Non-primary switch (gene test)"   
+## [3] "Primary switch (transc. test)"     "Non-primary switch (transc. test)"
+## [5] "Primary switch (both tests)"       "Non-primary switch (both tests)"
+
+
+

Summary of DTU plurality

+

In case you want to know how many isoforms are affected per gene.

+
# A tally of genes switching isoform ranks.
+print( dtu_plurality_summary(mydtu) )
+
##   isof_affected num_of_genes
+## 1             2            5
+## 2             4            1
+
# The gene IDs displaying isoform switching.
+ids <- get_plurality_ids(mydtu)
+

These give you the number and IDs of genes in which 2, 3, etc… isoforms show DTU.

+
+
+
+
+

Contact information

+

The rats R package was developed within The Barton Group at The University of Dundee by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch.

+

To report problems or ask for assistance, please raise a new issue on the project’s support forum. Providing a reproducible working example that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure to read the vignette(s), and browse/search the support forum before posting a new issue, in case your question is already answered there.

+

Enjoy!

+

+
+ + + +
+
+ +
+ + + + + + + + + + + + + + + + diff --git a/inst/doc/plots.R b/inst/doc/plots.R new file mode 100644 index 0000000..4ce996e --- /dev/null +++ b/inst/doc/plots.R @@ -0,0 +1,62 @@ +## ----setup, include=FALSE----------------------------------------------------- +knitr::opts_chunk$set(echo = TRUE) + +## ---- include=FALSE----------------------------------------------------------- +library(rats) + +## ----------------------------------------------------------------------------- +# Simulate some data. +simdat <- sim_boot_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +# Call DTU +mydtu <- call_DTU(annot= myannot, verbose= FALSE, + boot_data_A= mycond_A, boot_data_B= mycond_B, + dprop_thresh=0.1, qboot=TRUE, rboot=FALSE) + +## ----------------------------------------------------------------------------- +# Grouping by condition (DEFAULT): +plot_gene(mydtu, "MIX", style="bycondition") + +## ----------------------------------------------------------------------------- +# Grouping by isoform: +plot_gene(mydtu, "MIX", style="byisoform") + +## ----eval=FALSE--------------------------------------------------------------- +# models <- annot2models('/my/annotation/file.gtf') +# library(ggbio) +# # This will plot the structure of all isoforms for the given gene ID. +# autoplot(models[['mygeneID']]) + +## ---- eval=FALSE-------------------------------------------------------------- +# # Proportion change VS transcript-level significance. Each point is a transcript +# plot_overview(mydtu, type="tvolcano") +# +# # This can also be plotted for genes, by using the largest isoform effect size as proxy. +# plot_overview(mydtu, type="gvolcano") + +## ---- eval=FALSE-------------------------------------------------------------- +# # Distribution of proportion change. +# plot_overview(mydtu, type="dprop") +# +# # Distribution of largest isoform proportion change per gene. +# plot_overview(mydtu, type="maxdprop") + +## ---- eval=FALSE-------------------------------------------------------------- +# # Proportion change VS transcript-level significance. Each point is a transcript +# plot_overview(mydtu, type="fcvolcano") +# +# # This can also be plotted for genes, by using the largest isoform effect size as proxy. +# plot_overview(mydtu, type="fcVSdprop") + +## ----------------------------------------------------------------------------- +# Pairwise Pearson's correlations among samples. +plot_diagnostics(mydtu, type='cormat') # Default type. + +## ---- eval=FALSE-------------------------------------------------------------- +# # Start the interactive volcano plot. +# plot_shiny_volcano(mydtu) + diff --git a/inst/doc/plots.Rmd b/inst/doc/plots.Rmd new file mode 100644 index 0000000..136b08d --- /dev/null +++ b/inst/doc/plots.Rmd @@ -0,0 +1,214 @@ +--- +title: 'RATs: Plots' +author: "Kimon Froussios" +date: "08 JUL 2019" +output: + html_document: + keep_md: yes + theme: readable + toc: yes + toc_float: yes +vignette: > + \usepackage[utf8]{inputenc} + %\VignetteIndexEntry{RATs 3: Plots} + %\VignetteEngine{knitr::rmarkdown} +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = TRUE) +``` + +*** + +```{r, include=FALSE} +library(rats) +``` + +Set up an example. + +```{r} +# Simulate some data. +simdat <- sim_boot_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +# Call DTU +mydtu <- call_DTU(annot= myannot, verbose= FALSE, + boot_data_A= mycond_A, boot_data_B= mycond_B, + dprop_thresh=0.1, qboot=TRUE, rboot=FALSE) +``` + + +*** + + +# Visualisation of results + + +The RATs output object provides a host of information and we encourage users to familiarize themselves with it. +But a good plot is worth a thousand numbers. RATs provides a non-exhaustive set of basic visualisation options for the results. + +The plotting functions return a `ggplot2` object. You can just `print()` it, or assign it to a variable, further customise it with standard [ggplot2](http://ggplot2.org) operations, or even pass it on to other viewing functions, like `plotly::ggplotly()`. + +## Inspection of a given gene + +### Isoform abundances + +This is a very useful function for inspecting a gene of interest. It enables quick visual evaluation of the dispersion of the replicate measurements, the magnitude of the absolute and proportion changes, the presence of outliers, and the consistency among the replicates. + +```{r} +# Grouping by condition (DEFAULT): +plot_gene(mydtu, "MIX", style="bycondition") +``` + +* The top two facets show the absolute abundances (counts) of the isoforms as supplied in the input. +* The bottom two facets show the correspondng relative abundances (proportions). +* The facets on the left ocrrespond to one condition, the facets on the right correspond to the other condition. +* The boxplots describe the abundance distribution of each isoform across replicates. +* The actual abundance measurements are overlayed as points. +* The set of abundances obtained in each replicate is shown by the lines connecting the points. This highlights the level of consistency between the replicates. +* The presence of DTU for each transcript is encoded in the fill and shape of the abundance points. +* The points and lines are placed slightly off-centre to prevent replicates masking one another when the measurements are very similar. +* The colours of the replicates are recycled between the two conditions. So in the example, there are 4 samples: controls-1, controls-2, patients-1 and patients-2. + +When there are many replicates or many isoforms, it may be preferable to group abundances by isoform, making individual comparisons easier: + +```{r} +# Grouping by isoform: +plot_gene(mydtu, "MIX", style="byisoform") +``` + +### Customisation of the abundances plot + +#### Change information layers + +The `fillby`, `colourby` and `shapeby` parameters of `plot_gene()` can be respectively used to control which information layers +are encoded as fill, line/point colour, and point shape. Possible values are `c("isoform", "condition", "DTU", "none", "replicate")`. +Be aware that some combinations of plot style and information layers are not possible. + +#### Change colour code + +Colour codes can be customised by specifying new values to the corresponding parameters of `plot_gene()`: + +* `isofcolvec` - Colour vector for isoform highlighting. Used to build a colorRampPalette. +* `dtucolvec` - Colour vector for DTU highlighting. +* `condcolvec` - Colour vector for condition highlighting. +* `replcolvec` - Colour vector for replicate highlighting. Used to build a colorRampPalette. +* `nonecol` - Colour to use when no colour coding is wanted. + +An example of a colour vector, using standard R colour aliases, would be `c('blue', darkred', 'gold')`. + + +### Structure of the given gene + +With the use of the third-party Bioconductor package [ggbio](https://bioconductor.org/packages/release/bioc/html/ggbio.html), one can plot gene models from `GRanges`/`GRangesList` objects. This can be useful in interpreting transcript expression and DTU. + +Therefore RATs offers a helper function to create an appropriate collection of `GRanges`/`GRangesList` objects from a GTF file. The collection is structured as a list, indexed by the GTF `gene ID` values. Each list element is a `GRangesList` object with the annotated transcripts for that gene. + +```{r eval=FALSE} +models <- annot2models('/my/annotation/file.gtf') +library(ggbio) +# This will plot the structure of all isoforms for the given gene ID. +autoplot(models[['mygeneID']]) +``` + +For more options and more refined plots, refer to the `ggbio` documentation. + + +## Overview plots + +Our simulated dataset is too small to properly demonstrate what these plots might look like. +So, instead, each one is accompanied by a static image of the plot created with a real and much larger dataset. + +Possibly the most common plot in differential expression is the volcano plot, which plots the effect size against +the statistical significance. The thresholds are also shown, although the default significance threshold of 0.05 +is very low (hint: no lines are drawn for the axes). + +```{r, eval=FALSE} +# Proportion change VS transcript-level significance. Each point is a transcript +plot_overview(mydtu, type="tvolcano") + +# This can also be plotted for genes, by using the largest isoform effect size as proxy. +plot_overview(mydtu, type="gvolcano") +``` + +This is what these look like on a larger dataset: +![Transcript significance VS effect size](./figs/tvolcano.jpg) + +You can also get density histograms for the volcanos (the Y axis is square-root compressed): + +```{r, eval=FALSE} +# Distribution of proportion change. +plot_overview(mydtu, type="dprop") + +# Distribution of largest isoform proportion change per gene. +plot_overview(mydtu, type="maxdprop") +``` + +This is what these look like on a larger dataset: +![Effect size distribution](./figs/dprop.jpg) + +Although fold-changes of transcript expression are not tied to DTU, you can plot the traditional FC volcano and the relationship between FC and proportion change. Bear in mind that the FCs will be based on the abundances provided as input, *without any adjustments* such as library size normalization. + +```{r, eval=FALSE} +# Proportion change VS transcript-level significance. Each point is a transcript +plot_overview(mydtu, type="fcvolcano") + +# This can also be plotted for genes, by using the largest isoform effect size as proxy. +plot_overview(mydtu, type="fcVSdprop") +``` + +![Fold change VS significance](./figs/fcvolcano.jpg) +![Fold change VS proportion change](./figs/fcvsdprop.jpg) + + +## Diagnostic plots + +Currently there is only one plot type in this category. + +```{r} +# Pairwise Pearson's correlations among samples. +plot_diagnostics(mydtu, type='cormat') # Default type. +``` + +What you want to see here, is a nice separation between the samples of different conditions. +Anomalies in this plot may indicate batch effects or mislabelled samples. + + +## Interactive plots + +If you prefer picking points from a plot rather than sorting through tables, the gene-level volcano plot is also available through +an interactive `shiny` app, that pulls up the relevant `Gene` and `Transcript` results and the isoform abundance plot +for any volcano point you select. + +```{r, eval=FALSE} +# Start the interactive volcano plot. +plot_shiny_volcano(mydtu) +``` + +1. Hovering over a point (or cluster of points) will show the gene IDs and some summary info. +2. Clicking on a point will display the all the available information calculated for the gene and its isoforms, as +well as draw the isoform abundance plot for the gene. + +When you finish exploring the volcano plot, close the popup window or stop the shiny runtime in order to return to your R terminal. + + +*** + + +# Contact information + +The `rats` R package was developed within [The Barton Group](http://www.compbio.dundee.ac.uk) at [The University of Dundee](http://www.dundee.ac.uk) +by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch. + +To **report problems** or **ask for assistance**, please raise a new issue [on the project's support forum](https://github.com/bartongroup/Rats/issues). +Providing a *reproducible working example* that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure +to **read the vignette(s)**, and browse/search the support forum before posting a new issue, in case your question is already answered there. + +Enjoy! + +![](./figs/rats_logo.png) + + diff --git a/inst/doc/plots.html b/inst/doc/plots.html new file mode 100644 index 0000000..04d7f9b --- /dev/null +++ b/inst/doc/plots.html @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + +RATs: Plots + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ + + + + + + +
+

Set up an example.

+
# Simulate some data.
+simdat <- sim_boot_data(clean=TRUE) 
+# For convenience let's assign the contents of the list to separate variables
+mycond_A <- simdat[[2]]   # Simulated bootstrapped data for one condition.
+mycond_B <- simdat[[3]]   # Simulated bootstrapped data for other condition.
+myannot <- simdat[[1]]    # Transcript and gene IDs for the above data.
+
+# Call DTU
+mydtu <- call_DTU(annot= myannot, verbose= FALSE,
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  dprop_thresh=0.1, qboot=TRUE, rboot=FALSE)
+
+
+

Visualisation of results

+

The RATs output object provides a host of information and we encourage users to familiarize themselves with it. But a good plot is worth a thousand numbers. RATs provides a non-exhaustive set of basic visualisation options for the results.

+

The plotting functions return a ggplot2 object. You can just print() it, or assign it to a variable, further customise it with standard ggplot2 operations, or even pass it on to other viewing functions, like plotly::ggplotly().

+
+

Inspection of a given gene

+
+

Isoform abundances

+

This is a very useful function for inspecting a gene of interest. It enables quick visual evaluation of the dispersion of the replicate measurements, the magnitude of the absolute and proportion changes, the presence of outliers, and the consistency among the replicates.

+
# Grouping by condition (DEFAULT):
+plot_gene(mydtu, "MIX", style="bycondition")
+

+
    +
  • The top two facets show the absolute abundances (counts) of the isoforms as supplied in the input.
  • +
  • The bottom two facets show the correspondng relative abundances (proportions).
  • +
  • The facets on the left ocrrespond to one condition, the facets on the right correspond to the other condition.
  • +
  • The boxplots describe the abundance distribution of each isoform across replicates.
  • +
  • The actual abundance measurements are overlayed as points.
  • +
  • The set of abundances obtained in each replicate is shown by the lines connecting the points. This highlights the level of consistency between the replicates.
  • +
  • The presence of DTU for each transcript is encoded in the fill and shape of the abundance points.
  • +
  • The points and lines are placed slightly off-centre to prevent replicates masking one another when the measurements are very similar.
  • +
  • The colours of the replicates are recycled between the two conditions. So in the example, there are 4 samples: controls-1, controls-2, patients-1 and patients-2.
  • +
+

When there are many replicates or many isoforms, it may be preferable to group abundances by isoform, making individual comparisons easier:

+
# Grouping by isoform:
+plot_gene(mydtu, "MIX", style="byisoform")
+

+
+
+

Customisation of the abundances plot

+
+

Change information layers

+

The fillby, colourby and shapeby parameters of plot_gene() can be respectively used to control which information layers are encoded as fill, line/point colour, and point shape. Possible values are c("isoform", "condition", "DTU", "none", "replicate"). Be aware that some combinations of plot style and information layers are not possible.

+
+
+

Change colour code

+

Colour codes can be customised by specifying new values to the corresponding parameters of plot_gene():

+
    +
  • isofcolvec - Colour vector for isoform highlighting. Used to build a colorRampPalette.
  • +
  • dtucolvec - Colour vector for DTU highlighting.
  • +
  • condcolvec - Colour vector for condition highlighting.
  • +
  • replcolvec - Colour vector for replicate highlighting. Used to build a colorRampPalette.
  • +
  • nonecol - Colour to use when no colour coding is wanted.
  • +
+

An example of a colour vector, using standard R colour aliases, would be c('blue', darkred', 'gold').

+
+
+
+

Structure of the given gene

+

With the use of the third-party Bioconductor package ggbio, one can plot gene models from GRanges/GRangesList objects. This can be useful in interpreting transcript expression and DTU.

+

Therefore RATs offers a helper function to create an appropriate collection of GRanges/GRangesList objects from a GTF file. The collection is structured as a list, indexed by the GTF gene ID values. Each list element is a GRangesList object with the annotated transcripts for that gene.

+
models <- annot2models('/my/annotation/file.gtf')
+library(ggbio)
+# This will plot the structure of all isoforms for the given gene ID.
+autoplot(models[['mygeneID']])
+

For more options and more refined plots, refer to the ggbio documentation.

+
+
+
+

Overview plots

+

Our simulated dataset is too small to properly demonstrate what these plots might look like. So, instead, each one is accompanied by a static image of the plot created with a real and much larger dataset.

+

Possibly the most common plot in differential expression is the volcano plot, which plots the effect size against the statistical significance. The thresholds are also shown, although the default significance threshold of 0.05 is very low (hint: no lines are drawn for the axes).

+
# Proportion change VS transcript-level significance. Each point is a transcript
+plot_overview(mydtu, type="tvolcano")
+
+# This can also be plotted for genes, by using the largest isoform effect size as proxy.
+plot_overview(mydtu, type="gvolcano")
+

This is what these look like on a larger dataset: Transcript significance VS effect size

+

You can also get density histograms for the volcanos (the Y axis is square-root compressed):

+
# Distribution of proportion change.
+plot_overview(mydtu, type="dprop")
+
+# Distribution of largest isoform proportion change per gene.
+plot_overview(mydtu, type="maxdprop")
+

This is what these look like on a larger dataset: Effect size distribution

+

Although fold-changes of transcript expression are not tied to DTU, you can plot the traditional FC volcano and the relationship between FC and proportion change. Bear in mind that the FCs will be based on the abundances provided as input, without any adjustments such as library size normalization.

+
# Proportion change VS transcript-level significance. Each point is a transcript
+plot_overview(mydtu, type="fcvolcano")
+
+# This can also be plotted for genes, by using the largest isoform effect size as proxy.
+plot_overview(mydtu, type="fcVSdprop")
+

Fold change VS significance Fold change VS proportion change

+
+
+

Diagnostic plots

+

Currently there is only one plot type in this category.

+
# Pairwise Pearson's correlations among samples.
+plot_diagnostics(mydtu, type='cormat') # Default type.
+

+

What you want to see here, is a nice separation between the samples of different conditions. Anomalies in this plot may indicate batch effects or mislabelled samples.

+
+
+

Interactive plots

+

If you prefer picking points from a plot rather than sorting through tables, the gene-level volcano plot is also available through an interactive shiny app, that pulls up the relevant Gene and Transcript results and the isoform abundance plot for any volcano point you select.

+
# Start the interactive volcano plot.
+plot_shiny_volcano(mydtu)
+
    +
  1. Hovering over a point (or cluster of points) will show the gene IDs and some summary info.
  2. +
  3. Clicking on a point will display the all the available information calculated for the gene and its isoforms, as well as draw the isoform abundance plot for the gene.
  4. +
+

When you finish exploring the volcano plot, close the popup window or stop the shiny runtime in order to return to your R terminal.

+
+
+
+
+

Contact information

+

The rats R package was developed within The Barton Group at The University of Dundee by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch.

+

To report problems or ask for assistance, please raise a new issue on the project’s support forum. Providing a reproducible working example that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure to read the vignette(s), and browse/search the support forum before posting a new issue, in case your question is already answered there.

+

Enjoy!

+

+
+ + + +
+
+ +
+ + + + + + + + + + + + + + + + diff --git a/man/annot2ids.Rd b/man/annot2ids.Rd index 9036ae4..8ac3151 100644 --- a/man/annot2ids.Rd +++ b/man/annot2ids.Rd @@ -4,8 +4,7 @@ \alias{annot2ids} \title{(deprecated) Extract matching transcript and gene IDs from a GTF file.} \usage{ -annot2ids(annotfile, transc_header = "target_id", - gene_header = "parent_id") +annot2ids(annotfile, transc_header = "target_id", gene_header = "parent_id") } \arguments{ \item{annotfile}{A GTF file.} diff --git a/man/calculate_DTU.Rd b/man/calculate_DTU.Rd index a1f5821..0ff9669 100644 --- a/man/calculate_DTU.Rd +++ b/man/calculate_DTU.Rd @@ -4,9 +4,20 @@ \alias{calculate_DTU} \title{Set up and execute the tests.} \usage{ -calculate_DTU(counts_A, counts_B, tx_filter, test_transc, test_genes, full, - count_thresh, p_thresh, dprop_thresh, correction, threads = 1, - use_sums = FALSE) +calculate_DTU( + counts_A, + counts_B, + tx_filter, + test_transc, + test_genes, + full, + count_thresh, + p_thresh, + dprop_thresh, + correction, + threads = 1, + use_sums = FALSE +) } \arguments{ \item{counts_A}{A data.table of counts for condition A. x: sample, y: transcript.} diff --git a/man/call_DTU.Rd b/man/call_DTU.Rd index 86db111..5fbe92d 100644 --- a/man/call_DTU.Rd +++ b/man/call_DTU.Rd @@ -4,15 +4,37 @@ \alias{call_DTU} \title{Calculate differential transcript usage.} \usage{ -call_DTU(annot = NULL, TARGET_COL = "target_id", - PARENT_COL = "parent_id", count_data_A = NULL, count_data_B = NULL, - boot_data_A = NULL, boot_data_B = NULL, name_A = "Condition-A", - name_B = "Condition-B", varname = "condition", use_sums = FALSE, - p_thresh = 0.05, abund_thresh = 5, dprop_thresh = 0.2, - correction = "BH", scaling = 1, testmode = "both", lean = TRUE, - qboot = TRUE, qbootnum = 0L, qrep_thresh = 0.95, rboot = TRUE, - rrep_thresh = 0.85, description = NA_character_, verbose = TRUE, - threads = 1L, seed = NA_integer_, reckless = FALSE, dbg = "0") +call_DTU( + annot = NULL, + TARGET_COL = "target_id", + PARENT_COL = "parent_id", + count_data_A = NULL, + count_data_B = NULL, + boot_data_A = NULL, + boot_data_B = NULL, + name_A = "Condition-A", + name_B = "Condition-B", + varname = "condition", + use_sums = FALSE, + p_thresh = 0.05, + abund_thresh = 5, + dprop_thresh = 0.2, + correction = "BH", + scaling = 1, + testmode = "both", + lean = TRUE, + qboot = TRUE, + qbootnum = 0L, + qrep_thresh = 0.95, + rboot = TRUE, + rrep_thresh = 0.85, + description = NA_character_, + verbose = TRUE, + threads = 1L, + seed = NA_integer_, + reckless = FALSE, + dbg = "0" +) } \arguments{ \item{annot}{A data.table matching transcript identifiers to gene identifiers. Any additional columns are allowed but ignored.} diff --git a/man/denest_sleuth_boots.Rd b/man/denest_sleuth_boots.Rd index 7886099..d5c5e44 100644 --- a/man/denest_sleuth_boots.Rd +++ b/man/denest_sleuth_boots.Rd @@ -4,9 +4,16 @@ \alias{denest_sleuth_boots} \title{Extract bootstrap counts into a less nested structure.} \usage{ -denest_sleuth_boots(slo, annot, samples, COUNTS_COL = "tpm", - BS_TARGET_COL = "target_id", TARGET_COL = "target_id", - PARENT_COL = "parent_id", threads = 1) +denest_sleuth_boots( + slo, + annot, + samples, + COUNTS_COL = "tpm", + BS_TARGET_COL = "target_id", + TARGET_COL = "target_id", + PARENT_COL = "parent_id", + threads = 1 +) } \arguments{ \item{slo}{A sleuth object.} diff --git a/man/do_boot.Rd b/man/do_boot.Rd index b22da6d..fa98b61 100644 --- a/man/do_boot.Rd +++ b/man/do_boot.Rd @@ -4,10 +4,22 @@ \alias{do_boot} \title{Perform the bootstraps.} \usage{ -do_boot(lean, tx_filter, eltr, elge, boot_data_A = NULL, - boot_data_B = NULL, count_data_A = NULL, count_data_B = NULL, - niter = NULL, threads = 1, verbose = TRUE, test_transc = TRUE, - test_genes = TRUE, ...) +do_boot( + lean, + tx_filter, + eltr, + elge, + boot_data_A = NULL, + boot_data_B = NULL, + count_data_A = NULL, + count_data_B = NULL, + niter = NULL, + threads = 1, + verbose = TRUE, + test_transc = TRUE, + test_genes = TRUE, + ... +) } \arguments{ \item{lean}{Minimal insight reported.} diff --git a/man/granges2ids.Rd b/man/granges2ids.Rd index b0ce368..16b7e73 100644 --- a/man/granges2ids.Rd +++ b/man/granges2ids.Rd @@ -4,8 +4,7 @@ \alias{granges2ids} \title{Extract matching transcript and gene IDs from a GRanges object.} \usage{ -granges2ids(annot, transc_header = "target_id", - gene_header = "parent_id") +granges2ids(annot, transc_header = "target_id", gene_header = "parent_id") } \arguments{ \item{annot}{A GRanges object with gene_id and transcript_id metadata columns.} diff --git a/man/gtf2ids.Rd b/man/gtf2ids.Rd index 425c550..bda8cdb 100644 --- a/man/gtf2ids.Rd +++ b/man/gtf2ids.Rd @@ -4,8 +4,7 @@ \alias{gtf2ids} \title{Extract matching transcript and gene IDs from a GTF file.} \usage{ -gtf2ids(annotfile, transc_header = "target_id", - gene_header = "parent_id") +gtf2ids(annotfile, transc_header = "target_id", gene_header = "parent_id") } \arguments{ \item{annotfile}{A GTF file.} diff --git a/man/parameters_are_good.Rd b/man/parameters_are_good.Rd index 105a4e2..f8c9cb7 100644 --- a/man/parameters_are_good.Rd +++ b/man/parameters_are_good.Rd @@ -4,10 +4,32 @@ \alias{parameters_are_good} \title{Check input parameters.} \usage{ -parameters_are_good(annot, count_data_A, count_data_B, boot_data_A, - boot_data_B, TARGET_COL, PARENT_COL, correction, testmode, scaling, - threads, seed, p_thresh, abund_thresh, dprop_thresh, qboot, qbootnum, - qrep_thresh, rboot, rrep_thresh, reckless, lean, verbose, use_sums) +parameters_are_good( + annot, + count_data_A, + count_data_B, + boot_data_A, + boot_data_B, + TARGET_COL, + PARENT_COL, + correction, + testmode, + scaling, + threads, + seed, + p_thresh, + abund_thresh, + dprop_thresh, + qboot, + qbootnum, + qrep_thresh, + rboot, + rrep_thresh, + reckless, + lean, + verbose, + use_sums +) } \arguments{ \item{annot}{Annotation dataframe.} diff --git a/man/plot_gene.Rd b/man/plot_gene.Rd index c7b1afa..f561a2c 100644 --- a/man/plot_gene.Rd +++ b/man/plot_gene.Rd @@ -4,13 +4,19 @@ \alias{plot_gene} \title{Plot abundances for all isoforms of a specified gene.} \usage{ -plot_gene(dtuo, pid, style = "bycondition", fillby = NA_character_, - colourby = NA_character_, shapeby = NA_character_, - isofcolvec = c("tomato", "lightblue", "forestgreen", "purple", - "hotpink", "gold3"), dtucolvec = c(`TRUE` = "firebrick1", `FALSE` = - "dodgerblue", `NA` = "gold"), condcolvec = c("grey15", "steelblue"), +plot_gene( + dtuo, + pid, + style = "bycondition", + fillby = NA_character_, + colourby = NA_character_, + shapeby = NA_character_, + isofcolvec = c("tomato", "lightblue", "forestgreen", "purple", "hotpink", "gold3"), + dtucolvec = c(`TRUE` = "firebrick1", `FALSE` = "dodgerblue", `NA` = "gold"), + condcolvec = c("grey15", "steelblue"), replcolvec = c("red", "blue", "green", "violet", "pink", "orange"), - nonecol = "grey50") + nonecol = "grey50" +) } \arguments{ \item{dtuo}{A DTU object.} diff --git a/man/scale_data.Rd b/man/scale_data.Rd index bb671a8..58c7628 100644 --- a/man/scale_data.Rd +++ b/man/scale_data.Rd @@ -4,8 +4,15 @@ \alias{scale_data} \title{Apply scaling.} \usage{ -scale_data(scaling, threads, steps, count_data_A, count_data_B, - boot_data_A, boot_data_B) +scale_data( + scaling, + threads, + steps, + count_data_A, + count_data_B, + boot_data_A, + boot_data_B +) } \arguments{ \item{scaling}{Scaling factor(s).} diff --git a/man/sim_boot_data.Rd b/man/sim_boot_data.Rd index 9691ab6..3039a21 100644 --- a/man/sim_boot_data.Rd +++ b/man/sim_boot_data.Rd @@ -4,8 +4,7 @@ \alias{sim_boot_data} \title{Generate an artificial dataset of bootstrapped abundance estimates, for code-testing or examples.} \usage{ -sim_boot_data(PARENT_COL = "parent_id", TARGET_COL = "target_id", - clean = TRUE) +sim_boot_data(PARENT_COL = "parent_id", TARGET_COL = "target_id", clean = TRUE) } \arguments{ \item{PARENT_COL}{Name for the bootdtraps column containing counts.} diff --git a/man/sim_count_data.Rd b/man/sim_count_data.Rd index 3c32e06..76dfec6 100644 --- a/man/sim_count_data.Rd +++ b/man/sim_count_data.Rd @@ -4,8 +4,11 @@ \alias{sim_count_data} \title{Generate an artificial dataset of abundance estimates, for code-testing or examples.} \usage{ -sim_count_data(PARENT_COL = "parent_id", TARGET_COL = "target_id", - clean = TRUE) +sim_count_data( + PARENT_COL = "parent_id", + TARGET_COL = "target_id", + clean = TRUE +) } \arguments{ \item{PARENT_COL}{Name for the bootdtraps column containing counts.} diff --git a/man/structure_data.Rd b/man/structure_data.Rd index bb253cd..33be14a 100644 --- a/man/structure_data.Rd +++ b/man/structure_data.Rd @@ -4,8 +4,15 @@ \alias{structure_data} \title{Structure input data.} \usage{ -structure_data(tx_filter, steps, threads, count_data_A, count_data_B, - boot_data_A, boot_data_B) +structure_data( + tx_filter, + steps, + threads, + count_data_A, + count_data_B, + boot_data_A, + boot_data_B +) } \arguments{ \item{tx_filter}{Pre-processed annotation.} diff --git a/vignettes/input.Rmd b/vignettes/input.Rmd index 54a93be..1b95c87 100644 --- a/vignettes/input.Rmd +++ b/vignettes/input.Rmd @@ -1,9 +1,10 @@ --- title: 'RATs: Input and Settings' author: "Kimon Froussios" -date: "08 JUL 2019" +date: "31 MAR 2022" output: html_document: + keep_md: yes theme: readable toc: yes toc_float: yes @@ -30,13 +31,13 @@ library(rats) RATs can work with several input types: -1. [Salmon](https://github.com/COMBINE-lab/salmon) and [Kallisto](http://pachterlab.github.io/kallisto/) quantifications. +1. [Kallisto](http://pachterlab.github.io/kallisto/) quantifications in plain-text or RHDF5 format. 2. Bootstrapped abundance estimates in lists of R `data.table`s. 3. Abundance estimates in R `data.table`s. -For option 1, the function `fish4rodents()` will load the data into tables suitable for option 2. Details in the respective -section below. For options 2 and 3, the format of the tables is as in the example below. The first column contains the transcript identifiers. -Subsequent columns contain the abundances. +For option 1, the function `fish4rodents()` will load the data into tables suitable for options 2 or 3 accordingly. +Details in the respective section below. For options 2 and 3, the format of the tables is as in the example below. +The first column contains the transcript identifiers and subsequent columns contain the abundances. ```{r, echo=FALSE} # Show the first rows of the table corresponding to one sample, from emulated data. @@ -49,11 +50,10 @@ condition is represented by a list of such tables. ### Read counts, TPMs, etc -To get the best results, we recommend obtaining TPM abundances, so as to account for differing transcript lengths, -and then scaling these values to your actual library sizes to regain count-like magnitudes. - -RATs provides parameters to scale the abundances per sample to meet this requirement. +To get the best results, we recommend obtaining TPM abundances, so as to account for differing transcript lengths, and then scaling these values to your actual library sizes to regain count-like magnitudes. +You can scale all libraries to the depth of your shallowest library for equal weight of all samples, or you can scale each sample to its own library if depths vary greatly and you want the deeper libraries to carry more weight. +RATs provides parameters to scale the length-normalized abundances per sample to meet this requirement. ## Annotation @@ -71,14 +71,15 @@ RATs provides functionality to create this table from a GTF file or a `GRanges` # Extract transcript ID to gene ID index from a GTF annotation. myannot <- gtf2ids("my_annotation_file.gtf") -# Extract transcript ID and gene ID from a GRanges object. It must have GTF-style metadata columns "gene_id" and "transcript_id". +# Extract transcript ID and gene ID from a GRanges object. +# It must have GTF-style metadata columns "gene_id" and "transcript_id". myannot <- granges2ids(mygranges) ``` Extracting the ID pairs from a `TxDb` object is simpler and does not require a dedicated helper function: ```{r eval=FALSE} -myannot <- select(mytxdb, keys(mytxdb), "TXNAME", "GENEID") +myannot <- select(mytxdb, keys(mytxdb), "GENEID", "TXNAME") # Rename the columns to match what RATs expects. names(myannot) <- c('gene_id', 'target_id') ``` @@ -92,7 +93,7 @@ names(myannot) <- c('gene_id', 'target_id') As input data, we will use the data emulators that RATs uses in its code tests. These "data" are extremely limited and completely fictional, but are adequate to demonstrate data format and command syntax. -If RATs issues *warnings* about the emulated dataset being too small, disregard them. +If RATs issues *warnings* about the emulated dataset being too small, disregard them for this tutorial, they are meant for real datasets. ### DTU from abundance estimates, without bootstraps @@ -121,6 +122,7 @@ Now we can call DTU: # Find DTU between the simulated datasets. mydtu <- call_DTU(annot= myannot, count_data_A= mycond_A, count_data_B= mycond_B, verbose= FALSE, + scaling= 1, name_A= "healthy", name_B= "patients", varname= "My phenotype", description="Comparison of two simulated counts datasets @@ -131,7 +133,8 @@ mydtu <- call_DTU(annot= myannot, count_data_A= mycond_A, #### Mandatory arguments: 1. `annot` - An annotation data frame, as described in the Input formats section. -2. `count_data_A` and `count_data_B` - Each is a `data.table` of transcript abundances as described in the Input formats section. +2. `count_data_A` and `count_data_B` - Each is a `data.table` of transcript abundances as described in the Input formats section. They should contain length-normalized values, like TPMs or pseudocounts by up-scaled TPMs. +3. `scaling` - A vector of scaling factors (one per sample), or a single scaling factor to be applied to all samples. This parameter is mandatory if input is TPM, but can be omitted if abundances are pre-scaled. #### Optional arguments (will be recorded in the output object, but have no effect on the run): @@ -168,6 +171,7 @@ Now we can call DTU: # Find DTU between conditions. mydtu <- call_DTU(annot= myannot, boot_data_A= mycond_A, boot_data_B= mycond_B, verbose= FALSE, + scaling= 1, name_A= "wildtype", name_B= "some mutant", varname = "My phenotype", description="Comparison of two simulated datasets of bootstrapped counts for the @@ -178,56 +182,36 @@ mydtu <- call_DTU(annot= myannot, boot_data_A= mycond_A, #### Mandatory arguments: 1. `annot` - An annotation data frame, as described in the *Input formats* section. -2. `boot_data_A` and `boot_data_B` - Each is a list of `data.table` objects, as described in the Input section. +2. `boot_data_A` and `boot_data_B` - Each is a list of `data.table` objects, as described in the Input section. They should contain length-normalized values, like TPMs or pseudocounts by up-scaled TPMs. +3. `scaling` - A vector of scaling factors (one per sample), or a single scaling factor to be applied to all samples. This parameter is mandatory if input is TPM, but can be omitted if abundances are pre-scaled. #### Optional arguments (will be recorded in the output object, but have no effect on the run): -* `name_A`, `name_B` - A name for each conditon. +* `name_A`, `name_B` - A name for each condition. * `varname` - The name of the variable/condition. * `description` - Free-text description. -### DTU with Salmon/Kallisto output +### DTU with Kallisto output -RATs offers a method to import bootstrapped abundances directly from [Salmon](https://combine-lab.github.io/salmon/) -output (requires [wasabi](https://github.com/COMBINE-lab/wasabi)) or [Kallisto](https://pachterlab.github.io/kallisto/) -output. The raw abundances are normalised to TPM (default). +The raw abundances are normalised to TPM (default). Consider instead providing the real depth of your libraries. ```{r, eval=FALSE} # Mock-up code, does not run. # 1. Collect your outputs into vectors. The end of each path should be a -# directory with a unique name/identifier for one sample. +# directory with a unique name/identifier for one sample and containing +# the respective output of Kallisto. samples_A <- c("your/path/SAMPLE1", "your/path/SAMPLE4","your/path/SAMPLE5") -samples_B <- c("your/path/SAMPLE2", "your/path/SAMPLE3","your/path/SAMPLE7", - "your/path/SAMPLE10") +samples_B <- c("your/path/SAMPLE2", "your/path/SAMPLE3","your/path/SAMPLE7", "your/path/SAMPLE10") # 2. Calculate length- & library-normalised abundances. # Scale them to 1M reads for TPM values. mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, - annot= myannot, scaleto=100000000) -``` - -The output is a list, containing two lists of `data.table` objects, as for the bootstrapped input in the previous section: - -```{r, echo=FALSE} -# Since the fish4rodents code is a mock-up, create the input using something that does run: -simdat <- sim_boot_data(clean=TRUE) -mydata=list(boot_data_A=c(simdat[[2]], simdat[[3]]), - boot_data_B=c(simdat[[3]], simdat[[2]])) -myannot <- simdat[[1]] -``` - -```{r} -print(class(mydata)) -print(names(mydata)) -print(c( class(mydata$boot_data_A), class(mydata$boot_data_B) )) -print(class(mydata$boot_data_A[[1]])) -print(class(mydata$boot_data_B[[1]])) + annot= myannot, scaleto=1e6) # scaling to TPM ``` -This helper function works *only* with bootstrapped quantifications. -The abundaces are normalised for isoform length and library-size. +The output is a list, containing either two lists of `data.table` objects of bootstrapped data or just two `data.table`s of non-bootstrapped data, as per the input formats specifications. Then follow the respective example for the data type, as already covered above. #### Mandatory arguments (`fish4rodents`): @@ -237,25 +221,9 @@ last segments of each path should be a directory with a unique identifying name #### Optional arguments (`fish4rodents`): -* `scaleto` - allows you to control the normalisation factor. (Default 1000000 gives TPM values). +* `scaleto` - Library depth to aim for. (Default 1000000 gives TPM values). * `beartext` - directs `fish4rodents()` to read bootstrap data from plain-text files in a `bootstraps` subdirectory in each sample, instead of parsing the abundance.h5 file of the sample. (Default FALSE) -And finally run DTU in the way already shown: - -```{r, eval=FALSE} -# 3. Run RATs with the bootstrapped data format. -# Scale the TPM abundances to the respective library sizes. -mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, - boot_data_B= mydata$boot_data_B, verbose= FALSE, - scaling=c(25, 26, 23, 50, 45, 48, 52)) - -# Remember that TPMs are already scaled to 1M, so scaling to the -# library size of 50M only requires a factor of 50, not 50000000! -``` - -#### Mandatory arguments: - -* `scaling` - A vector of scaling factors, one per sample, that ensures that the abundances are scaled to the library size instead of 1M. *** @@ -324,7 +292,7 @@ mydtu <- call_DTU(annot = myannot, In this process, all the 1 vs. 1 combinations of samples, one from each condition, are used to bootstrap the variation across replicates. -Two parameters control bootstrapping of DTU calls agaisnt the samples: +Two parameters control bootstrapping of DTU calls against the samples: ```{r} # Bootstrap (default). @@ -336,13 +304,14 @@ mydtu <- call_DTU(annot = myannot, 1. `rboot` - Whether to bootstrap the replicates or not. (Default TRUE) 2. `rrep_thresh` - Reproducibility threshold: The minimum fraction of the iterations that have to agree on a result to consider it confident. Ignored if `rboot=FALSE`. To calculate the reproducibility without factoring it in the DTU classification, set the threshold to 0. (Default 0.85) -**Note** that for few replicates per condition, the reproducibility values are highly discrete. For example, the number of iterations for 3 samples per condition is `3 * 3 = 9`. -So the minimum disagreement rate is `1 / 9 = 0.111...`, or conversely a reproducibility of `8 / 9 = 0.888...`, -hence the default threshold value of 0.85. +**Note** that for few replicates per condition, the reproducibility values are highly discrete. +For example, the number of iterations for 2 samples per condition is `2 * 2 = 4`. +So the minimum disagreement rate is `1 / 4 = 0.25`, or conversely a reproducibility of `3/4 = 0.75`. +The default threshold value of 0.85 is based on 3 replicates per condition, meaning 9 iterations and aiming for `8/9=0.889` agreement. ### Extra bootstrapping info -Additional information on the range, variance and centre of the effect size and p-value across bootstrap iterations can be calculated on demand. This requires keeping the full raw results for every iteration in memory and can have a considerable footprint that scales with the number of transcripts and iterations. This is controlled by the `lean` parameter. +Additional information on the range, variance and centre of the effect size and p-value across bootstrap iterations can be calculated on request. This requires keeping the full raw results for every iteration in memory and can have a considerable footprint that scales with the number of transcripts and iterations. This is controlled by the `lean` parameter. ```{r} # Extra info on variance across iterations. @@ -356,13 +325,10 @@ mydtu <- call_DTU(annot = myannot, ## Abundance scaling and normalisation -Unlike Differential Transcript/Gene Expression, where libraries must be normalised for size so that expression values are comparable, abundances for Differential Transcript Usage are normalised to the expression of the respective individual gene. Therefore, RATs does not require the libraries to have the same size, and we recommend leaving libraries at their respective sizes. +Unlike Differential Transcript/Gene Expression, where libraries must be normalised for size so that expression values are comparable, abundances for Differential Transcript Usage are normalised to the expression of the respective individual gene. Therefore, RATs does not require the libraries to have the same size. For flexibility with different types of input, scaling can be applied in either/both of two stages: The data import step by -`fish4rodents()`, or/and the actual testing step by `call_DTU()`. In an example examined previously, `fish4rodents()` was -instructed to create TPM abundances, by normalising to `1000000` reads. Such values are useful with other tools that -a user may also intend to use. Subsequently, these TPMs were re-scaled to reflect the library size of each sample, thus providing -RATs with count-like abundance values that retain the normalisation by isoform length. +`fish4rodents()`, or/and the actual testing step by `call_DTU()`. The import applies length normalization and by default scales to 1 million. Such values are useful to have for use in other analyses. These TPMs can then be re-scaled to length-normalized pseudo-counts that reflect the library sizes. Both `fish4rodents()` and `call_DTU()` support scaling by a single value or a vector of values. @@ -376,13 +342,13 @@ Both `fish4rodents()` and `call_DTU()` support scaling by a single value or a ve # Scale to individual library sizes directly at the import step. mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, annot= myannot, - scaleto=c(25123456, 2665431, 23131313, + scaleto= c(25123456, 2665431, 23131313, 5000000, 45123132, 48456654, 52363636), verbose= FALSE) # No additional scaling needed. mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, boot_data_B= mydata$boot_data_B, - scaling=1, # default + scaling= 1, # default verbose= FALSE) # 2: @@ -393,15 +359,15 @@ mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, # Scale library fractions to the library sizes. mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, boot_data_B= mydata$boot_data_B, - scaling=c(25123456, 2665431, 23131313, 5000000, + scaling= c(25123456, 2665431, 23131313, 5000000, 45123132, 48456654, 52363636), verbose= FALSE) # 3: -# Scale Kallisto/Salmon quantifications to TPMs. +# Scale Kallisto quantifications to TPMs. mydata <- fish4rodents(A_paths= samples_A, B_paths= samples_B, annot= myannot, - scaleto=1000000) # default + scaleto= 1000000) # default # Scale TPMs to individual library sizes. mydtu <- call_DTU(annot= myannot, boot_data_A= mydata$boot_data_A, boot_data_B= mydata$boot_data_B, @@ -439,7 +405,7 @@ Up to and including version `0.6.5`, RATs combined the isoform abundance values The resulting values are thus larger and pass the significance test more easily, increasing sensitivity. But this can also boost false positives. -Starting with version `0.7.0`, the user is given the choice between sums and means. By default RATs now uses the means instead of the sums. +Now, instead, the user is given the choice between sums and means. By default RATs now uses the means instead of the sums. ```{r} mydtu <- call_DTU(annot = myannot, diff --git a/vignettes/output.R b/vignettes/output.R new file mode 100644 index 0000000..a1cfbf8 --- /dev/null +++ b/vignettes/output.R @@ -0,0 +1,68 @@ +## ----setup, include=FALSE----------------------------------------------------- +knitr::opts_chunk$set(echo = TRUE) + +## ----------------------------------------------------------------------------- +library(rats) +library(data.table) + +## ----------------------------------------------------------------------------- +# Simulate some data. +simdat <- sim_boot_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +# Call DTU +mydtu <- call_DTU(annot= myannot, verbose= FALSE, + boot_data_A= mycond_A, boot_data_B= mycond_B, + dprop_thresh=0.1, qboot=TRUE, rboot=FALSE) + +## ----------------------------------------------------------------------------- +print( names(mydtu) ) + +## ----------------------------------------------------------------------------- +# Parameter list's elements. +print( names(mydtu$Parameters) ) + +## ----------------------------------------------------------------------------- +# Genes table's fields. +print( names(mydtu$Genes) ) + +## ----------------------------------------------------------------------------- +# Transcripts table's fields. +print( names(mydtu$Transcripts) ) + +## ----------------------------------------------------------------------------- +# Elements of Abundances. +print( names(mydtu$Abundances) ) + +## ----------------------------------------------------------------------------- +# Abundance table for first condition. +print( head(mydtu$Abundances[[1]]) ) + +## ----------------------------------------------------------------------------- +# A tally of the outcome. +print( dtu_summary(mydtu) ) + +## ----------------------------------------------------------------------------- +# Gene and transcript IDs corresponding to the tally above. +ids <- get_dtu_ids(mydtu) +print( names(ids) ) +print( ids ) + +## ----------------------------------------------------------------------------- +# A tally of genes switching isoform ranks. +print( dtu_switch_summary(mydtu) ) + +# The gene IDs displaying isoform switching. +ids <- get_switch_ids(mydtu) +print( names(ids) ) + +## ----------------------------------------------------------------------------- +# A tally of genes switching isoform ranks. +print( dtu_plurality_summary(mydtu) ) + +# The gene IDs displaying isoform switching. +ids <- get_plurality_ids(mydtu) + diff --git a/vignettes/output.Rmd b/vignettes/output.Rmd index 9738a26..6224e84 100644 --- a/vignettes/output.Rmd +++ b/vignettes/output.Rmd @@ -234,7 +234,7 @@ print( dtu_summary(mydtu) ) ``` The `get_dtu_ids()` function lists the coresponding identifiers per category. -The ID lists obtained ordered by effect size (`Dprop`). +The ID lists obtained are ordered by effect size (`Dprop`). ```{r} # Gene and transcript IDs corresponding to the tally above. diff --git a/vignettes/output.html b/vignettes/output.html new file mode 100644 index 0000000..2f7f1e7 --- /dev/null +++ b/vignettes/output.html @@ -0,0 +1,624 @@ + + + + + + + + + + + + + + + +RATs: Raw Output + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ + + + + + + +
+
library(rats)
+library(data.table)
+

Let’s set up an example, using RAT’s data emulator (used for code testing, not suitable for data simulations).

+
# Simulate some data.
+simdat <- sim_boot_data(clean=TRUE) 
+# For convenience let's assign the contents of the list to separate variables
+mycond_A <- simdat[[2]]   # Simulated bootstrapped data for one condition.
+mycond_B <- simdat[[3]]   # Simulated bootstrapped data for other condition.
+myannot <- simdat[[1]]    # Transcript and gene IDs for the above data.
+
+# Call DTU
+mydtu <- call_DTU(annot= myannot, verbose= FALSE,
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  dprop_thresh=0.1, qboot=TRUE, rboot=FALSE)
+
+
+

Output structure

+

The output of RATs is a list containing 4 elements:

+
print( names(mydtu) )
+
## [1] "Parameters"  "Genes"       "Transcripts" "Abundances"
+
+

Parameters

+

Parameters is a list that contains information about the data and the settings for a particular run.

+
# Parameter list's elements.
+print( names(mydtu$Parameters) )
+
##  [1] "description"         "time"                "rats_version"       
+##  [4] "R_version"           "var_name"            "cond_A"             
+##  [7] "cond_B"              "data_type"           "num_replic_A"       
+## [10] "num_replic_B"        "num_genes"           "num_transc"         
+## [13] "tests"               "use_sums"            "correction"         
+## [16] "p_thresh"            "abund_thresh"        "dprop_thresh"       
+## [19] "abund_scaling"       "quant_boot"          "quant_reprod_thresh"
+## [22] "quant_bootnum"       "rep_boot"            "rep_reprod_thresh"  
+## [25] "rep_bootnum"         "seed"                "reckless"           
+## [28] "lean"
+
    +
  • description - (str) Free-text description of the run. It is useful to record data sources, annotation source and version, experimental parameters, etc…
  • +
  • time - (str) Date and time for the run. This does not represent the exact time the run started.
  • +
  • rats_version - (str) The version of RATs.
  • +
  • R_version - (str) The version of R (including OS architecture).
  • +
  • var_name - (str) The value passed to the varname parameter.
  • +
  • cond_A & cond_B - (str) The values passed to the name_A and name_B parameters.
  • +
  • data_type - (str) The format of the input data.
  • +
  • num_replic_A & num_replic_B - (int) The number of samples in each condition.
  • +
  • num_genes - (int) The number of genes in the provided annotation.
  • +
  • num_transc - (int) The number of transcripts in the provided annotation.
  • +
  • tests - (str) The value passed to the testmode parameter.
  • +
  • use_sums - (bool) Sum the replicates instead of averaging them (pre-0.7.0 RATs always summed).
  • +
  • p_thresh - (num) The value passed to the p_thresh parameter.
  • +
  • abund_thresh - (num) The value passed to the abund_thresh parameter.
  • +
  • dprop_thresh - (num) The value passed to the dprop_thresh parameter.
  • +
  • correction - (str) Multiple testing correction method.
  • +
  • abund_scaling - (num) The value(s) passed to the scaling parameter. It will be either a single numeric value or a named vector of values.
  • +
  • quant_boot - (bool) The value passed to the qboots parameter.
  • +
  • quant_reprod_thresh - (num) The value passed to the qrep_thresh parameter, if qboot==TRUE.
  • +
  • quant_bootnum - (int) The value passed to the qbootnum parameter, if qboot==TRUE.
  • +
  • rep_boot - (bool) The value passed to the rboot parameter.
  • +
  • rep_reprod_thresh - (num) The value passed to the rrep_thresh parameter, if rboot==TRUE.
  • +
  • rep_bootnum - (int) The number of replicate bootstrapping iterations (currently M*N, where M and N are the numbers of samples in the two conditions), if rboot==TRUE.
  • +
  • seed - (int) Custom seed for the random generator. NA if none was specified.
  • +
  • reckless - (bool) The value passed to the reckless parameter.
  • +
  • lean - (bool) The value passed to the lean parameter.
  • +
+

Note: If bootstraps are disabled, the bootstrap-related fields may be NA, regardless of supplied values, to reflect the fact that they were not used.

+
+
+

Genes

+

Genes is a data.table listing results at the gene level. For your convenience, the respective aggregated transcript-level DTU calls are also included here (defined as at least one isoform being called DTU individually).

+
# Genes table's fields.
+print( names(mydtu$Genes) )
+
##  [1] "parent_id"      "elig"           "sig"            "elig_fx"       
+##  [5] "quant_reprod"   "DTU"            "transc_DTU"     "known_transc"  
+##  [9] "detect_transc"  "elig_transc"    "maxDprop"       "pval"          
+## [13] "pval_corr"      "quant_na_freq"  "quant_dtu_freq"
+

The first few columns show the result of each decision step in a boolean manner, allowing easy filtering of the table. The remaining columns list the values based on which these decisions were made. Pseudo-code formulas are shown here to help understand how the different fields interact when making decisions.

+
    +
  • parent_id - (str) Gene identifier.
  • +
  • elig - (bool) Eligible for testing. Whether the gene met the pre-filtering criteria. = (elig_transc >= 2).
  • +
  • sig - (bool) Statistically significant. = (pval_corr < Parameters$p_thresh).
  • +
  • elig_fx - (bool) Eligible effect size. Whether at least one of the isoforms meets the effect size criterion. = any(Transcript[parent_id, elig_fx]).
  • +
  • quant_reprod - (bool) Result reproducible across quantification iterations. For positive DTU, = (quant_dtu_freq >= Parameters$quant_reprod_thresh), for non-DTU = (quant_dtu_freq <= 1 - Parameters$quant_reprod_thresh).
  • +
  • rep_reprod - (bool) Result reproducible across replicates. For positive DTU, = (rep_dtu_freq >= Parameters$rep_reprod_thresh), for non-DTU = (rep_dtu_freq <= 1 - Parameters$rep_reprod_thresh).
  • +
  • DTU - (bool) Gene-level Differential Transcript Usage. = (sig & elig_fx & quant_reprod & rep_reprod).
  • +
  • transc_DTU - (bool) Aggregated from Transcripts$DTU: At least one isoform was individually reported as DTU. = (Transcript[ , any(DTU), by=parent_id]).
  • +
  • known_transc - (int) Number of known trascripts for this gene according to the given annotation.
  • +
  • detect_trancs - (int) Number of detected (expressed) transcripts in the given dataset.
  • +
  • elig_transc - (int) Number of eligible transcripts, aggregated from Transcripts$elig.
  • +
  • pval - (num) G test of independence p-value for the isoform ratios of the gene.
  • +
  • pval_corr - (num) Multiple testing corrected p-value. pval_corr= p.adjust(pval, Parameters$correction).
  • +
  • quant_p_median - (num) Median of corrected p-values across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_min - (num) Minimum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_max - (num) Maximum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_na_freq - (num) Fraction of quantification iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • quant_dtu_freq - (num) Fraction of replicate iterations that support a positive DTU classification.
  • +
  • rep_p_median - (num) Median p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_min - (num) Minimum observed p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_max - (num) Maximum observed p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_na_freq - (num) Fraction of replication iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • rep_dtu_freq - (num) Fraction of replication iterations that support a positive DTU classification.
  • +
+

Note: The fields reporting on the bootstraps will not be shown when bootstrapping is disabled.

+
+
+

Transcripts

+

Transcripts is a data.table listing results at the transcript level. For your convenience, the respective gene-level DTU calls are also included here.

+
# Transcripts table's fields.
+print( names(mydtu$Transcripts) )
+
##  [1] "target_id"      "parent_id"      "elig_xp"        "elig"          
+##  [5] "sig"            "elig_fx"        "quant_reprod"   "DTU"           
+##  [9] "gene_DTU"       "abundA"         "abundB"         "stdevA"        
+## [13] "stdevB"         "log2FC"         "totalA"         "totalB"        
+## [17] "propA"          "propB"          "Dprop"          "pval"          
+## [21] "pval_corr"      "quant_na_freq"  "quant_dtu_freq"
+

The first few columns show the result of each decision step in a boolean manner, allowing easy filtering of the table. The remaining columns list the values based on which these decisions were made. Pseudo-code formulas are shown here to help understand how the different fields interact when making decisions.

+
    +
  • target_id - (str) Transcript identifier.
  • +
  • parent_id - (str) Gene identifier.
  • +
  • elig_xp - (bool) Eligible expression level. = (meanA >= Parameters$abund_thresh | meanB >= Parameters$abund_thresh).
  • +
  • elig - (bool) Eligible for testing (meets the noise threshold and at least one other isoform is expressed). = (elig_xp & totalA != 0 & totalB != 0 & (abundA != totalA | abundB != totalB)).
  • +
  • sig - (bool) Statistically significant. = (pval_corr < Parameters$p_thresh).
  • +
  • elig_fx - (bool) Eligible effect size. Proxy for biological significance. = (Dprop > Parameters$dprop_thresh). *. quant_reprod - (bool) Quantification reproducible. For positive DTU, = (quant_dtu_freq >= Parameters$quant_reprod_thresh), for non-DTU = (quant_dtu_freq <= 1 - Parameters$quant_reprod_thresh).
  • +
  • rep_reprod - (bool) Replication reproducible. For positive DTU, = (rep_dtu_freq >= Parameters$rep_reprod_thresh), for non-DTU = (rep_dtu_freq <= 1 - Parameters$rep_reprod_thresh).
  • +
  • DTU - (bool) The Transcript is Differentially Used. = (sig & elig_fx & quant_reprod & rep_reprod).
  • +
  • gene_DTU - (bool) Expanded from Genes$DTU. Indicates that the gene as a whole shows significant change in isoform ratios. = (Genes[parent_id, DTU]).
  • +
  • abundA and abundB - (num) Either the mean or the sum of the abundances across replicates, depending on what is indicated by Parameters$use_sums. This is the value used for the tests.
  • +
  • stdevA and stdevB - (num) The standard deviation of the abundance across the replicates.
  • +
  • log2FC - (num) log2 of fold-change of transcript abundance: = log2(abundB / abundA). abundA and abundB are not internally normalised for library size, so care must be taken when interpreting log2FC.
  • +
  • totalA and totalB - (num) The total abundance for the gene: totalA= sum(transcripts[parent_id, abundA]).
  • +
  • propA and propB - (num) The proportion of the gene expression owed to this transcript. propA= abundA / totalA.
  • +
  • Dprop - (num) The difference in the proportion of the transcript between the two conditions (effect size). = (probB - propA).
  • +
  • pval - (num) The proportion equality test P-value for the transcript.
  • +
  • pval_corr - (num) Multiple testing corrected p-value. = p.adjust(pval, Parameters$correction).
  • +
  • quant_p_median - (num) Median of corrected p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_min - (num) Minimum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_p_max - (num) Maximum observed (corrected) p-value across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_mean - (num) Mean effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_stdev - (num) Standard deviation of effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_min - (num) Minimum observed effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_Dprop_max - (num) Maximum observed effect size across quantification bootstraps (not available in lean mode).
  • +
  • quant_na_freq - (num) Fraction of quantification iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • quant_dtu_freq - (num) Fraction of quantification iterations that support a positive DTU classification.
  • +
  • rep_p_median - (num) Median of corrected p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_min - (num) Minimum observed (corrected) p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_p_max - (num) Maximum observed (corrected) p-value across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_mean - (num) Mean effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_stdev - (num) Standard deviation of effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_min - (num) Minimum observed effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_Dprop_max - (num) Maximum observed effect size across replication bootstraps (not available in lean mode).
  • +
  • rep_na_freq - (num) Fraction of replication iterations in which DTU could not be determined (not meeting pre-filtering criteria).
  • +
  • rep_dtu_freq - (num) Fraction of replication iterations that support a positive DTU classification.
  • +
+

Note: The fields reporting on the bootstraps will not be shown when bootstrapping is disabled.

+
+
+

Abundances

+

Abundances is a list of two data.tables, one for each condition. Each transcript is represented by a single abundance value per replicate, so if bootstrapped data was used, these values are the means across iterations. If plain abundances were provided as input, then Abundances essentially contains the input data. These abundances are included in the output because they are required for some of RATs’ plotting options.

+
# Elements of Abundances.
+print( names(mydtu$Abundances) )
+
## [1] "condA" "condB"
+
    +
  1. condA - (num) The transcript abundances in the first condition.
  2. +
  3. condB - (num) The transcript abundances in the second condition.
  4. +
+
# Abundance table for first condition.
+print( head(mydtu$Abundances[[1]]) )
+
##     V1  V2 target_id parent_id
+## 1: 100 115    ALLA:1      ALLA
+## 2:  40  30    ALLA:2      ALLA
+## 3: 300 400    D2TE_a      D2TE
+## 4: 400 500    D2TE_b      D2TE
+## 5: 250 270     1D2TU      D2TU
+## 6: 250 300     2D2TU      D2TU
+
+
+
+
+

Quick results

+

For your convenience, RATs provides a few functions to give you a quick summary of the run. They all follow the same style.

+

These reports should not be seen as a substitute for the detailed RATs output.

+
+

Summary of DTU

+

The dtu_summary() function lists the total number of genes and transcripts for each of 3 categories:

+
    +
  • DTU: There is significant change in isoform ratios (in terms of both effect size and statistical significance).
  • +
  • non-DTU: No significant change.
  • +
  • ineligible: Ineligible for testing. Genes/transcripts with read count below the set threshold, or where the gene has only one known transcript.
  • +
+
# A tally of the outcome.
+print( dtu_summary(mydtu) )
+
##                           category tally
+## 1            DTU genes (gene test)     6
+## 2        non-DTU genes (gene test)     3
+## 3     ineligible genes (gene test)     3
+## 4         DTU genes (transc. test)     6
+## 5     non-DTU genes (transc. test)     3
+## 6  ineligible genes (transc. test)     3
+## 7           DTU genes (both tests)     6
+## 8       non-DTU genes (both tests)     3
+## 9    ineligible genes (both tests)     3
+## 10                 DTU transcripts    14
+## 11             non-DTU transcripts     7
+## 12          ineligible transcripts     5
+

The get_dtu_ids() function lists the coresponding identifiers per category. The ID lists obtained are ordered by effect size (Dprop).

+
# Gene and transcript IDs corresponding to the tally above.
+ids <- get_dtu_ids(mydtu)
+print( names(ids) )
+
##  [1] "DTU genes (gene test)"           "non-DTU genes (gene test)"      
+##  [3] "ineligible genes (gene test)"    "DTU genes (transc. test)"       
+##  [5] "non-DTU genes (transc. test)"    "ineligible genes (transc. test)"
+##  [7] "DTU genes (both tests)"          "non-DTU genes (both tests)"     
+##  [9] "ineligible genes (both tests)"   "DTU transcripts"                
+## [11] "non-DTU transcripts"             "ineligible transcripts"
+
print( ids )
+
## $`DTU genes (gene test)`
+## [1] "XSW"  "MIX"  "SW"   "LC"   "ALLA" "D2TU"
+## 
+## $`non-DTU genes (gene test)`
+## [1] "D2TE" "SAME" "FAKE"
+## 
+## $`ineligible genes (gene test)`
+## [1] "LONE" "SOLO" "NN"  
+## 
+## $`DTU genes (transc. test)`
+## [1] "XSW"  "MIX"  "SW"   "LC"   "ALLA" "D2TU"
+## 
+## $`non-DTU genes (transc. test)`
+## [1] "D2TE" "SAME" "FAKE"
+## 
+## $`ineligible genes (transc. test)`
+## [1] "LONE" "SOLO" "NN"  
+## 
+## $`DTU genes (both tests)`
+## [1] "XSW"  "MIX"  "SW"   "LC"   "ALLA" "D2TU"
+## 
+## $`non-DTU genes (both tests)`
+## [1] "D2TE" "SAME" "FAKE"
+## 
+## $`ineligible genes (both tests)`
+## [1] "LONE" "SOLO" "NN"  
+## 
+## $`DTU transcripts`
+##  [1] "XSW:one" "XSW:two" "MIX.b"   "SW1"     "SW2"     "MIX.a"   "LC1"    
+##  [8] "LC2"     "ALLA:1"  "ALLA:2"  "MIX.ab"  "2D2TU"   "1D2TU"   "MIX.l2" 
+## 
+## $`non-DTU transcripts`
+## [1] "D2TE_b" "D2TE_a" "SAME_1" "SAME_2" "FAKE-2" "FAKE-1" "MIX.l1"
+## 
+## $`ineligible transcripts`
+## [1] "LONE.a" "MIX.n"  "SOLO.1" "NNa"    "NNb"
+
+
+

Summary of isoform switching

+

Isoform switching is a subset of DTU. Primary isoform switching is often considered the most likely type of DTU to have an effect. The following two functions summarise the extent of isoform switching in the results:

+
# A tally of genes switching isoform ranks.
+print( dtu_switch_summary(mydtu) )
+
##                            category genes
+## 1        Primary switch (gene test)     4
+## 2    Non-primary switch (gene test)     1
+## 3     Primary switch (transc. test)     4
+## 4 Non-primary switch (transc. test)     1
+## 5       Primary switch (both tests)     4
+## 6   Non-primary switch (both tests)     1
+
# The gene IDs displaying isoform switching.
+ids <- get_switch_ids(mydtu)
+print( names(ids) )
+
## [1] "Primary switch (gene test)"        "Non-primary switch (gene test)"   
+## [3] "Primary switch (transc. test)"     "Non-primary switch (transc. test)"
+## [5] "Primary switch (both tests)"       "Non-primary switch (both tests)"
+
+
+

Summary of DTU plurality

+

In case you want to know how many isoforms are affected per gene.

+
# A tally of genes switching isoform ranks.
+print( dtu_plurality_summary(mydtu) )
+
##   isof_affected num_of_genes
+## 1             2            5
+## 2             4            1
+
# The gene IDs displaying isoform switching.
+ids <- get_plurality_ids(mydtu)
+

These give you the number and IDs of genes in which 2, 3, etc… isoforms show DTU.

+
+
+
+
+

Contact information

+

The rats R package was developed within The Barton Group at The University of Dundee by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch.

+

To report problems or ask for assistance, please raise a new issue on the project’s support forum. Providing a reproducible working example that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure to read the vignette(s), and browse/search the support forum before posting a new issue, in case your question is already answered there.

+

Enjoy!

+

+
+ + + +
+
+ +
+ + + + + + + + + + + + + + + + diff --git a/vignettes/output.md b/vignettes/output.md new file mode 100644 index 0000000..214eb36 --- /dev/null +++ b/vignettes/output.md @@ -0,0 +1,441 @@ +--- +title: 'RATs: Raw Output' +author: "Kimon Froussios" +date: "08 JUL 2019" +output: + html_document: + keep_md: yes + theme: readable + toc: yes + toc_float: yes +vignette: > + \usepackage[utf8]{inputenc} + %\VignetteIndexEntry{RATs 2: Raw Output} + %\VignetteEngine{knitr::rmarkdown} +--- + + + +*** + + +```r +library(rats) +library(data.table) +``` + + +Let's set up an example, using RAT's data emulator (used for code testing, not suitable for data simulations). + + +```r +# Simulate some data. +simdat <- sim_boot_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +# Call DTU +mydtu <- call_DTU(annot= myannot, verbose= FALSE, + boot_data_A= mycond_A, boot_data_B= mycond_B, + dprop_thresh=0.1, qboot=TRUE, rboot=FALSE) +``` + + +*** + + +# Output structure + +The output of RATs is a list containing 4 elements: + + +```r +print( names(mydtu) ) +``` + +``` +## [1] "Parameters" "Genes" "Transcripts" "Abundances" +``` + + +## Parameters + +`Parameters` is a list that contains information about the data and the settings for a particular run. + + +```r +# Parameter list's elements. +print( names(mydtu$Parameters) ) +``` + +``` +## [1] "description" "time" "rats_version" +## [4] "R_version" "var_name" "cond_A" +## [7] "cond_B" "data_type" "num_replic_A" +## [10] "num_replic_B" "num_genes" "num_transc" +## [13] "tests" "use_sums" "correction" +## [16] "p_thresh" "abund_thresh" "dprop_thresh" +## [19] "abund_scaling" "quant_boot" "quant_reprod_thresh" +## [22] "quant_bootnum" "rep_boot" "rep_reprod_thresh" +## [25] "rep_bootnum" "seed" "reckless" +## [28] "lean" +``` + +* `description` - (str) Free-text description of the run. It is useful to record data sources, annotation source and version, experimental parameters, etc... +* `time` - (str) Date and time for the run. This does not represent the exact time the run started. +* `rats_version` - (str) The version of RATs. +* `R_version` - (str) The version of R (including OS architecture). +* `var_name` - (str) The value passed to the `varname` parameter. +* `cond_A` & `cond_B` - (str) The values passed to the `name_A` and `name_B` parameters. +* `data_type` - (str) The format of the input data. +* `num_replic_A` & `num_replic_B` - (int) The number of samples in each condition. +* `num_genes` - (int) The number of genes in the provided annotation. +* `num_transc` - (int) The number of transcripts in the provided annotation. +* `tests` - (str) The value passed to the `testmode` parameter. +* `use_sums` - (bool) Sum the replicates instead of averaging them (pre-0.7.0 RATs always summed). +* `p_thresh` - (num) The value passed to the `p_thresh` parameter. +* `abund_thresh` - (num) The value passed to the `abund_thresh` parameter. +* `dprop_thresh` - (num) The value passed to the `dprop_thresh` parameter. +* `correction` - (str) Multiple testing correction method. +* `abund_scaling` - (num) The value(s) passed to the `scaling` parameter. It will be either a single numeric value or a named vector of values. +* `quant_boot` - (bool) The value passed to the `qboots` parameter. +* `quant_reprod_thresh` - (num) The value passed to the `qrep_thresh` parameter, if `qboot==TRUE`. +* `quant_bootnum` - (int) The value passed to the `qbootnum` parameter, if `qboot==TRUE`. +* `rep_boot` - (bool) The value passed to the `rboot` parameter. +* `rep_reprod_thresh` - (num) The value passed to the `rrep_thresh` parameter, if `rboot==TRUE`. +* `rep_bootnum` - (int) The number of replicate bootstrapping iterations (currently M*N, where M and N are the numbers of samples in the two conditions), if `rboot==TRUE`. +* `seed` - (int) Custom seed for the random generator. `NA` if none was specified. +* `reckless` - (bool) The value passed to the `reckless` parameter. +* `lean` - (bool) The value passed to the `lean` parameter. + +**Note:** If bootstraps are disabled, the bootstrap-related fields may be `NA`, regardless of supplied values, to reflect the fact that they were not used. + + +## Genes + +`Genes` is a [data.table](https://cran.r-project.org/web/packages/data.table/) listing +results at the gene level. For your convenience, the respective aggregated transcript-level DTU calls are +also included here (defined as at least one isoform being called DTU individually). + + +```r +# Genes table's fields. +print( names(mydtu$Genes) ) +``` + +``` +## [1] "parent_id" "elig" "sig" "elig_fx" +## [5] "quant_reprod" "DTU" "transc_DTU" "known_transc" +## [9] "detect_transc" "elig_transc" "maxDprop" "pval" +## [13] "pval_corr" "quant_na_freq" "quant_dtu_freq" +``` + +The first few columns show the result of each decision step in a boolean manner, allowing easy filtering of the table. +The remaining columns list the values based on which these decisions were made. +Pseudo-code formulas are shown here to help understand how the different fields interact when making decisions. + +* `parent_id` - (str) Gene identifier. +* `elig` - (bool) Eligible for testing. Whether the gene met the pre-filtering criteria. `= (elig_transc >= 2)`. +* `sig` - (bool) Statistically significant. `= (pval_corr < Parameters$p_thresh)`. +* `elig_fx` - (bool) Eligible effect size. Whether at least one of the isoforms meets the effect size criterion. `= any(Transcript[parent_id, elig_fx])`. +* `quant_reprod` - (bool) Result reproducible across quantification iterations. +For positive DTU, `= (quant_dtu_freq >= Parameters$quant_reprod_thresh)`, for non-DTU `= (quant_dtu_freq <= 1 - Parameters$quant_reprod_thresh)`. +* `rep_reprod` - (bool) Result reproducible across replicates. +For positive DTU, `= (rep_dtu_freq >= Parameters$rep_reprod_thresh)`, for non-DTU `= (rep_dtu_freq <= 1 - Parameters$rep_reprod_thresh)`. +* `DTU` - (bool) Gene-level Differential Transcript Usage. `= (sig & elig_fx & quant_reprod & rep_reprod)`. +* `transc_DTU` - (bool) Aggregated from `Transcripts$DTU`: At least one isoform was individually reported as DTU. `= (Transcript[ , any(DTU), by=parent_id])`. +* `known_transc` - (int) Number of known trascripts for this gene according to the given annotation. +* `detect_trancs` - (int) Number of detected (expressed) transcripts in the given dataset. +* `elig_transc` - (int) Number of eligible transcripts, aggregated from `Transcripts$elig`. +* `pval` - (num) G test of independence p-value for the isoform ratios of the gene. +* `pval_corr` - (num) Multiple testing corrected p-value. `pval_corr= p.adjust(pval, Parameters$correction)`. +* `quant_p_median` - (num) Median of corrected p-values across quantification bootstraps (not available in `lean` mode). +* `quant_p_min` - (num) Minimum observed (corrected) p-value across quantification bootstraps (not available in `lean` mode). +* `quant_p_max` - (num) Maximum observed (corrected) p-value across quantification bootstraps (not available in `lean` mode). +* `quant_na_freq` - (num) Fraction of quantification iterations in which `DTU` could not be determined (not meeting pre-filtering criteria). +* `quant_dtu_freq` - (num) Fraction of replicate iterations that support a positive `DTU` classification. +* `rep_p_median` - (num) Median p-value across replication bootstraps (not available in `lean` mode). +* `rep_p_min` - (num) Minimum observed p-value across replication bootstraps (not available in `lean` mode). +* `rep_p_max` - (num) Maximum observed p-value across replication bootstraps (not available in `lean` mode). +* `rep_na_freq` - (num) Fraction of replication iterations in which `DTU` could not be determined (not meeting pre-filtering criteria). +* `rep_dtu_freq` - (num) Fraction of replication iterations that support a positive `DTU` classification. + +**Note:** The fields reporting on the bootstraps will not be shown when bootstrapping is disabled. + + +## Transcripts + +`Transcripts` is a [data.table](https://cran.r-project.org/web/packages/data.table/) listing +results at the transcript level. For your convenience, the respective gene-level DTU calls are also included here. + + +```r +# Transcripts table's fields. +print( names(mydtu$Transcripts) ) +``` + +``` +## [1] "target_id" "parent_id" "elig_xp" "elig" +## [5] "sig" "elig_fx" "quant_reprod" "DTU" +## [9] "gene_DTU" "abundA" "abundB" "stdevA" +## [13] "stdevB" "log2FC" "totalA" "totalB" +## [17] "propA" "propB" "Dprop" "pval" +## [21] "pval_corr" "quant_na_freq" "quant_dtu_freq" +``` + +The first few columns show the result of each decision step in a boolean manner, allowing easy filtering of the table. +The remaining columns list the values based on which these decisions were made. +Pseudo-code formulas are shown here to help understand how the different fields interact when making decisions. + +* `target_id` - (str) Transcript identifier. +* `parent_id` - (str) Gene identifier. +* `elig_xp` - (bool) Eligible expression level. `= (meanA >= Parameters$abund_thresh | meanB >= Parameters$abund_thresh)`. +* `elig` - (bool) Eligible for testing (meets the noise threshold and at least one other isoform is expressed). `= (elig_xp & totalA != 0 & totalB != 0 & (abundA != totalA | abundB != totalB))`. +* `sig` - (bool) Statistically significant. `= (pval_corr < Parameters$p_thresh)`. +* `elig_fx` - (bool) Eligible effect size. Proxy for biological significance. `= (Dprop > Parameters$dprop_thresh)`. +*. `quant_reprod` - (bool) Quantification reproducible. +For positive DTU, `= (quant_dtu_freq >= Parameters$quant_reprod_thresh)`, for non-DTU `= (quant_dtu_freq <= 1 - Parameters$quant_reprod_thresh)`. +* `rep_reprod` - (bool) Replication reproducible. +For positive DTU, `= (rep_dtu_freq >= Parameters$rep_reprod_thresh)`, for non-DTU `= (rep_dtu_freq <= 1 - Parameters$rep_reprod_thresh)`. +* `DTU` - (bool) The Transcript is Differentially Used. `= (sig & elig_fx & quant_reprod & rep_reprod)`. +* `gene_DTU` - (bool) Expanded from `Genes$DTU`. Indicates that the gene as a whole shows significant change in isoform ratios. `= (Genes[parent_id, DTU])`. +* `abundA` and `abundB` - (num) Either the mean or the sum of the abundances across replicates, depending on what is indicated by `Parameters$use_sums`. This is the value used for the tests. +* `stdevA` and `stdevB` - (num) The standard deviation of the abundance across the replicates. +* `log2FC` - (num) log2 of fold-change of transcript abundance: `= log2(abundB / abundA)`. `abundA` and `abundB` are not internally normalised for library size, so care must be taken when interpreting `log2FC`. +* `totalA` and `totalB` - (num) The total abundance for the gene: `totalA= sum(transcripts[parent_id, abundA])`. +* `propA` and `propB` - (num) The proportion of the gene expression owed to this transcript. `propA= abundA / totalA`. +* `Dprop` - (num) The difference in the proportion of the transcript between the two conditions (effect size). `= (probB - propA)`. +* `pval` - (num) The proportion equality test P-value for the transcript. +* `pval_corr` - (num) Multiple testing corrected p-value. `= p.adjust(pval, Parameters$correction)`. +* `quant_p_median` - (num) Median of corrected p-value across quantification bootstraps (not available in `lean` mode). +* `quant_p_min` - (num) Minimum observed (corrected) p-value across quantification bootstraps (not available in `lean` mode). +* `quant_p_max` - (num) Maximum observed (corrected) p-value across quantification bootstraps (not available in `lean` mode). +* `quant_Dprop_mean` - (num) Mean effect size across quantification bootstraps (not available in `lean` mode). +* `quant_Dprop_stdev` - (num) Standard deviation of effect size across quantification bootstraps (not available in `lean` mode). +* `quant_Dprop_min` - (num) Minimum observed effect size across quantification bootstraps (not available in `lean` mode). +* `quant_Dprop_max` - (num) Maximum observed effect size across quantification bootstraps (not available in `lean` mode). +* `quant_na_freq` - (num) Fraction of quantification iterations in which `DTU` could not be determined (not meeting pre-filtering criteria). +* `quant_dtu_freq` - (num) Fraction of quantification iterations that support a positive `DTU` classification. +* `rep_p_median` - (num) Median of corrected p-value across replication bootstraps (not available in `lean` mode). +* `rep_p_min` - (num) Minimum observed (corrected) p-value across replication bootstraps (not available in `lean` mode). +* `rep_p_max` - (num) Maximum observed (corrected) p-value across replication bootstraps (not available in `lean` mode). +* `rep_Dprop_mean` - (num) Mean effect size across replication bootstraps (not available in `lean` mode). +* `rep_Dprop_stdev` - (num) Standard deviation of effect size across replication bootstraps (not available in `lean` mode). +* `rep_Dprop_min` - (num) Minimum observed effect size across replication bootstraps (not available in `lean` mode). +* `rep_Dprop_max` - (num) Maximum observed effect size across replication bootstraps (not available in `lean` mode). +* `rep_na_freq` - (num) Fraction of replication iterations in which `DTU` could not be determined (not meeting pre-filtering criteria). +* `rep_dtu_freq` - (num) Fraction of replication iterations that support a positive `DTU` classification. + +**Note:** The fields reporting on the bootstraps will not be shown when bootstrapping is disabled. + + +## Abundances + +`Abundances` is a list of two `data.table`s, one for each condition. +Each transcript is represented by a single abundance value per replicate, so if bootstrapped data was used, these values are the means across iterations. If plain abundances were provided as input, then `Abundances` essentially contains the input data. These abundances are included in the output because they are required for some of RATs' plotting options. + + +```r +# Elements of Abundances. +print( names(mydtu$Abundances) ) +``` + +``` +## [1] "condA" "condB" +``` + +1. `condA` - (num) The transcript abundances in the first condition. +2. `condB` - (num) The transcript abundances in the second condition. + + +```r +# Abundance table for first condition. +print( head(mydtu$Abundances[[1]]) ) +``` + +``` +## V1 V2 target_id parent_id +## 1: 100 115 ALLA:1 ALLA +## 2: 40 30 ALLA:2 ALLA +## 3: 300 400 D2TE_a D2TE +## 4: 400 500 D2TE_b D2TE +## 5: 250 270 1D2TU D2TU +## 6: 250 300 2D2TU D2TU +``` + +*** + +# Quick results + +For your convenience, RATs provides a few functions to give you a quick summary of the run. They all follow the same style. + +These reports should not be seen as a substitute for the detailed RATs output. + +## Summary of DTU + +The `dtu_summary()` function lists the total number of genes and transcripts for each of 3 categories: + +* DTU: There is significant change in isoform ratios (in terms of both effect size and statistical significance). +* non-DTU: No significant change. +* ineligible: Ineligible for testing. Genes/transcripts with read count below the set threshold, or where the gene has only one known transcript. + + +```r +# A tally of the outcome. +print( dtu_summary(mydtu) ) +``` + +``` +## category tally +## 1 DTU genes (gene test) 6 +## 2 non-DTU genes (gene test) 3 +## 3 ineligible genes (gene test) 3 +## 4 DTU genes (transc. test) 6 +## 5 non-DTU genes (transc. test) 3 +## 6 ineligible genes (transc. test) 3 +## 7 DTU genes (both tests) 6 +## 8 non-DTU genes (both tests) 3 +## 9 ineligible genes (both tests) 3 +## 10 DTU transcripts 14 +## 11 non-DTU transcripts 7 +## 12 ineligible transcripts 5 +``` + +The `get_dtu_ids()` function lists the coresponding identifiers per category. +The ID lists obtained are ordered by effect size (`Dprop`). + + +```r +# Gene and transcript IDs corresponding to the tally above. +ids <- get_dtu_ids(mydtu) +print( names(ids) ) +``` + +``` +## [1] "DTU genes (gene test)" "non-DTU genes (gene test)" +## [3] "ineligible genes (gene test)" "DTU genes (transc. test)" +## [5] "non-DTU genes (transc. test)" "ineligible genes (transc. test)" +## [7] "DTU genes (both tests)" "non-DTU genes (both tests)" +## [9] "ineligible genes (both tests)" "DTU transcripts" +## [11] "non-DTU transcripts" "ineligible transcripts" +``` + +```r +print( ids ) +``` + +``` +## $`DTU genes (gene test)` +## [1] "XSW" "MIX" "SW" "LC" "ALLA" "D2TU" +## +## $`non-DTU genes (gene test)` +## [1] "D2TE" "SAME" "FAKE" +## +## $`ineligible genes (gene test)` +## [1] "LONE" "SOLO" "NN" +## +## $`DTU genes (transc. test)` +## [1] "XSW" "MIX" "SW" "LC" "ALLA" "D2TU" +## +## $`non-DTU genes (transc. test)` +## [1] "D2TE" "SAME" "FAKE" +## +## $`ineligible genes (transc. test)` +## [1] "LONE" "SOLO" "NN" +## +## $`DTU genes (both tests)` +## [1] "XSW" "MIX" "SW" "LC" "ALLA" "D2TU" +## +## $`non-DTU genes (both tests)` +## [1] "D2TE" "SAME" "FAKE" +## +## $`ineligible genes (both tests)` +## [1] "LONE" "SOLO" "NN" +## +## $`DTU transcripts` +## [1] "XSW:one" "XSW:two" "MIX.b" "SW1" "SW2" "MIX.a" "LC1" +## [8] "LC2" "ALLA:1" "ALLA:2" "MIX.ab" "2D2TU" "1D2TU" "MIX.l2" +## +## $`non-DTU transcripts` +## [1] "D2TE_b" "D2TE_a" "SAME_1" "SAME_2" "FAKE-2" "FAKE-1" "MIX.l1" +## +## $`ineligible transcripts` +## [1] "LONE.a" "MIX.n" "SOLO.1" "NNa" "NNb" +``` + +## Summary of isoform switching + +Isoform switching is a subset of DTU. Primary isoform switching is often considered the most likely +type of DTU to have an effect. The following two functions summarise the extent of isoform switching +in the results: + + +```r +# A tally of genes switching isoform ranks. +print( dtu_switch_summary(mydtu) ) +``` + +``` +## category genes +## 1 Primary switch (gene test) 4 +## 2 Non-primary switch (gene test) 1 +## 3 Primary switch (transc. test) 4 +## 4 Non-primary switch (transc. test) 1 +## 5 Primary switch (both tests) 4 +## 6 Non-primary switch (both tests) 1 +``` + +```r +# The gene IDs displaying isoform switching. +ids <- get_switch_ids(mydtu) +print( names(ids) ) +``` + +``` +## [1] "Primary switch (gene test)" "Non-primary switch (gene test)" +## [3] "Primary switch (transc. test)" "Non-primary switch (transc. test)" +## [5] "Primary switch (both tests)" "Non-primary switch (both tests)" +``` + +## Summary of DTU plurality + +In case you want to know how many isoforms are affected per gene. + + +```r +# A tally of genes switching isoform ranks. +print( dtu_plurality_summary(mydtu) ) +``` + +``` +## isof_affected num_of_genes +## 1 2 5 +## 2 4 1 +``` + +```r +# The gene IDs displaying isoform switching. +ids <- get_plurality_ids(mydtu) +``` + +These give you the number and IDs of genes in which 2, 3, etc... isoforms show DTU. + + +*** + +# Contact information + +The `rats` R package was developed within [The Barton Group](http://www.compbio.dundee.ac.uk) at [The University of Dundee](http://www.dundee.ac.uk) +by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch. + +To **report problems** or **ask for assistance**, please raise a new issue [on the project's support forum](https://github.com/bartongroup/Rats/issues). +Providing a *reproducible working example* that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure +to **read the vignette(s)**, and browse/search the support forum before posting a new issue, in case your question is already answered there. + +Enjoy! + +![](./figs/rats_logo.png) + + diff --git a/vignettes/plots.R b/vignettes/plots.R new file mode 100644 index 0000000..4ce996e --- /dev/null +++ b/vignettes/plots.R @@ -0,0 +1,62 @@ +## ----setup, include=FALSE----------------------------------------------------- +knitr::opts_chunk$set(echo = TRUE) + +## ---- include=FALSE----------------------------------------------------------- +library(rats) + +## ----------------------------------------------------------------------------- +# Simulate some data. +simdat <- sim_boot_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +# Call DTU +mydtu <- call_DTU(annot= myannot, verbose= FALSE, + boot_data_A= mycond_A, boot_data_B= mycond_B, + dprop_thresh=0.1, qboot=TRUE, rboot=FALSE) + +## ----------------------------------------------------------------------------- +# Grouping by condition (DEFAULT): +plot_gene(mydtu, "MIX", style="bycondition") + +## ----------------------------------------------------------------------------- +# Grouping by isoform: +plot_gene(mydtu, "MIX", style="byisoform") + +## ----eval=FALSE--------------------------------------------------------------- +# models <- annot2models('/my/annotation/file.gtf') +# library(ggbio) +# # This will plot the structure of all isoforms for the given gene ID. +# autoplot(models[['mygeneID']]) + +## ---- eval=FALSE-------------------------------------------------------------- +# # Proportion change VS transcript-level significance. Each point is a transcript +# plot_overview(mydtu, type="tvolcano") +# +# # This can also be plotted for genes, by using the largest isoform effect size as proxy. +# plot_overview(mydtu, type="gvolcano") + +## ---- eval=FALSE-------------------------------------------------------------- +# # Distribution of proportion change. +# plot_overview(mydtu, type="dprop") +# +# # Distribution of largest isoform proportion change per gene. +# plot_overview(mydtu, type="maxdprop") + +## ---- eval=FALSE-------------------------------------------------------------- +# # Proportion change VS transcript-level significance. Each point is a transcript +# plot_overview(mydtu, type="fcvolcano") +# +# # This can also be plotted for genes, by using the largest isoform effect size as proxy. +# plot_overview(mydtu, type="fcVSdprop") + +## ----------------------------------------------------------------------------- +# Pairwise Pearson's correlations among samples. +plot_diagnostics(mydtu, type='cormat') # Default type. + +## ---- eval=FALSE-------------------------------------------------------------- +# # Start the interactive volcano plot. +# plot_shiny_volcano(mydtu) + diff --git a/vignettes/plots.html b/vignettes/plots.html new file mode 100644 index 0000000..bee2e49 --- /dev/null +++ b/vignettes/plots.html @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + +RATs: Plots + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ + + + + + + +
+

Set up an example.

+
# Simulate some data.
+simdat <- sim_boot_data(clean=TRUE) 
+# For convenience let's assign the contents of the list to separate variables
+mycond_A <- simdat[[2]]   # Simulated bootstrapped data for one condition.
+mycond_B <- simdat[[3]]   # Simulated bootstrapped data for other condition.
+myannot <- simdat[[1]]    # Transcript and gene IDs for the above data.
+
+# Call DTU
+mydtu <- call_DTU(annot= myannot, verbose= FALSE,
+                  boot_data_A= mycond_A, boot_data_B= mycond_B,
+                  dprop_thresh=0.1, qboot=TRUE, rboot=FALSE)
+
+
+

Visualisation of results

+

The RATs output object provides a host of information and we encourage users to familiarize themselves with it. But a good plot is worth a thousand numbers. RATs provides a non-exhaustive set of basic visualisation options for the results.

+

The plotting functions return a ggplot2 object. You can just print() it, or assign it to a variable, further customise it with standard ggplot2 operations, or even pass it on to other viewing functions, like plotly::ggplotly().

+
+

Inspection of a given gene

+
+

Isoform abundances

+

This is a very useful function for inspecting a gene of interest. It enables quick visual evaluation of the dispersion of the replicate measurements, the magnitude of the absolute and proportion changes, the presence of outliers, and the consistency among the replicates.

+
# Grouping by condition (DEFAULT):
+plot_gene(mydtu, "MIX", style="bycondition")
+

+
    +
  • The top two facets show the absolute abundances (counts) of the isoforms as supplied in the input.
  • +
  • The bottom two facets show the correspondng relative abundances (proportions).
  • +
  • The facets on the left ocrrespond to one condition, the facets on the right correspond to the other condition.
  • +
  • The boxplots describe the abundance distribution of each isoform across replicates.
  • +
  • The actual abundance measurements are overlayed as points.
  • +
  • The set of abundances obtained in each replicate is shown by the lines connecting the points. This highlights the level of consistency between the replicates.
  • +
  • The presence of DTU for each transcript is encoded in the fill and shape of the abundance points.
  • +
  • The points and lines are placed slightly off-centre to prevent replicates masking one another when the measurements are very similar.
  • +
  • The colours of the replicates are recycled between the two conditions. So in the example, there are 4 samples: controls-1, controls-2, patients-1 and patients-2.
  • +
+

When there are many replicates or many isoforms, it may be preferable to group abundances by isoform, making individual comparisons easier:

+
# Grouping by isoform:
+plot_gene(mydtu, "MIX", style="byisoform")
+

+
+
+

Customisation of the abundances plot

+
+

Change information layers

+

The fillby, colourby and shapeby parameters of plot_gene() can be respectively used to control which information layers are encoded as fill, line/point colour, and point shape. Possible values are c("isoform", "condition", "DTU", "none", "replicate"). Be aware that some combinations of plot style and information layers are not possible.

+
+
+

Change colour code

+

Colour codes can be customised by specifying new values to the corresponding parameters of plot_gene():

+
    +
  • isofcolvec - Colour vector for isoform highlighting. Used to build a colorRampPalette.
  • +
  • dtucolvec - Colour vector for DTU highlighting.
  • +
  • condcolvec - Colour vector for condition highlighting.
  • +
  • replcolvec - Colour vector for replicate highlighting. Used to build a colorRampPalette.
  • +
  • nonecol - Colour to use when no colour coding is wanted.
  • +
+

An example of a colour vector, using standard R colour aliases, would be c('blue', darkred', 'gold').

+
+
+
+

Structure of the given gene

+

With the use of the third-party Bioconductor package ggbio, one can plot gene models from GRanges/GRangesList objects. This can be useful in interpreting transcript expression and DTU.

+

Therefore RATs offers a helper function to create an appropriate collection of GRanges/GRangesList objects from a GTF file. The collection is structured as a list, indexed by the GTF gene ID values. Each list element is a GRangesList object with the annotated transcripts for that gene.

+
models <- annot2models('/my/annotation/file.gtf')
+library(ggbio)
+# This will plot the structure of all isoforms for the given gene ID.
+autoplot(models[['mygeneID']])
+

For more options and more refined plots, refer to the ggbio documentation.

+
+
+
+

Overview plots

+

Our simulated dataset is too small to properly demonstrate what these plots might look like. So, instead, each one is accompanied by a static image of the plot created with a real and much larger dataset.

+

Possibly the most common plot in differential expression is the volcano plot, which plots the effect size against the statistical significance. The thresholds are also shown, although the default significance threshold of 0.05 is very low (hint: no lines are drawn for the axes).

+
# Proportion change VS transcript-level significance. Each point is a transcript
+plot_overview(mydtu, type="tvolcano")
+
+# This can also be plotted for genes, by using the largest isoform effect size as proxy.
+plot_overview(mydtu, type="gvolcano")
+

This is what these look like on a larger dataset: Transcript significance VS effect size

+

You can also get density histograms for the volcanos (the Y axis is square-root compressed):

+
# Distribution of proportion change.
+plot_overview(mydtu, type="dprop")
+
+# Distribution of largest isoform proportion change per gene.
+plot_overview(mydtu, type="maxdprop")
+

This is what these look like on a larger dataset: Effect size distribution

+

Although fold-changes of transcript expression are not tied to DTU, you can plot the traditional FC volcano and the relationship between FC and proportion change. Bear in mind that the FCs will be based on the abundances provided as input, without any adjustments such as library size normalization.

+
# Proportion change VS transcript-level significance. Each point is a transcript
+plot_overview(mydtu, type="fcvolcano")
+
+# This can also be plotted for genes, by using the largest isoform effect size as proxy.
+plot_overview(mydtu, type="fcVSdprop")
+

Fold change VS significance Fold change VS proportion change

+
+
+

Diagnostic plots

+

Currently there is only one plot type in this category.

+
# Pairwise Pearson's correlations among samples.
+plot_diagnostics(mydtu, type='cormat') # Default type.
+

+

What you want to see here, is a nice separation between the samples of different conditions. Anomalies in this plot may indicate batch effects or mislabelled samples.

+
+
+

Interactive plots

+

If you prefer picking points from a plot rather than sorting through tables, the gene-level volcano plot is also available through an interactive shiny app, that pulls up the relevant Gene and Transcript results and the isoform abundance plot for any volcano point you select.

+
# Start the interactive volcano plot.
+plot_shiny_volcano(mydtu)
+
    +
  1. Hovering over a point (or cluster of points) will show the gene IDs and some summary info.
  2. +
  3. Clicking on a point will display the all the available information calculated for the gene and its isoforms, as well as draw the isoform abundance plot for the gene.
  4. +
+

When you finish exploring the volcano plot, close the popup window or stop the shiny runtime in order to return to your R terminal.

+
+
+
+
+

Contact information

+

The rats R package was developed within The Barton Group at The University of Dundee by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch.

+

To report problems or ask for assistance, please raise a new issue on the project’s support forum. Providing a reproducible working example that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure to read the vignette(s), and browse/search the support forum before posting a new issue, in case your question is already answered there.

+

Enjoy!

+

+
+ + + +
+
+ +
+ + + + + + + + + + + + + + + + diff --git a/vignettes/plots.md b/vignettes/plots.md new file mode 100644 index 0000000..11dec0a --- /dev/null +++ b/vignettes/plots.md @@ -0,0 +1,225 @@ +--- +title: 'RATs: Plots' +author: "Kimon Froussios" +date: "08 JUL 2019" +output: + html_document: + keep_md: yes + theme: readable + toc: yes + toc_float: yes +vignette: > + \usepackage[utf8]{inputenc} + %\VignetteIndexEntry{RATs 3: Plots} + %\VignetteEngine{knitr::rmarkdown} +--- + + + +*** + + + +Set up an example. + + +```r +# Simulate some data. +simdat <- sim_boot_data(clean=TRUE) +# For convenience let's assign the contents of the list to separate variables +mycond_A <- simdat[[2]] # Simulated bootstrapped data for one condition. +mycond_B <- simdat[[3]] # Simulated bootstrapped data for other condition. +myannot <- simdat[[1]] # Transcript and gene IDs for the above data. + +# Call DTU +mydtu <- call_DTU(annot= myannot, verbose= FALSE, + boot_data_A= mycond_A, boot_data_B= mycond_B, + dprop_thresh=0.1, qboot=TRUE, rboot=FALSE) +``` + + +*** + + +# Visualisation of results + + +The RATs output object provides a host of information and we encourage users to familiarize themselves with it. +But a good plot is worth a thousand numbers. RATs provides a non-exhaustive set of basic visualisation options for the results. + +The plotting functions return a `ggplot2` object. You can just `print()` it, or assign it to a variable, further customise it with standard [ggplot2](http://ggplot2.org) operations, or even pass it on to other viewing functions, like `plotly::ggplotly()`. + +## Inspection of a given gene + +### Isoform abundances + +This is a very useful function for inspecting a gene of interest. It enables quick visual evaluation of the dispersion of the replicate measurements, the magnitude of the absolute and proportion changes, the presence of outliers, and the consistency among the replicates. + + +```r +# Grouping by condition (DEFAULT): +plot_gene(mydtu, "MIX", style="bycondition") +``` + +![](/Users/kimon.froussios/GitHub/RATS/vignettes/plots_files/figure-html/unnamed-chunk-3-1.png) + +* The top two facets show the absolute abundances (counts) of the isoforms as supplied in the input. +* The bottom two facets show the correspondng relative abundances (proportions). +* The facets on the left ocrrespond to one condition, the facets on the right correspond to the other condition. +* The boxplots describe the abundance distribution of each isoform across replicates. +* The actual abundance measurements are overlayed as points. +* The set of abundances obtained in each replicate is shown by the lines connecting the points. This highlights the level of consistency between the replicates. +* The presence of DTU for each transcript is encoded in the fill and shape of the abundance points. +* The points and lines are placed slightly off-centre to prevent replicates masking one another when the measurements are very similar. +* The colours of the replicates are recycled between the two conditions. So in the example, there are 4 samples: controls-1, controls-2, patients-1 and patients-2. + +When there are many replicates or many isoforms, it may be preferable to group abundances by isoform, making individual comparisons easier: + + +```r +# Grouping by isoform: +plot_gene(mydtu, "MIX", style="byisoform") +``` + +![](/Users/kimon.froussios/GitHub/RATS/vignettes/plots_files/figure-html/unnamed-chunk-4-1.png) + +### Customisation of the abundances plot + +#### Change information layers + +The `fillby`, `colourby` and `shapeby` parameters of `plot_gene()` can be respectively used to control which information layers +are encoded as fill, line/point colour, and point shape. Possible values are `c("isoform", "condition", "DTU", "none", "replicate")`. +Be aware that some combinations of plot style and information layers are not possible. + +#### Change colour code + +Colour codes can be customised by specifying new values to the corresponding parameters of `plot_gene()`: + +* `isofcolvec` - Colour vector for isoform highlighting. Used to build a colorRampPalette. +* `dtucolvec` - Colour vector for DTU highlighting. +* `condcolvec` - Colour vector for condition highlighting. +* `replcolvec` - Colour vector for replicate highlighting. Used to build a colorRampPalette. +* `nonecol` - Colour to use when no colour coding is wanted. + +An example of a colour vector, using standard R colour aliases, would be `c('blue', darkred', 'gold')`. + + +### Structure of the given gene + +With the use of the third-party Bioconductor package [ggbio](https://bioconductor.org/packages/release/bioc/html/ggbio.html), one can plot gene models from `GRanges`/`GRangesList` objects. This can be useful in interpreting transcript expression and DTU. + +Therefore RATs offers a helper function to create an appropriate collection of `GRanges`/`GRangesList` objects from a GTF file. The collection is structured as a list, indexed by the GTF `gene ID` values. Each list element is a `GRangesList` object with the annotated transcripts for that gene. + + +```r +models <- annot2models('/my/annotation/file.gtf') +library(ggbio) +# This will plot the structure of all isoforms for the given gene ID. +autoplot(models[['mygeneID']]) +``` + +For more options and more refined plots, refer to the `ggbio` documentation. + + +## Overview plots + +Our simulated dataset is too small to properly demonstrate what these plots might look like. +So, instead, each one is accompanied by a static image of the plot created with a real and much larger dataset. + +Possibly the most common plot in differential expression is the volcano plot, which plots the effect size against +the statistical significance. The thresholds are also shown, although the default significance threshold of 0.05 +is very low (hint: no lines are drawn for the axes). + + +```r +# Proportion change VS transcript-level significance. Each point is a transcript +plot_overview(mydtu, type="tvolcano") + +# This can also be plotted for genes, by using the largest isoform effect size as proxy. +plot_overview(mydtu, type="gvolcano") +``` + +This is what these look like on a larger dataset: +![Transcript significance VS effect size](./figs/tvolcano.jpg) + +You can also get density histograms for the volcanos (the Y axis is square-root compressed): + + +```r +# Distribution of proportion change. +plot_overview(mydtu, type="dprop") + +# Distribution of largest isoform proportion change per gene. +plot_overview(mydtu, type="maxdprop") +``` + +This is what these look like on a larger dataset: +![Effect size distribution](./figs/dprop.jpg) + +Although fold-changes of transcript expression are not tied to DTU, you can plot the traditional FC volcano and the relationship between FC and proportion change. Bear in mind that the FCs will be based on the abundances provided as input, *without any adjustments* such as library size normalization. + + +```r +# Proportion change VS transcript-level significance. Each point is a transcript +plot_overview(mydtu, type="fcvolcano") + +# This can also be plotted for genes, by using the largest isoform effect size as proxy. +plot_overview(mydtu, type="fcVSdprop") +``` + +![Fold change VS significance](./figs/fcvolcano.jpg) +![Fold change VS proportion change](./figs/fcvsdprop.jpg) + + +## Diagnostic plots + +Currently there is only one plot type in this category. + + +```r +# Pairwise Pearson's correlations among samples. +plot_diagnostics(mydtu, type='cormat') # Default type. +``` + +![](/Users/kimon.froussios/GitHub/RATS/vignettes/plots_files/figure-html/unnamed-chunk-9-1.png) + +What you want to see here, is a nice separation between the samples of different conditions. +Anomalies in this plot may indicate batch effects or mislabelled samples. + + +## Interactive plots + +If you prefer picking points from a plot rather than sorting through tables, the gene-level volcano plot is also available through +an interactive `shiny` app, that pulls up the relevant `Gene` and `Transcript` results and the isoform abundance plot +for any volcano point you select. + + +```r +# Start the interactive volcano plot. +plot_shiny_volcano(mydtu) +``` + +1. Hovering over a point (or cluster of points) will show the gene IDs and some summary info. +2. Clicking on a point will display the all the available information calculated for the gene and its isoforms, as +well as draw the isoform abundance plot for the gene. + +When you finish exploring the volcano plot, close the popup window or stop the shiny runtime in order to return to your R terminal. + + +*** + + +# Contact information + +The `rats` R package was developed within [The Barton Group](http://www.compbio.dundee.ac.uk) at [The University of Dundee](http://www.dundee.ac.uk) +by Dr. Kimon Froussios, Dr. Kira Mourão and Dr. Nick Schurch. + +To **report problems** or **ask for assistance**, please raise a new issue [on the project's support forum](https://github.com/bartongroup/Rats/issues). +Providing a *reproducible working example* that demonstrates your issue is strongly encouraged to help us understand the problem. Also, be sure +to **read the vignette(s)**, and browse/search the support forum before posting a new issue, in case your question is already answered there. + +Enjoy! + +![](./figs/rats_logo.png) + + diff --git a/vignettes/plots_files/figure-html/unnamed-chunk-3-1.png b/vignettes/plots_files/figure-html/unnamed-chunk-3-1.png new file mode 100644 index 0000000000000000000000000000000000000000..ef39d9feadb94bcbadb2e6efec14594721e709d6 GIT binary patch literal 59705 zcma&ObyStz`UOgtG$&!SP*A+l(Q5B4UaH{=r8m|vQjG>pe*2by z{>b&|yN&YC;Mwg*(;C}(rbL_XqHzQJ3z?QQ9BcP^mh?inqL>|p%ZbZRIvup+RwV~f z%wNANeT566yB@!l{xX4wyw}K4)0Eg?-7++Pvzc+^x3%bexcDrtfk`K6ks5}Hu$+10 z*J@4QW_LHAONZ|`n(sI>W6WoU&ot0PYn^Sg2S;SRi_@3&S5M}99N;cVQ=t6S5_IQZC%ItVJr|@HTf^#$y9C>Cnatpnv=WAy zt+qbz5?=AjvZe>~$+XcD`GgYceN%IY6UvEDx3QXc^UH0QqGFz(?TiJJspgnVK_0Fh z0)xGW68E)i`WYy$e##lBn;0Ze%c~5`m0nkrB$aP18N!F6H7vOMPQ$MoHeZ;*_#QHw zTk=hhzs@&{6lFS$T06y3FA(b1D9TC}d(daD$L*yS4Asj(b?Ikyy}!71)5uIkT1|M3 z_l)o(HH&)fiCDkCMlEd~rhc7^f9&df|J%95LFnwZY{CttMAF0qU7_yhDbWKW9l@Ua z­{B;v?0EPZqgatlxhw=KSG=UaTa{=K}v)JcEy2vx6Y_1M3+{gYMf+Y{yScyZ^E zg&Jius-LGtiR(DBnFHk{n=FfLLeTX~io|tR0`gq41lj==laD4p`QD&&^(9d_o18WN zob-gIRL!!U@&`R|%vv{%ectLMx-r*-qJxO9B1wmtQ&Q zJLx-;I%i8;O?n=2S|3*AR-tTKCcm4{7So<#7N9c;5$x>hG?7!>ejXZ(Y{=r}##4e5 zjrYC@p|8^3q{O#00I$e-->$S~YDHL8DhYws=iAy52dskKS}>)oFabq~ZIf5 zKRLnKiojmy6B_||BOiSqP9a?3PKO|ZrKr|-`zMo5JJmzzs~;^hzt^ViMs^LXuNk3K zurs_s-DuCD+xxNI^z!F7^x9;L4X8?QcHT~V*~bUGInR7k=WGPtds_Z0?Yh?(%cZd6 zcNRn30p@EhM^L3g-#jjrJ!rd)mSA{)2X%F5C=!m9knUaRc-T=dLe2QJ=sn#%c=?{e zPA)+;X4xy$tyww*K5a6qE>*tc0kl2lRd>qR-2oi@v2dNz{0aR}5ErtPSJhTs^^7NZ;`L zdIKzxGvVZ+aQd^A#AT5%y|_})xkqLYh*%F>G#ZB%l9+ZbpZuI>&oW&S4i(%d78j0u zg-Yf!!JnH$tE+=yZ+j*kNjfSKn15bMvT(`_I|2e|$Z=5ryzpUEMLa40{fR0AG(*nk z$aGptXl%0oy>eg%y#wH6{_mBejI0D*raCV`@XxK{pq?u&!v52s2+Zd<0Voz99V+zO z^vWAI32W|;yD;*zHr8T=xjjidmZ9~t^!;vn@fV;OTxvHSwch!7Mpg)1 z&KNs&q4D%Dws=P!t#bd64U!77yox7l1kT6BX~w*dTDFF2 zd~Tc)>)Z~s6Q>#+jR*SsG3koN1g|n!vTIIziR}Ar>lbKjXTQe}56jc0w*AxNS zzjP?Kh4Qa1eh%1su7oPCm@V}F^z?MSJrK6qY=n@Wi3xQ%!j{fR-}mD4AJR${9&WpN zI)3*<&VjwDvcw1+T7;3Um&u8VluQ0kEyF2nT^YY*-Tl~_W7x&x!BCZ)oSipn#)KH- zA2Qt+<70^V-^7v#zS(EYip$D+W#4jh!^Q6J#A!Y6w@gC} ze)#pW|M&dbUEy>~0>or({#56mAIxdQ@E`J8F15CNB;rw+t+l32=e9i!%;2(4I^X~E zi_TFz6qW7nCsBjx&r>I9rn|!? zc=1KZV|nR3%r?>N>FoJ%G41PFInn0t|N3S<5q9FuoWt&>aQESQ2+VDm@O{T0rYk(t zhoz^7?BOgy9TLB5!(T){Ty~UmQ@E`r3+LBT1OHil^CIn^QMMzWGk!Fhs?ZnCwK@D# z)5kj_vU7@euA1d{yQAFVH_))9ngI{1m6-T%?&m)v$X-en3&Y~TJ;rC|^%sgUlX z&)Hk&j6{qL;nRLfr>#u)!QI~_@EiJ`8=uWm`CN+=-;VEjfN|c|4e2zlC&DIs(RRA>kX1XYgczF`da##;)6p(ul zBv6~Zf3CM=Sm=GU*fMgNBN}8w9C~%2Qb3WY|Jh1E?J1I>%d8E3Xilfz?qaFO^`Bkt zAQ)(6HyOiL>er1WE%R`D0b3llILgv`-I*NfbBr!+PhlfM{BC2SbTpl3Y?^;2Uk>jb z{I3BD2lO{`a*4iom#Lhnrn!iHLa^Yhy6Y=XGw8%4#S!vvCadPe%$FV9HfR*zTiOu2v_&00O8`^Se$qd+_v8 zW%{J94i}==5^8cA*rU!reZpOv408PhpUPn#Lx!sCXgO7y>PYjUlPJOfpQLL8KUBZY zCY9F=VI|3Rh`Bz6uX7zL=IztNk^hG9(@ksy5uu&du;M>qQcV=BExJ`LK9n!QxE|Se zawY0zAIoUO2!5Ap{qonC*`s^*L2m#=8J_*MA^zpnC>CyXg>1juqIYDjh5FUi)r0&@ z22Y5jJ_f4+U#HKm+MZe*gFn;@eNvtYEG`li@%#6>AVO}KKt|TvJwCrAy_71XhSR;m z^T^GWuDZrNe|o$U-WmTAWFYlLDc^d!T)D~37H72o2_JQ6O~66BIJ`ZIbmJqb@FLR+ zAL$nj{6V%)!?al*ovQE`@QLDK=&4_P@0I@v*zE^!x-k=&b(|^AASbFRNr$WJ!z31aLdK$g}8-0&lM_(O>e8 zPZE8DMIx6Z|6e*GgRaMM$cI5O#cWA#yIVMt*UaNTZ0H(>2|kv=l!jJO^i1WpO{=Hl-mBdCj#uou9r9u++&HG_Bmy(tq#@$JVlMX_R|qI)BeKF&B>q*72wmraMkLG$hg4*6ecLLxbU(OYEY zz;E)M^uXi8-9|T#B4^iBN(2%cA6G*&FUj6d$&QJC9%29-Lr?(Yb0yA~;=75oiZ6zd zF=$`T@OJW(oPAgM_hqZe0oKpQuO$c5691L!KS{QK=FTxyOS$`hU7HTl>2<4Lso+2P ztD6{L07v%$O~ZfoWVk&@j%#ph5J}Uf=9LZHvrf z6>jzt9?jMcMgKO+1kHby$kA)@GEM3>7fJPKNQ7I>67d`hXs{7V|P1v-I-nDMYU{)x0u$P$TQG!_#kTK{xX1ZD#}2S)o9h1vhX8So~Y z1`P3M-az%gn;E1Qf&Z>6F_36@wmHJ?xGJGlWA=8Ku*L7eORLGPjNX5xGo;#iYZQBH zaA+tIgq$RqSoO|8Sj6>degDrO07{m~B#FZyi<14!h8{{{=6JfhetH7%z~tArx5$nQ zGf3Fs(vWF9DVA&;4R7@LDTz0*+!3?^E=e-%3QfHLcth$&p2EKQB=r8s|A}K`(f4ZM z^lVHx{i34v_Klv;iDXSoGTAOB;|%~)8-t7$pFnb5uoC8*ry=PO#V-bd=swB&bJ z#%Vn@d`{tVF#G%E-T5!YAz9i?lT$og-2RPZ{a5B$p5N%7b?uA^-IW6LB+lo4XoD-X zC7>vH@hQV~N-F^%EASw2@}`Saq(=p>bRl4K9Rv>^(`D*FXBN#$kr;tfnZ}b|qI|c5 z*^Mmz88w~n7V&Is0jIAGJK@f-ojxra+@wmuL@1E`$%1~IuF)Xo%MnUh( zPtdRk_&pb3MO(0=oiX#>#G=Te`SB?K-ZUW8o`*1;E#MbG9XrlDVr@15HjYDXVa2%Jog z6LKZucPG!LL!0+MT;jpi5J2$q4E0KZw-Ae8u9Cf-fh&Ei2#`=Uc4}9lFfO81p4%*vS}-C zdn6cIs5Achitv?wtM2IQt(Trx3+`_fX+B;)z;|ilbBBpUJfoq*XhBtSI7tW+ab&9K z``yMglU=S^)tL+@O+AwjwKzCih z9CGr#T>F7L;}!!-lJcfQzB8rJ4~Y4=UCNkr-mwCw;q#7t#0l~7`Djc0 zBFj55PO-v|9*L^6m;#@)&c#+k0&aQPjk=MHVFEmSUH7KAS_+iJeoahdFp)oW{>+h% zC7A$wG2osRFCdy;OzgGz1vEi}D2%KK89^5GsHqRY`EbwR#y)|VmyX}PBBYXWdMyV- zg-HM{XM4Wij~>174k=Q;h!BR~ZJ%{iq+>Kj#}ov*i9FdvgQg+*u8-0lGk0_GFNC4o za`CGb6%|=phj>N5Y{3k&Q9mNL@02pFaO5!YRW0QKg;ejZdazuTwU(C%0J%LTKp6P zbz<0%su-)9k%EFk#JL5vs?;5Wvc^;e#d&kzhc7x$Pw&L_jN?Z$`Q_GnqZ$3Gw8ZAI z9Wr4elgB_bxA`U)1^@fu?n=(esyM=&AnKG+o90^(BNG!YoSAzrnJV_CYM;QqX^3iZ z@ej(6H~>(7O4M1q{o-d3mQrkotE=Db75!TA@DO?B<(=7d$X_y!fi|jq!=U$?ae_U5d@??M2de^D&aM zSke;z(#R>iL1ev0*WJk?i+60VNmxiGu`ZlTU?QzQ?(M0=8-qG*ld`|;icC-FdOZBM zU;{`lPDgL$F?Qthwe2=pIShK4o39scp`kY5Sp4M^mZdrnQ4X=XFI>Srp4jO6?H-VN z1jDxyb%fa+FjkF8YX0LSD@TD9EGjL#gn;Fdac) zCEz58eeMqG%|?$`Z9&K^g6zreRtS^Q9f1RX_g`>)BHFI5qkC7cWwaN^58^CnS{MWPZ$f&wNcr>~KXGL;9SxzE~cV zZ4g|U{U7%9Hx}HNxXScu%%bHp`PB40R^S`YM)@};T^VoXQgL*k#OntVNqW z4Y9P@2+)lvJpQN7a3Bus^ghD7i>{ZLB#?AFWWQh(aEhB@Lyg_wLn_4tVMZP~cmqCm z#<%VMH0u0lNgtCTAC#`&oVKw-ri<5}F934k22}OYJXfJ;M8iTRHXz%bC@ca_NdyT3 z*LIv0NL?7B3AwO6I=Z6RUcihAd0h7v-$zanTm&JO>g;WGSIpJhXEO>KWZrhj;Vu5K z!wrt;aCO_`in$OBS2E_6w*27R;8(R84< znOTJ?Fn==sQSIh=83&2H=DfDBE-6!CwvN6~Rcjc7SM<9!lUBr^m#2rBn!>O~T7H~| z7@ywdj|CVwhCh4OJu#EUT9C$W8aeOKh1RMN7FqW?t#9pSM*!9#bAj&Um;|O?b0KKs z;i>5)txDl1EoKr-BqF*O;~4*uK&p`MkBKX9t45x1cdOSNYVq|bm|;heOz-gnM-gLJj2{<&UJgDXoJqur^k;`1 zoAg0I0ulTnfX+PP$0?0SzbtPQGs7-6N7CiGLeWOXfB3ueUmDV7i~S`UmK9*=#aVFo zRuG#%t8A#un#x*@(p2g4)x`1BSF3}<#S{xk3p&Ks3~&!VUp{f$FERm+@Dquk7k>IU z{IeHGn~u^LYX#YU46q2OtdYBbUED}i6k>C2uY3zgn-OL8{D#=S!63&9Su>L_!gcX= z!tJ_n58sJL)%l;dknIs@frVs^M3S|CY!n8IvTyTvULc(Mg&j3HnnY0BfO0lR6xMRC zu8g2qnwm}iC|JMKVFciWTs3!4-atw#Oh%Zq&8Xi+x%~mT60J8161ESn7L4lV#*N^o zvQi*ge79d}{Q%GXCdGVOKNOXKA_x(Kdolje8DE@0vfppN>s)1ADv0b*-`Bzavoz8n!Vh)6L}|txf!7bf-LP9$~)8B>Q{k zwF=iNatxX~(qgoV`>7siy^s*bMXZ?cP=FEg-G*4OK#i>1Jxj#Huw82a;I^D9=Ayo2 z`%CF|f|8q4*XTbS9P*oXy&~?cy2}_h8~y4KzM;&?=>Z8B{H(tl=Q*T0{|e_R0J$p_ z3bdLCGhM0@cTo86S8}CXsv@UV4s0*#)*8u zqU#?^ZscgasvXp8)63JbuG)NBm3vmVx-&0k^29BBs?IH@GOeRHhH-+XnfU0go(hEaHFg|a~kvZ|?(mgB|$ zMX-S_{)Q4%b8o~)a3BaVz#AzqUoDwZk+(~=pTjz4M)+;=q_tGUHj}ieY%BW0+>@_X z@x>uEeIK!k`V{t^o6SIy>6t%s{3sl_)jB13N;l=Nb^h)kqx?J>v-kGRiet0U6mQdH z-{gMVNO{2PV+dd%6GfWYo4k97V@T-uw#1YlomE#H zP`o;5`C1OT+XQs%-yDz#3{LxbI>C-nt<`fU$^)8cNp|+`8n3tgeXNv_Cwz?qkg#IV z9%NSIOyKrE^F5d~F=5prqiJzg{4Ot>Q56xF>ir0Q90=Fxu?k1h&-|aQeNAJqwGq+c z7c}c%htWo^rA7FRbB-UE^zo;_2hhg>z(c(~B?=g!1<%e1X1n8jd;JiLE=RqI$yJO2 zGyRtn3II`LJ}{_VxI!ExqL9bss0gLv_)7oliEvHYo54CX3Qe&%F;}6^1og7CnKDKC+s$}Na22>Kz-?$7&Nwei@UIMO6 z$ZVg#pci&|vTFN_rZW%i?081zWw zKqE3JFoq$9w?H~zuAg^`LM7ysIdws)4J)2KWZ?$OKt2k|Bing{bbwZQ`oC1sZy3VWpL7Ey&U^!U0HRq0PUoRI^G9=y67&fB0Q@ zsW1eVefvwbYu`ZVpihd+yVDifJ^%wLD=CoymXY-?Zt=UNN>Ncq6b}$M4`yq{6XJ>a z-NO6U*!FlarZNw{GQE4~5a&qR(8#MUBnrNW`uMeL>|mNVbuY|&u2G?*yt<1<{Rx(C z>9us_nTD(O@Ls)9zQ^TZA}+CCY%tp{Vn-GIFT3A6(Jn&QpYFS6Hia0o>dYfKi9C4A zu%|P)8*d0cQUMTqpG#c?lB=_`Qcgu2s!b?<}-zzsj~Fu$J;%rpZ90k zPfS4bOaPqRt@ir@1>!*E2xF@q%ve*cR^NW0$l~M#0M$YB@^HcW6tItKF|RlA{{#{6 z8BsOdoVgP6@yIdFkw&{6&DFCI_H>ti1ZW54Mg1H0rJ%+}LY``w2xK?kN{s1ONl&o& z9UZG?5o&iOZ?nmNpQmP&kf-1}%^+D#m)r7D9HSQ2o=D3wqpl-eaJoOB4pjVM-mlK} z1Su5ptCsHMQ0F%J3m&=BL(%%DqsE&wD&+++b&-?K`4;bb0iZ%U0p$+qv5}?uSd1et zD=p1x6Tz)LXA5W0>cnNguXXiT^`k3yL=3-C-x9I}^3?g?G;KKfV{Ri1S@?t_MD}PI`VuMmg;|n;l;SlR9kgY3!uC+o5o zUS(9wQe(%byOHkC7s(sKj!WHhmr1(M2Fi}UXf6fWJuEq|wIuYrqTHY@ z`y0Kkho~)qL-KkCz7q$G-dh5tfqHnwEio8!Ys}Qt)QNg~eF!D~mP5Tl&o(0#@Y76y z0Z9g!zW?@O?=8mG|3E!P0C?VmwAnsJF{z-Qnyk=YVtQrL!SFX;i{Vt_F;B7d`=E)C z-khgD29yp@Q53Y63Sy5)G9BdcrqEB3nq8a!2U){WV>)5b#k4+L&YAAdRGt2mCQa4M z2EiiRKE>vI`==Rit7s6yM4hb;0T5_kuK?x1XC-;uICSm5WPq9o)LGlKdec4nL9UyV z^`1S2pmdSZoZ`N0uB-NFg~Y8MZtbZSq?|UwMv{ZJ{q-%n`E-yG$Rr9y8Wno&tg~_C z;&7u9_;z9OKPZ)?mVB??|EaZ3e%&hz;rbv^W&@k`m;L3`4$s3&aYj{GkM<+2GL(Zx zid0`t)WqKB@8#jYi^+SkB2ys;#)U0EcpBgfrl8^N+unaxd@|0d{IASe93C*cW?c8x z0<)2&4n} z85-I`RtQJ+y=GH`Baioebc5RS4Ktlg-|u zfs|5jC<0d8E$3x8C1hPj8@%(8#q4>6M>Vp3?^(pZxB64txmUV7*YP*}(?MW98`(TS zd1QeSR3H=JJ*-@Dx>{JxPlpZdPO0r@Ui9ekWOf}3G3bJPgao;sl|dfD=LJeoRQfi_ zTz=a|YqMrj`g5L$-bR|so#WS9x=TvN2b<91jTg3pv-4=EBSVG&vTZLELlmSTXdW!q zuA@Rsf#qB>`XJqGf}xWG4Ior+t+N-TV|-&HFdO5JO)C zC`Ke*H5G^`*Nxyd-BgLLMQAUm(T5Ok+Z~WEh}nBgFFXSbOhYiR3?=I#sRu!d9wX6q zy(V?yph+4I?O*nG*_7%XepMe(+tP1&lojs~X6JtJi0|)b8~vn8k_C7I3W6uvB~5T3 zI5CG4=2AEMDYZEEmSjP02wUB2a5KBR{EvK|LX&c=+|D0yfxXGsvY*w^yOJX#_+`k7 zAP{4BXsj0kF$AEapDbN>O1aay7#1f#=wfBwwd53ewI!3gVGxJv=VzUUaSDg643YJ` zr;2Naw0l%*J_K+Kc4j~y<>iNvcSL^4%x&Sgo3e&$fu;%K7=`Oal*)Rxpf%Y@epxb4 zg_V}R2-GE72zLBo^BUk=#MDb%&*fi3e2Qcvu8)zm^jlSDg*dAX*8(3`hq9wpJzP0Vg8nMZa7ep=b;#Z_%(4NPFR45)}2l-1HF~OhPmvNB!rO-Yxgdh(0n(r z@XBoz8%@YxcbmG_rszu=d(UEAui^E05gRRN1?((Y=b}GKV3Z~l27AX%lO>Gm>gqk| zXj{3Ttc3p{};&4w?v)j7=qmfn_7OLlzG(Ou^n%t|kZ5 zM5QEQaAj9DU5aJhpZZ+7+P$TJ(UpRj1*MG%E|29reBW-FD70QX3)Anl0L2axa6a|t z#tJcz`ku$HudiRvX6Fk+D7ac(pOczp6%-vaJr-T&Hw3fqDY0-7;iUw^x~QVR5z{V zc-9~|0}c$k^0%RQon4f|y&^AZzG>v|LYOKEEF@ulb8+nwbSl?s3GQD+t;5gyGpjvL zj4VqwiA-gI8_wkBbi>qiMJO3k?43UA-u;_0HQ_c#r&pZhN*7x?`AQ|sbTY#*`HFhj zDAd<0P>k=2eg)1xdlAVgEVW;D9?H^@h71kIx(`tS;qsm@1!&v{KwA-tMd-l93#+Zx z4V3c!-Nvt=*8(OLi2VR^)1-7C#^YD?X4a7qy0>G9OQ2A9zX;XfS1M_o4fHw<={kPi z#2Mjt9)hPwr&6Hs+5hQoDItoW<=&)T%A*1Jnk__ZkCW?whSjIUr5IQ5x*& z9-M8KTzMZEcz4Nl9eYbrRuQ_O9W{_OMiUn*JYyi(W$iS)CJRnkS6p6CR7?VDyS^Uq zE;eqaS>L-4K-_{gW+Uu(6B8~;%x~tgbMSoT_4w2?AQ3kbOEX_|>FN-t$O6hMcGkx3 zQ7i9&php37g=Sym3_Z1RN77sLU}LR^fwyoa(@H{<3`5QZCj873;wYGJ+*R75h1mY) zz4poyva$}72Y-7&1mu6ZPrfXAKgOBKjw8PKJf68N%|TWjzIo|E(cX2ROj&SbCQ#c7 z(JFMM{&6!qWRD6{qXEogydn1bLJ(SC<3FL9-zTX@ z6DzL?gNXhzZlx=X2p+deSdb*vX0cfdg5*6x?UHXcl7>8YX<~)%Et0rnRZ|8QVT7DW z!K?3h%;nd|P3X~c+nFD$osjsItc!Y|tC_-d9cK^;IokI`)}g-HgxGhYSX$#q{jNLC z{lLB~NXX1&29NoPL0cf!9U1KZSB;pZ2$09B8XVB#5m8lBdVHRqZk|GZT6m>UOkC(I zav-Ep&bN;?W_TT`dm1e0wmFrSlBMAH|#zR<@K}3-FB?9x49O`aNn~(F)7vGSy&{V+SmH?RS>=9V~E+JwfrY{2EV}}+ zGmDwtea@9|m6^#1nVh(JIGfsJ4)HnKY*lj1BtFtVbkN*sY?wG0=TQ~S)N3#0mR{&= zf%rZ_K#$O{Rwo1ZRUi0&BH*=i>PF%wCslKWbsak39p_%D3&a6RfKH4|0OBHr_?3kp zPcZal0d=1MoXbQTI1zx7PXtj<*I~_Orm|yS+zVJxqOWFwPa&V!Y?lrjACHtTk8M>o zuC20C3AlwLFQu*!ZNp802E)7?%GX=`@UxI~u>GQ%spM;qTv)>?y>%U+e0? zWdP++l&3AM9ZjzEQ98rBuyn`~7%K7K!=ANtkrx^F#eDeU`DPUplmL<#=3r556z0aD zkOdr`Kx*m)2E?!i8jqq-x8jdE12e8dY@H7Ht$UI?Au+B75oyUuqds1T|37xITXmm3}ju7Q3(HmxnA8pz9|cd*{c;82G}-dkw;MefP~l{P3YA^t%f*<^PglAhzd30# zb8gjPsbF#^cSHf0B&3*gY1~ zP21U=eH#}y!B&QIj3u?6a^;rK_Ls2X>49d?-9Rm>?G+GS8##fE*(Gx=a6>*l#21Na zkL8hva?`CxoOvHH-9M1LwC~3~X0ei4l1E`S(cboX=@&b@QqosHRO(I2^gR#CQH4fd z58l(3e$7ND-Kw9rYA0|puG37`RsG_KIwIN$8I)aQ_@`@)fx;}NctiN~m+bt>>MjQpIBJIWAG)6;Am2xEG z-RzmqE(-wz99_DS7?v5b9EdOLfJlS*tz@1aA0XE64;3%Y7dyV;>|Eczd! zkF)wlf#IyAO8eCzktVQ9gnpt zMgo_3`=#_t$6ymvQ(0ge@qNZuM;9SVwoWo$ofh>4-z9l1G%%jk?yomcycZa5pS1-W z@&wy|h1AW!?HCpy=-#Sns~x3=g&4hWxoCJr^YB%ri2V)Q*<_c$V_>MUayE=5g8j9- z#PGgcUy>u0JN2_b%2)yA7q4{b3Nqc&7}HVPlJWFBIy87vR7Kei=jtn7`hH&=lZ2ou zQ5HKbC$OB6SBs5t0m*3pD*mDiLzt6>T0_s%G{W~J3$qFa;sHeb?%N+n&hBw+u*S8u zB#CZ%4s`p^K;(lDwnO1f`EN$T!m8wg@*S)S)Ax$UHL_QQ|Ne)J7)LH@{rEU0(70Gi zR8&A|Z@7b^))k*bbce^#&VwOmr9*yr9?&8`a?Vg9NzBAgd45@gg9?tS<%3DaZ^qjm z4(!eH@NUsxE@E~d=C%V1^j8A-P-6a0b))s^_?=$`a)~r=^MHFvA>k(E=$TOlf{F;R z>%(>hqF6vxClFOGbz{rluZ1Gajd4P-ELq?&Qi|dJ%L}rjU;NFm56)XmF9sG!xQOJR zzRJBnD*EO0$op_?huT$fJx=tgRXZnfcST-T?gdQBYb?RYZTOy57KkJNGh>c|@A$Jw z{H+*~c!8(;vyIC+`(yxo)nkA^$@s_ie%Pw#0CjTz($k|mEq#$cwsaJWKUXZz$E$A~{_;2ti2=Qq-?vyW_cCfIE0(x3Md|%3X7!|K;gtKI|HRL6 z$Vdp`yZ4_h+GH*1VKdreZB|PuX!)^2j@R=sLVEeI>4@90FQ|4HXzXlM7zKIxa>;~k zDF(I%X~~e2MaYoEjTsAGhi@p;i7)x50Buj+N}=q{V3UFKZQ zT_rrtqiAD#<6W8wj%X;`(L9UW)_fU05KGEm??1p3SNTnj@QGvw?7@&Rk=TGb{IMTDE>7;2b%F2GwX zg)Dhg)Mjw|(~Xde0xSRYqaSuW$(#fPwy8<9=R$A4RdPQNjF90jIn|2OG5r!Nzfil% zN_iY{`C)eMy9VxGz$OJ1xdTjCQTact&sM@nUj#=2sh}$@gbp}+*b=YX?I!hE*Qi#5 zC~(y%-UKU_OGtEZ|6K(cnB(NKT0i7V8DB*;bRPR9^J(qg=hmgDkrVPRS^d-{j^`xV zK2qT1Vs*eJNXZ0+b^ZG!W1d6QGj$lG)mJz0gijouJ3MDsQ8s`DN-p-T(h~Fzmlj;{H40tPiOMV!-6;yV zt)!YmSq*puc4z1jDONAILia?pZD8Y+R*@b)4Tm~Ydda5t+URpArNtbcz7M&^d)Loe ztd5GznU&Bjg(jP5y^ zo8F&i-#vv_uBK=lFP7s`p0P|ETENqsESvD)diQA|g#ovvdS!6%Gozef-n(3>(?90f zsZMOU%26+vv8QhO14W3G!r=TN0vVYelELE@%CMhF^Ab_vY4Xp)H##3llqmgLa$YpA zJp0`Z<=mwr(;f>Ix(O!Qv+Yy2PA${Wxd%=0R@2jSV~oQ886M`4_ZJv1cYh~1C5`5i zM67RyuNN+uj+Icp=KImdX~(3#CbbxF-bcL0+~me+oIGfFz5O+&V8U!PgI-bSCJ#Yo z1`9I_33?afB`+CJr&ytvK;i%BVfA89`y=2{j6@m$#U=t{M`O^*va_w9Cz#`Q$!VLF zFTODQYa2n7g$`!o4tZbr;Q7nYEAa%?5|)IK59;IjO^pqxt2IiA33f1m-9AmixJ8Z| zL@cyr=2~m-p)jY?#pBDQrAd{n#p8Ejho>-^tWtfXq`cx9)8+3?fhV8cWm_q^KH&GW z5YTxgIyMYQa%>2J+Vqc|e027&>(BaaRQuGTqn-N=Y8JLw@Q0b+wJ2=M1p{Gd^2jce zB>W`Tba6F<6R^f13aVA;wZJ{2WJ92}fYG@6C|;@7UD_?F;2S+5@gu3&^6(q+<%p0^csEL;W>~t-pxaA2VFc1n%1TPU{w~=vx*?v$>Y>+t+ zhQG`nQN1ZmT6v{3`z$ix9QuQyN9L=)8yX0_5Sjg?oL&dA9CP44KG1H4j1Hr=g*0&? zd_nKfVTL`}?PQ_5l{NrmU5%7P0m*p;dY4X0J~AXAkOc-qzQ6K{o(S^&Lb#8JKHXhM zyFQ=PYHzko@ zUnz5X|JI#D$!IDiZl z)9seFQd@rUK(X4cfrhA7qflOKf7f}FCs$n1L!VxvVF>0|dt^$4cFekmC;D>xfeS?f5r2r4MS=A}KiWAqN` zGN~%Y{@rmss+J!f-$&^2W3KQ3Y`fKDg3Isoxx~eGpogXl-pcm(6FIm&-=SnwFOB>5 zHXR`^tj2LIn&-BGmn03@PcCPVI){#H=4Z|5Gl0^~zlc#UcS+MSH2w3!#9+6|vayy)-2b4_NdQGSs-(^5(Z$#r? zy~7F#P{!q{{WO2Anb_np4ROp_C@^%zNA;KFk&X2Y%Lf z3bN4)!sAYrq0x|WIR2uC=a}P*&%77BWE+>~D;4cNjPY!*044JBr<#X|V%ZsyJyDZ} z=(4Z>JJVUzF1%e^L{88VadM^HA0o9mj)-G-h(sT4&2es3HFqcjA3f?bT0x0&Yw^GgL&aM*EiT*v9x9eEPpRpIc4@TFmikP+i zHjVRdaR4L$BfXw1LGM8@(pNl7J~e+;^vgfyLx7+e@#J^eCfl2?z$kr@DX#gbm5Skq;+f;O z&Is8h1f(O)dv0Y`yY8vqfWCf21P3%eKedIA%L5l^++KOpXilJ0B6q0eI=B2WIOCzqG0>OydH_US*{K~ATZ4&%UlQCt%7A%D=lHMY0sK7*n zhXax5Pn0XvN_HPHus&Fxt`D3pdLPLGH_CbthESaMVPju#m{_x1>(T{j6k>SzRQ&7J?R|IY>?E$bje0G2oU(KXd z-Mwv#WN>7^hwKc^%c7P9C?TXX;u?qlV2^ErWHZ9o)GM_sgi3gQoDZBTfOyywfZsA6cNaP6vEj^O)I>sLqw z`JDkqT8G{(ub%{1uhGqHz^^3e@t^mLHhwRxOSC0~;znPIF_x_PfU!&hvEJS2KXZF5 zR&W+Db@qQ$Q?4yMXOKRhn;{ao^8rj4EzKQP{md7uKDjwhIRD?MsOgpZGBBJ>@X$9n1$+-IBWOxfZ?I z{Oo%OQi=K{y<7&12|TVe-yrRyC1&CIM~+d}_dhBTFYJL^-_@iqhPd|;y6;*zFOG$l zmR1D1r_MQdP4nKl_mq@lY9l%4rPPPBb9ZROPL>hC`IKNJ_DkY{s~ zlsooEBU9!&M-TGBc^VDSg75sUJH5QQ9?qoAa?@HZ`r_P<=X?Fxo$0c`_E8pv=ps?< zXP-BIUx+gIDepzsMZ_Nt5kV(G;@OB=hj@=s)C_J+S2`O3k>au^Wq}*M--c}V9tD1O zt-a`dn*R@1Zyi%sT~ZQCvytvDr9(QTr9nkPy1TnUQc6NfI;Fe2n>#n> z-0zM_{ zs=gPNEq~v&*oWuTkz8^AvF-Lmb&Z#Fv+j4@!>q-6h0B5NNz2lNJ7yNvW=bHSv^+di z?vw1cp9PO!8L+E*Y!)yc{9WGo-Bnl8^nEMd>!g^2n(Di0Mw3H=q*tiso&x$#-LezC zCDFl?S*kk0S1OQdSmze14vwv)#XU3cpeZ83s6Vr7H2zCRENu_Z_bDER*iEWI5xWGi zHYiSxP|Qsgr~1R^%ZDt`%$Ao_fxxs3 zYZc>#<6b5QMM26{Tc@z4K}JddlCQ zXzWjG+XaWP=(FM{P$JHEz(|7{F!`V%jQlxFbyZDlKJ!LQ9Ky_dH$wjf4#L3kbjz(z z%hn1QXRB$Md#JPt)|~WBh+AE3{CGq9U*g4KOKCC3KN3FoxOtg&&zuKltpC7WF_V3& zMd8Yea5SYC*mk)Et_*DxvEo#05%U)1xSZ4ZTml0F38|?J{SsZ%iTyF&ev_hJw1HJp zgUrpTPJ}|g(5%9f_JeC0){%R=;#GS~^!MFNm}$)6AMg8f;g^ z4sd{t|8NdQpp3&oAk*kO@VemByJl^^}`24W*|5mXY_BexoC0!*}6 zfQuaCxI3jZz`MhwxA_M;a{~G@n`v{!X>QvEBf3Us;*7TnA<@KPk8mP0?5P^Lyx7_7 z_JfQW?|1TLWNlb9m1eAF3C`(a^M{pA>Xa(_Gs|CE0k^wA@Jp=iy2PI+fqUko(t+kg zhCiQ~e_ymLtryQ#NMoro9Xw~Y43^VypL3e*Ih)jD1p}aym`1rYR!KD4sWes$tM6ShBw+PEY!t1|t;-nmW49}qsZmI@! zl9bg*`5-~&NgaBuHGdSb51Nh)Jfr~c1A$ed)^~&4oT4^~$~GlL=ANWuJiUwO?l&(m ziXAU5NFZn)qXpS5Kr7&3xlkj*Ou3)$Ob*tzzQ&CNxiwS^NE;~GK)LB>CRQJCdye0Q zq)tOI#Lzs@=(UgeI8?O8r~Upou0;~yCSYUz{QP|Qmu#qaF&j&ChAPb}Btr-dos=+? z9=Q^A(LU%zr8+-5QH`$Uh)~UJHV{{wWVg^`J8l5r!jVb zH|!w)$@j4mch_ucF0OG-RFO?h7yl8Wt#30x&VUtU|ID?+P>77a7NFPzT=p=1RylJM znD+KpD9VG)d+TFgs8$q@s#TE%SGb&t&d2v2Re@X0ctc)iOtMD7Rx0HxN)zZO2ymIm zK_eyvW%KZ-stg{EeSZF%ELj$JRfD;oy4fc*CLd(7Q$VA3=0I#LNn?8qWuEiYuk>D< zdgplYCP5lD29gf)Jn^j^F#9;Lf>xh^hd)@W6A=SaKg4R7&hQ(ke1aXdU$XPGIlJ?& zCbXRk+Fdbjy&#vB2o=0G=+EGaBquT{2syyk0hkioK0aUOfne`PwrUI&5gc1i| z<}Ly4^*w-T-Ksy4ja{Vl?c4fBP$Yc!`wIo!yb01B)0`lPk>n>D((_WIx;G@vxaQJt zIjZsXI$RVsqElK%Wqai36#Ds`yS^=uMlro4acF5j=b%}-#*}V>y^j1rSh!)U6)L%n z&dQY}wLPIH&HBwocSm8~(cqS=0k(X| z{$~oe2ZSR5tW=axnJ!|7@0`}tsvB)))L=}E={my)Sla;_G)4k$#64~H7svE8+B@sDJP`bH zF!&IK5(}sobz!;2@;Zk#f+nFQ40Eb+%`57(EC2<}Aqn=pSnzJq!oT|FE1RV2t z+*La+(ljH$ zYxotJE+-)6uR1?hVvv=xtt)u6eJoKrOfbxVR)92#A8Q!rI-l64&pWOk?k`famr1;Y zJd&TaA51QN`u;l$t--B9k~eny17itbA`lPsay@q7e4hBX@p}`|oww*=_WWfyUmShQ z(Y=t{_@~f`Kf<{?GV9@|+y2TNRNg)a*vU1J+fUWVjbPlvp8wLR@hKz?< z(Ao@BgYJa-Ch%^Ffv{dpgbN{nMtyQ2cvt0paLAP*>l}l+eBl%Wp~8>%8Wr1RiVA8W zKPL;ac%M+~VTe9qgla2^incoZwX0Y-N9#G>b5V9(NuxQ_Q;60|ML)Pmoc^i7+Oc%a zE)zVMa_E1N5Bn~b#7uYv#?bci?QTgGm(QKgr4_xU94v}FISbxUkam>gUO(qAl^rww zqUjPiJVg(NNtMpZ(HE3IH3G)Xsx{}TFHTxvD$el&n)V2eJl<#-`3cSWq7=q+~h_U8wy9s*v(UL@d-Zf2?nCbsB z1u>u9?F(a$Ks6I{9GF~(I zWJoE0FqMLrU;8OK?65*A(~eU#qRNg5-a~%p>;Ye*8P9b_<944R64|`fWN8W@N}Sof z^()Ca-7WPP!*@Qyt_bBO-ux-bk%W$|B_zc|K&??%h)o_3f!(JL|A9)+@-3$H=xvwT z(8k=$GngC)Mk@d07IG$)-1A67bEn92x57n(8kZ7HMak+oRc9s~_Y>?27ZD|$Le#Ay zL+?UVYYUE)XZ!SOnqi{}@z-Xy7E}+BohSXZ%bykx);o=LT&lA}pOcoi6u#M2E6TR} zjyTdkPd(8?C*6zl!1=mdO@}o#4gM{KzGXJrt@mFtSWG#}y8C2ga>>iaQ2XX0S(`3%DDh>H;1@?&hiUOy8{kT`))qiIDZfH9rt zdX_hTeu# z0;<9XW^>Qx#SoLSire@rR0FFsqHWX;{#0{R(;0`HM>jK{uWE=k4}CLn+QYKW2{OCD z>6o`yy|v-ry;pCxgfROn4qS^ z1-)QO#i<=htR`D0X^g0ray2BWyEBQ3&|Q~H*OZZA|Kogl2%*#8ou{hV`q#MfB0AStJbC!PXm-*)2l4-@MMJ})uaVy%SB%c{ zZk{~beSaJvG4nW`y}~M-t^V9fjq3)(;Vv9pbVmZ8f;mcLdR04LVnOdI*YB5n6@R zU5!e@j$jtML=6X}`UTs#hi!4S*A>y>IE@VNk51kPHr=BzyBtIqpkZLFTpc(}OpfCEL`ei1hCp#`2VDA0xRMxJs!T+?Luw2kkvW}>En!>7*id^|%hn-7L1loUNj5GnK zOUc?)z9T5b?`!4HW7reEG<_&>MYIS=y}KS>XXSmGn%RET!d1*F$6+b+GG$uH!ZZk> zv&z{z<$crluB8nAJLDOriCE^51}Dq@(yP93kmR*|Z)(^XBIRls4jbbqnHW5K&&k*| zy-R$wx))LN!s4V}K4xqAcculeamqsoW7qYsr0mE{R5OESUVj#y+z;{sGI>L?ctdz( zK~_o3BR{;iuIfO$KYaux`lzGiw1N5$N>x==Q8Dv-!m+5a4O`ZeTOOI$(!a`h@AUAx zVM6H3L2HFE-D}tS%&I1?xrB_KP$y#$eY$V1*OpZy7{}-HzeuK*sSlW9cRRO+nOmz1nloKL&Mem z2OLUez(~I{YF^HIB&ood7Fv`!hO|wH%qO(`S_}68N7YRhd>cZdX{m+n z$AlQ;HQ9Vf2UwvSsr9DoS+=WcmyOkg|9<4g{sqA zyx-F@E(Dfc-VV#!lB=WJHheu*z4K;>yuG{WucCr$D(0Qby|XY48OzuSzx6cKVHYXp zEDH>M^9tpm?P;cE-0>d7*T4Nx%Jp-3&k+Q={Y$Yw$TV!_CiODCFnGUvp?alAhXTMs zyj4;%QDg#N;y0S*Q+SuJ4pmd+Z5ncs7(Y#PUc(lCH8|*o-(JYae0KKzK@`sfy~8`3 zSAk@FlK7+Kj=SPcYJo^RyT-Sb4Z$K?x{$#v5Nk^#%b28EXj)EoY#wmif=18Q9mfz<|=$- z%CY$+M1^5mV_|7~X;%G0k4N}n@bn>fF9Gj*K}g&Fw#?vKdGO~!(FiEcbK(`IF4L4* zUEOc^BgkyjRnQI`)EmOs1hS44e3{98FQN4KpwbkC9OFwolhirF+r+7|{AENsx~G2) zE)Q1;IxJ>?{#nVa=2+_`w`)O9t>6zS9Gj^(1ui$@C{1 zgRCT6#C@1+PYA{Ly(02bl{-btvS?j@d?Si9EO@yH}n5F%<6XQSJl*^ zbg6-WOB@gaQe>%L#r{}iWO&>&X9Y`IqOUKUX@<}bO%fCBh9Nna-6SC|5)-7BiNuEZnS{AbFLwsZDL5q{ zUPy4)wqK(X}EqISyuMcB+HhOL%H_xCzlc_lExuFr>oqnCzqa*9i=>^XOVTLl9U!Qzf>Xh zg%){k=erE$1TL!p1Hy)743*oXW7u6tA&k0Av@DGPP}v@!CA7|W587C7yzuT(H^C3m zgGp7L{HiMisz-8l++d!gjH_t2+;VrG1cgY(u@venzNOW76S|&TR$F{4SZL4jPC(pW zz2*BfZ?tzTGCp3u-Z_if6Z}Hu2EvR&e2YJVd$0QM-&u_-F~1Z6jsv3CaFB-kHzrLxNvUkGCE%#?YU8TW)5<6@V}pl+T!r@Bcg_+He#9 z17W#vHav~K`K{hf_l#KX!p>Y+SUPS>$Yz_Z-@2*c8W!Z>{PJjp3se~6h*6%rg+ATz zp;dq7`}3MIj>kp~Emh&-Uu8&ivwudv_D(KrO1nxCTfdWeuswa4waMFAISd~jsaWj# zshcMrq|IHP@rt7|9TT6~*}{MF9Dk<4W~Z#8^J|kkLPym-Uxb2pnTbVx_(3Vwi~3(X z(d%+c3*1ybN`*j;Sf;dLo3Vb$pUAi)081RpeXseWe|}6CdSd31@l{g z^a3_-3jw+!?r$YJ^6u3g>MfS`B~A7@#URo49VY)Wnks`vRPq0 zeRFn{Mf6;&(SCfR(HoGPY~;mdLNbbRCzw=4O3*wvjX6@I_ zYWVMrAEz=kiQ;fW`q7jL({PjaP0zY4KmGhcP_G{Q2H!-<#{p+*7G7}DfpZAqBdI}X zg`T_ch4t7%h~bI`fqUPd_E0w0jESM^%jl7I)WRn5n5j=EaD}E^)|3+{T}at~Hxq=B ziM)lMr%%w`W3w3$+|n$p~6`{~q?W=^!}S5z<7uJa3k)`wAG^xu<^bDfGj zRW?q9p&855Uf+4}{`k`&D|y)m!V`ZG;ZzhWiNWpIR`6%4*!=|eL7Q`ityA%<>f&?t z>|{4@%YcouEklLmB9VuL$m`8B!)kMD-2Sn~w^BX%RL+I5hdr3KO9=cQpb1O!LrfIjI2~RU5E7F+Jb@GQ}kW*yc z+UcByK5e`&NQ>x4c4VL;1d6NdtDe+-*+t@#+>Cviq9_ZU*b25ng+QSqT^@jRY=7Ld z@BU$j&f97YDt7&3@r4(_t~@G;?p6(k_I?ep?$>ft!#d=&U{2dBq5E4ur^?fw$>l4z zMWF_Zri#KZt%thV8J~;c%=Elh-E(MvQf2kCixZdHp|*nDc*nMzcE-7)=GOeWrW-LY z!p_8NRs^H2yaNn@cPCTIMTrsv=Jhh$>NBNXYp$azM}`F}drF+W+Gts0S8hb3Y7|V^ z5`i@rn|*8ZHz~#frd(2YTS$8_g38BgN1~8>$41Dj(NOuL&6MenfCb5aeXKI``p=k= z<Ul(VR5BE}QSiiHvOs)6%qVcx)CJv<)U$a8VBjqHxIvT^m4Cr%l4 z-=0`a05$?;%}I%*OrhnV`RCB~)2#9wFONdQgi?&}xZ~;>->;d|yo6+8i-*H>(w;kw z)zVyD7h8-ekf4Sg=E}_%5Biqm=8eB-EZ0Y}d00DqH9&aUM1#Tie*L*A9G3C`*_d|a zJI=9(_n!XI)tcA7#G+Q{!s@OakP2~KyzhC!fcYrt?j219^8virkt`P=-PR~_Yi$tean@3e<*cs%MZ5_O!$)u4Lm zbZM|btco6;(2@C}?~)K~gzapd5`ZLWB)_PYYQ^+P>B|%gmd?mv{Y*GS9*mM&bzO># ztHygI&xZP8k+kY-?Gra_H999_jb<7dv=I}Cgj4A88F7v3no5kkY&&6Q_Pj%_>zGvA z1X9CTAp?WAT9ohnw9yXhW=6*!-UiLRnVW-;hzL#Q*WRl_CfOuxPOHyS0O{@fE7d>> zNujGs8Kj=UAp%vWwH$-mY&U|kd@+%-|5ycVn2shi1-L2`oo;3?Cv3 z1UOz0zL0cJa(GCWu58X<3|ATR;#1q<|Kxj)Tj)n5s&Dic^zF#q<3(XJu=4XBaGp1a zYBuOEU+pwmy!@-BJQgvUDkyR=EWo>WgiFFRyzyIXLu!A&Df8j3@Xh|njhCNS`m$E~ z!zNpmuZU?)vv66#&$ICPSG?gn!JdhSPh2mDDH1dF zN^olMeDAvY96LntBzIp<+vaT@>3K7Lb+s`Yw6RF6;Zd+wc1inCgP|dJ;Vq!kvJ=NG z1=Et3Y%ksMdKw0ya|@BuQGberVr6|G&Gf6Uvng@nivMrQS{~*y zNu87t<8Dfy}#?;l+f(Vw^0jt;hzOvZlDTs~|94A3eNCv-w( zI6}+1tb9vvu;3N)^+n$U%+z!7Z85z};aAcDCO271Yjc}TWt0V8kbcvegYa9j>Mqhu zgC*tZnuxKI8R~=OjP)dyE}@`ReAAp&R>8L?Kk}3bWP}!rGtc-v{;X{Yp^Y4t4&8L# z6nz>$$Nj{&L4r$?g{+)Qn-KQCh4uY|wnf9|tnZltj;DUx%T`I)2B9iJs-q8Kp(?dz zn_2?2o$3+|Z^y~bv1L35_R zLSe(`g7yNhQ-i+FXMaA$ccY{D+w|bD{~@yfgUjo1EB2o}bS?b@v-J)e^R^#M2a??f zT)?`2U@EgZTybZ3nPLUMnw||b_{$|jbyPz{Rbkf5f49ETRA+Rx=+tw4C-~X>lDas# zGE79D0|RVxnB{eyQmuPO&TIZX8) z5Y#=|bF@y&ym|Yuej;AE#Oz^=WeW>1#q)A492_`ayBFTrrDx0?#0|>TS<*#bJW=Pr z;y>vMG;E5;{o0~Q{k!YJ?q2km6tiYwQXBokt^vv8Vj;OO=$2n#r7NL8{&#p8g%{%2 z7>M3TIo~Ctwv~qM$%i^V=e(PNqvUsqvv!>Ii>^W`L5>Zz^;afwpXVjDobIIVcV+~s zXewd(Fxsnw!W5fTN11jP&1oEngd1U>s}_?_}eN-g)I+&0N$OH5yyAIShz zx77iR{M{ZNo^r9(HQLKy+vXRy2`hRBs&N1Xu8gDCK6;43f9Uhq6HrrWH@g%4Hr}2K zH*KW4vpMfh`Q6dVS5xI_31zzI54g6+KJ{9Bhl=+yzWNRqX}?xT5fHB00Fu&*b$*n% z=x>OvtcOaaI|M)Xu5G`smo8~9Wm@R>pfW@&A}spwQp7&)h_fy7N*JU6vcf4=M_?I4 zG1~%vuFu_&ckXg#^VIOQcMRS-F&Ba!~5~Z2j1Y@&b-xvJnvlnrv0#? z_;;%ewd&k#zvX+FDozZY*!-J$2K=*@wVWGkaxy0YiDS{f;vgMXCC??Fm$dm&W|f@7E*b8akQ z2qton&kkzhrz<0h__Amn`1mZKJgbt+uxf1Hz1WV5F*^F@3=T8*6$OyqHw{*G+j(;i?olKr;D8JG{- z`pXGq}8!P8FX(q_}G zQVbIl-U@5cG2`}QBE7RxA_t#i?QJyiq~1MFL#h=PJgP6G15fc>AYQuJY*%qm#eve# zhnyT48TQ|o93o$Bq;ljH@?O&~FtO_hFyLx2;o+e#0od?Caxfv-{MkwW`#V_TRa>n z47YoPUftpc_;u!%NLn-QO_En>v(W^k*cH}8Cy}MS=C%&J_ry0F2fu$Cc+CHlV{lKHk4AWR_K#~y*O!zc^8A* zSt>`tvG*TA1Tpxi{dqSMXPYLRY#>6`v313P@qFTJXLYB2J8SfnquWEWM`-X0Y3uNe zJQwz1Jysw;Y^Vx^O30YU@4xHh2a%#A7fh!KY$ksHe-{X>ldp1s4}E&hVRm2mf0vG4 z3SJb3S?Y9c>c1-&{TBM}S2`VkrvG;X9{(_^nN%ig7ydu%{&>PrAp z6Eszz|BNqp!;Vpi*kS4wg1^cZL!Irc#P7jCPCEGmGQBB#bXXv7Of+3%O?2ua2xR;l zAMS62Yw^S~7WKGs*GSd4Z(VKc5q$xi0vYe6Iun09#k<7~m3sTNw^lKRbmWWN2#z3e z$=9l)1;WAjSRSFoJcgG@DQ*U-+#lO8o9KX$zVYo>>u4Ur`mk9cI>w`0yH$rj8*h}U zd%t!bZVqRyBeWMx>bto$P#lMjab1F1Ngn{xDDZ~B3^~a!S3!SdQ`>y+($IgF?{zSF|2y?6~_0&cId}VoUdNJ z+T>E4di$EaqQWPQE&?}i-iV54-OOUl2K0CW1IR?duZ(`{ zgQ$^_7;gXn9^S{j=>yRu8v?KtVyLmf(FMv^r1#>W_YndprbI2Rz!yUw;GCcHIWs{; zs`>9PSIj0$NuWIyU^Yceti7oE(5Pq>{r~%`nZo472+=9obaIJb#>U3NpKYj%7U4w$ zO?o7##u@ym)l3aD-82^sO((oAkSc64b7L*}-wPBafi+-G_q;ysd4W4h3m=uj=dxZA zZhyK9@W|!v7dAM7n+oH*RCWZ=mGdvbU5o?ghV1TCRCc zlIwZTc7Z40F-5qX72Ce_@H~WLQ{E#uZ(ILwf{@r&It-J3D-;=2xDeU-E%4#r7Cvp`CvcIOLkZ zas2}54!=%Q+>@^V-!N-MWjBpK1VYpzkbUForMdB#x9?-7ZA+>|pnFt84hgpl7IQ}=vBE!}o<7&cqu0}{4bB+NcBjP?<+s%a*Az(yenJaXs(p|yM z3)Coa6vLB~lk?EEu>KQvA(-@@(BEc8=G>jc>a7)t9`qxpcX~Vz|9zMPJmKYMkT}mX zBCt^Z?L0$0G-V zw<$6r(Es<6A|MdlA<1+`>;L`8FQVY>@S$$R|9$W!$;p98uwu;X|DH*hU}z5BmNYZ| z{J$$sjfsiCiJdR~Kc_q{rtkOfPwje7fb@FX%2E7U2+v_V&9 z(R?3JuMpAjnIOPB@D<=yCVSssA^HPVo<+d85CII|BhU{fq;VKZ7kngFok2CmSoEU;GP58h%{*N|3mclbs!J4b=t39{}f9mdDlc=6n+$RD#pt zJE#ku0TNCd;9)(hoe2Rz>qJke2E51BTAY60PW?t|Ft7%L`}nc52s;RYbD?&+PSiPQE2Bb*`5N}D-eU`GJ+X4Vc4 zkh=UprC|v8aN-3|`GY2RI)R);2=GEklC%0{EEbE`4>TB;L0cQ)Wf>E{+yanD++AoP z0~|B~Wfhepz*buNg+#_Vqvczom;nm}PCf&Ac_O>IyjJ~MgMiy9oAe2uhPFWs-bTx^ znoF>Qu|3m2-`sap91@k&$#*Si=2l+d3%A(3Q95cPS3LKjs%m7oD z8t}i&i_>Bl)!6a>0D+<<07B!!S1#?qSFSMxW>B3U$Z90-_iVk}xhA!ZCPeOTfZ&h~ z?j(?B=v1vg9gzt^h-OZ;nrpn?E;<74Zok&-m!>VtpoFJZd<}eczrVFVK(|i()rYl& z8H2tOCv9~>trvHIUt|X;P)T<|D{1uUoxYXCBG5d|m;Nne^z+zgCJ7|=xf%N1&OvwL znZR=M9ea>Cg$^D(sHdTvYfqD^yxg|-T&s7kdIW0TP`mc(nysB??U-aSsE7}o}BKl zX-KN^C$#oTwFY`ZO7<1cf@tk12ZfErFzueh@}CXhOUMA5I{jPLyFPF_ntHI5u%Dxu zkjcpusumdH19WVVA}YPY-idRnI0h{^Jw$-qT1bm2U?qiwF-+-6?37WI<Y!=UDi61Z6qs$Fd zB^2yhv0tV#S)rKdDW>j!Fp!~n84H+vT>us?tFv@x=ZU zWFQq3tr%?pADdXfof_JALD3ib>^y_iUMDu$6XJB@p}Jo~Ze8U~2*it!VJp700y6k_ zzaHabD|8cY#q+LJNrzmu%2jX@A>4%7>kk8q9JXl6HRiA5g*ca{(wV^tf}-3ka3w~79$3flxe zX#^vvmend_3zJE4+!YKs`VY*2sA}$aZw>yRtzGWmA^J6;@$zO^@BWw| zE870l)5D`tNjZ#6DD<`Ubi5}B??^Z$gEs_u-MAhfGnu=vp<%ie2AR`h4B2JDv({RH ze>7J_=!jEwuEALAh;qMZP|nlKr?UDh*_Z2`mp=Uqkv!3UG4@}g$ASg@ERN%nv9&Pa z4N-gn9oSdMw@qp7c4?6+)%l{2c{Oip)Qt#)zay3ChZ&r6Icy~G*d-EvCe)JY(daR2` zqe|nzT3tO=6};;jL`?&B4lVsQ38u_YLDz=a+#HYVxc7atX{`xJ>TWX9SF2uuuofvK zSO3;@hZLVn1|SF*o}mR4ifUR=;JkVKvhn4{sKvLrEhWj z!8Tu1SrVfZ9~WE}`4eB@?>GVvi+~%qt)>K#Iopc+g$6yZG2wmdMQfv{zc3{VF0hSP zz;SAc3j3mc`oa)@&hk~7LdJY;eRWlw_}kBu_tGc3R4*Sx0VZswPp`?py@T-JC!-w9 zI*1yzrS&FzGuT?`1a8C2v+TOlH%Q^1p5{xT(tq?W#8p;x>BIHV4L6np!Pt)i?IwpPfKX1{QJsvnc9gGDx2SemPRQ_(|t%n(tfcDcPm*=IdsBsqhzW~&amOmwq)*lHo<2{GKK1C zOr+gkI-ti~K&lwKnba-BIe6-EpQua;_FB$!-*VJV;IUL;*om5*o4X7(j|<%2LE_E> z?%1SIv*~Bw0q~uTM;!FC1ECpIjE3&3E9nx{OrLj>-L?P3GGYCh*ZMQg`8!D8cEeFb z-2~8%fqaWDwcAbAh0)Uekxby|7x15*o`UDRcZ91B#66bb zgCS0-emX*p%#jO)6I9*6pQzoWOFnYMZ!O1Ks-kTmFauGt#$K^dvx4#*xPDZT z*4b?iQFwqc)^BMGYa@i{uQ5Xyf|pM~F4YMr?8W`-?f^x>ZND0zWiy7 zmqLub6AtK>;>+|tL;o71bCW{@u)UJhJn!{qHES^<+J{z$-M|bWHh&uw6 zc+a0d@ZQNx5e{YEYYsFr|5b}d$>gcT0z3n($eyP zE!lJ7=KFW7z5gGbP?E4jl9P3)-a%&cr(=hCpgc#SnP8N=Xigy>MYgR$7@D zAJY%zqAKzgDK5vjXpU%tQtg-KeUMP;tG^-P0CpyS>QfBywBW4yH=ue7THfw6u!$ZDB;K{>PWRam`Ow za}CvM#`A}%K!yl(8M>lDCe$mtRBO8+m>0_QZwD%x9M+hANG9$V-WLx+y)tK3zky!J zho}=@E=z`upZ%OJe=Tr*#)c%iqRS{4KvqHk<9SHVFGv5e-TT4Ri|%?Mt!=dYg(Fto zT_dnutpmJ9rD{f{6tViLcaXmuC$aBsegT?Z2woMS@;v8vEq}qT!XW@$HuMW=K&e&Z z!<>6RDt?RT1Ss`OQ031wV2!#6)aYDxe+0Y;xP2^n({U-%d8(9tOXZiQw1>G7mys77v^TPMmYbf=>JxFfW zXOaN7uZ4AY4(TA}qSZ<3;WjH@gP_o<=ypw5dWtJZ2T!ZkkmO}zr#j4<@7ciu84y+E zf+4vVG$8J`VMx;s`}8)UltGc#c^7$NiU$&iH*JQ*Wam-I0!>69s#K6u8Ac$B3U`@u z5)v3KDL1;+@WIyA5{Crm1@UQH=Mvt~*@ORlEo|YtBo8@hUvkWTWY@gNfvQh3_Y{f{ zAmOmVys_B#a0h>IPV%YGT<)wsy%lv6z;TkQT6EY< zvRmLIG>aigNsX4YdAXKOO2XP}+A75wj=-r;riJ%ULn8nIemzpblv1fVWtj5TY$`~r zDtNFq#KQ7iE12qagxIQx^brh24)2w(%?%27>W5nik%=gDKgd%G%vv*+M!kp!2g2c) zYD-JXB_lIeF?QSvAAFSWBmW%s!{2;T6-EzI_^_%x;w64%gbZav7}X(FVpxN;Nb+A& z{LADE1pZ?8;;Ui_gN?S>kWHrj<{91^M+Xmv!z4;Y9PVSPL5?i?1~wW~)OP0CII~8< zQ!erp@mOUISVb=K@ci}!w$V#xtuAgokC@mYb7NsV&_na36xQ#JW_S*&zla}d$|0aS zkfLDidc5Xzc&s7ZyHHm*_#bp=CeM|!eJsw`9HX$M`O{;|$@0B6JVELf_`63uV$E~X zL-rI2eCfVY)8*A_2WLp{cP$YeJ3>Pk}lRZcVDH9W6+tcuyK7%O21C0D9QO zTcHqJLb;q7>1*B1c3iVDS4gu(p{_t>kUC62D9UTpd`dyZrfs<8x76OliF3!*R0w`P zLa;#UR-`XhbTyTE!Q%uSAv%q-ps}P99Qp}Ah9(+3B%leK_ySK9>Ep5}a>ED2X_e_9 zOA+A!m+N4Nl4kirX74X|c!4CI{=1KiEo{b;rh8H8?$z-i+aR`$uWJiv#G7J(s{h46ci-t?e?ke z`MN7tK#o23F;A42`td=B$0FC`ZE{TT98x@A;!>egLX}thoS*m>W%N}wrFWB^R>V}$ zHVakuX@*_&aX9iAmEH=_ZCdG$pvoNpl;Mg5Z1S-}wU?`cmA|f#17Npr9jFB!d!Fgt zm_xy4g#0Vi4Cxsqi9ASITP~^=qVUID_CbE219KTubev22w0JX!!z-KDT6hs(ivY|z z>ozlkLFe{6z<;6v=b{cEw-6B->BpjD6;ELGJ~~7mv`Q7}k`cE4X>)ddd7{u#l*piX zwlhOEoFt{RgR32leNSOKV*la8i@rkZEZHtc*DPDc`I<~CTzGq|e9##Kx*6UH^p~K$ zyi(c6(hj=FOU^2^ED`x)kj%xb^D(Ke$Fh-I44(c_k~Mu-Vj~&Pt4lyMVYP?+VUXn< zYkwB|WtAFZQn4g$m2&<>QSF8G(vQ@$0Sq;nUIbqcU!WZr>J zfB+gE7NarQw1S_J_!qsOEWa^N^e8aFO1FHi-8fc8-EF9a>Q*?`v4O;h zYKG~P9e|~;r?7tal-8s-TG-Iguv|_V-vq2Rp$VOA!%OI0Y&EBXte!{~KS>^LYeuPz zHXNkPpRU*be$I!fMsF$xT4Lp%e2RJU-P?>`amUd)G8(ly+9|`*!yz%t=%7sr7d40! z1r%lV+rFUudM%|DO+nsrPtRvCqVre_$rHdFG$JVK&|h}r{k}`fj|=}8P>KKb;^EI$ zFd0cyr4mFK1Wjkca$6pKxtzP38 z0Z-kEK;62&*#L^aI`USV{gLS>6pZi&T32r4&G!y$=kC~jGZ^$|<; zV^!&SgU$+sQn@R8k;n2Q(ws6tMyUDInOWES&dG6K`w1eF@5m8!Ctj*hll-$2kulRZ zT{=dYTReXrhV0SGFhmWipbn^DiF9#(El%2Pi3`Vc(-=Tk(27tk8d5Ws*#g~AqHdrC zW*jXa>TEkv{DP3vjC?lDQH$w)&7Z{)Fo|Rnf&2)fPak$$&t7;uP?BL`lf6``Ez$5; z-2X(Bv{s}T_cz|-zPnK4@=8DOhHu)%uv1i~S1R_gxnmVe8mfrg{#r=8mV*nE`;L&^ z7&(?n3pUj2!mVkl+L8d8oin8mKM59WK)U)cqwPRq;7 zL%DK9vp_$|b+3AIC{H0xUyVeM7BzoGA;MAdu?&7oX}5`aI_+dP_nOi}#N44rf|E2~ z{fUe@#In#pB(X-}T&{hFK0SXTwz$X!XOkMNYe1z%wCwrKEzl#40A@{?T1{?Tz-{4K zBTyH6&Sepur8Ghp25DLN^X4-op~Fs}`IHv5up!pf2@T8j0!aOT-}=ZD&eU)QB~r7dkQrm)4fU1I2$@N)-UvECJ-Z~4A7~dbE(<-Q@?m-kQ^ht+#Y5$gbA78pu2kv z%IQAH@w*cJ${B^271S z<_-AT77G&i}Ll+QljI}N~dJBJ@Ev`uS59z+!Xh#vT#^H&s@^dNa^?J z`X`+ zJQ2$G7*BH`12fOm|Atu6tBI;XG>|#;;v1eO_i{&4ba2EdNdl(}Wp;oKH3)=9Mdg|U z=Cf{%^Jz-bKh@PHuTEz`*teqdcvq{mt;Q|dQv6V-Q0 z_Bn`-k&*G|hxT6m=n6;RV>xh>v;Oz7fcfBjc9~F_1kmTd!!UAt#y>N-x}42hT%Ac0F$=yD9w=8w*>t= zKz~X=CTaSsIhD%s{61G5-3RZ-DMRL2pv7|yRGrae;R+Y`&j~K+((i>e9(WK~&XS&E zHlP=N0H6d*V)?zEQnlH|@+8a>xWSr$h{khpX4Y+3=|*}uP^7^)Vn};{gY2pkd3QPt z^KY~QCnN7yCBZojDrfkYX8qmzRJt*$4wa$H5MZa~a8qPMWzmPs9(p8XJ4aOIQ3t`$ zbd~c4%K?x}L57#`Vw${bI-m=>JsMqnL1H~{(gbsw)ZSp?Fcn^ImPra#}-iEoK7=LNe)`rMOcbXaceqGs-F=STgI!$b^(v+uCMi6a2J1wn4It}h04UZN4qFTPpXfzQ!<0ks2p~$MA-hT5 zU&sRf>*FP{tTF^s# z!5SdC0m7(v3iQmmEJBFS0Ia%80tlf7Yk=t@D0#TfO)V`Ww)*mfRR?qo7rh^ zl2I%GAR|UPdVe5^HA_8G&PERqlZW>8_2qr4Uz$g|>?hVQ7-O6eYa&dB){XubWbQ_B+{wu zkBQ&UZ4*ZG{B-om9ks+jzt#ffrA_j$OsmHqae%#ya#ZhzYJqDTO5KMxJXS0C}_p*nA`rC(w?r2YUY0)E<0=KJAG< zcfSyeUjW36b3whsTT=WcY%*8&yUC)6>xOPYe!$b-_isCF6_2bBH@`jzgFjdNDX=ZA zHwpIrPaVc)dj!-v#h~t{hM> z^CSK?iKCA!2B&=Oc7h3Qbm)8mM2eAE-aOe zfefRG`#7gsjr@3CW-z`!Bi`);NVfZM4KIgxLpuHYVg67odl9WinDM2iR;kjE z?H12Bm)=ee9{;|TpZQonlxZ8!xreSx-%ZZSk~ii#y!>H?*6eNgCxio-z(L(_?_kqD ziEwjsTWbIkjwsVZKnekjNJz>1#@~ufD~#J)YP9twEJiJ>^lxYDo&6W!kuY`VqbR^g zv>fFuCPNDs0y>*Ki$!cNWCw7;s9qr3Ts>E&!%5Z2c@%JhRex^^R2cMKC}) z@jXRsaXVeBT$Hc%KDTm3@Xu@o#^mTpg3jgufXU_qnDucIV?f2n;rdHaBbF@kv5xH1 zan9WTv_{}Ja2DTZ&!!2NfJOL&t!8Nq{cm?ms=56h0IdiSNG66f0+1J`G5X}_o6FO`NTFY*sR9|uSA7gp z`hYtLkuCOlXnYe?j`*8(NO8hJXEpN8W=2VV1&w8d$)n@(K5*>&Q;IQ&}X9iYD% z=;|lUtJL`RZ3Xv`y3#JZ?-j78!C1iA_p}dWS*1%~U(1<2E05L=U-Fs#0p1vczyNlB z6H_xYLWJ&>vA&JGd-wmY3#rdAiIX&pI0sP#R~XjC@b@VaysfDH;}_s%7-JAyhWE(Som*rGDG+kzdf*^(n7d0LcYCQR4EZZibk6kR|7z=eFw9 zQ*`k$^^PTf>tN(6O%fVBl;#}P3Ea^rIhK~!B5dX~sj~Kz*b8vPY%j8% zM6cc4vWb3I{d;GXLZK1s0Z99uKnY@kUrO!}7# zbObpP8v`OUzW%dNz@IXOz++(klko-^Gt#??fE4a!rj%o_4COD7D$ndkChcn_F*Ql> zXa7eGuL_;u`=^hE4{mbT{}vHBu&eD>WS0|a&2Qpx_9#j399`nZM*ghw1%6B}V|i|h zgAph>i(Eyrbvr?%&UOy|-sqc3jbJ-RX|f6P9su{{Mu%xH$EIj-ACV=C;YK9)vr?GT z_POo00LG5bpZfThifHhCg;=O$cH!@|@QnV}U8HxTET}aKP+NCA&Hm65p+!-8qhEPU zg1CR)-OHu_TL>H}Xpqn)@B)r*;XX3uyKZGlM5o~N$=)TqMrT?(PYYd zN>7d?xw~*HV8{8VY3vevp_gryvvQLBCbTgfU}mnRMefzYmBAT7GSs)8Z^;s);UaG& zi4|Na9bUM3WG?eYuNMnU^uagN-m{{QyM27jI@NtzI!2bSCR?D~nMAENeSe1v)M0m7 z6aY~XnxD3f&!ENHw=!A20AZ!;vPe1E(uXcKePyR<5cWot`#USlT2v>2CdwX-6K(o3 z%FJTfe<#Sc43xabXNkhe2v3ABxO4+YhoFpj`R?^J?3D0Q+zh)u96E_v05~SpL@=b} zkaPcuRgwPcUH`%YkZ@gS(D-2=Aog+sokhHqgIsr$b$&6XChtp9GU2Pzckjh!+gx!h zf5QRm5LA3H+IQ>-xsGmhs&z2f|M<7ax0b8@T#b1XK@a|+--w`^?P@ z7nGePrYAiPJ>}TEijz*6IRI_$Ff|*90-sI*_4CA|Tkdxn0&7IKOBoU6sU)_TeiH%h z3uJ(H8?k^0_})0>4Di1SM)|GhWuS-Jq#!Fhq#>hSfE4(~zJHoCt}BPB!E4413z+*V zOiY^o-V4qp6g!FDA!yRKN0^*BZhUawH7)Vo9#Yr;!oXO~>9>1k^0Hd6VKna^MD6B3 zRp?AMl-_v}J6R}1D0LcS*X^hAS+{3{N5Vh3%rg?NcjOq6)UpcTGy&TGX@D}%%MEzg zp*X?q#c+K7(fNd*4WDF8f*}8wy9q%Vda#a>zVlZi9fiH?<8!c+@B`&8wh@~BLnI5_ zDI{?;0_Ij@UyDNZ!ZITwk~fKxZc2y0=-)b-;^ZN5FuPQrPhuEo#a|}Ef9$$lP*6`u z%;&4aI1Q{2$-jj(e`YGiOXKRi=`EJWrR2X_tT9(2o_Htg)F2h}>G|NxSL~>2#zhhJ zUy2B3z>$dhL5V*>I93<|wJ^+c3_i(0LgG7-*vPMFRm0#pSLRJ?$qVCH=oxjMV=5Y$Y<~mQi6H;1{nR z3<2oCxQvWQAPIeQkRqTD7`5Y5QmjV!xEWqLvnUxm3hxuZ?x^5gHlt2*!$}boCBwY+ z`+@lW#1Gp~GyAwB1`nR{M2+Zo*QZlNNRN#p|Jyc@EamAkz5_k>??vbRii!ZRP|-}2Vi#=uAJGY z;QzanH*X5~h@Yl%Ap`kuxGh~PDZ3;u>>q!=_fkj;itrZO8>eC7h);v$xiRPY zqT=Ch5_^iyHScxZkBH`%DouVg8!d%gQYtV?SsXOS!U_5hw;C<{cc#K3C|-ON7XmT5 zG;H&u9O)gT{l3oX@SsF=+o5;C;EU4$x#dfHOwHv;iSa6!9#N@=>^EN>_68*2F8zioW92W-I|)D8s_}Ig^yh*f)||(Z$ulBiTlh_s+OYMJ{kvM zLhx9~Y2?q#6BLlg|2hXOGMg{eWbgUREz*kpUl&J)GOjLp7zMC$wR?MSWFQ>p_d2b) z5=uoSVBwTF{4%@RBa;?&4Y?oYf9Pa=pklm_ zFGwe)oyRh1%C!EgS)ACMg{+t#ir}MX6i*Sb2Dz+WGC{mM6CGfg;4Qvy=1mCJcQS^ z-3%8I{0ClObw|O$S}X2FCjrRHT5ra_SaMdB)Q*|Nu%ppaNc{rl_lPN8`% zT9KJRiTg9$RTXkN6Ms*f!g+sG7vLhoAlwI#Hbn@oHDtToJAP3NGUh2ZQGBojUo8{v zAEEC3*0f!YXwT%Um`UEwYa3Mgna){{U*&lJF1)-n>^HN=(4QBy{>q6`13Ss(#EfGiR3RqM&64&iDCpjX@{>x3_It1SEw? zY5>NyO{`jF(ET{KlhpDTS?D?jvB7atBazds?5_nCU5x5Dmy%4wuO+ts#Bq`cfl=rZ z+tsKL5v&YiEEyjBj7}rqAOd+xjJece_>vN_%??9`mlpH;^|UhC3XauWE&npkJH#Y@NYx}z zhcP@(N(26ZH>p7tYVaSl#eo}UuRAPn4==y2GwG|TO@?X>)ijqd zX8RwR=c?NOBzN)Dd3&m=YJc>9{?Pl;VC3h;=_E8>GkdJP7frE05S@3c^#y#xi!(za zrC*uXeHxLk&Wz7+4m~Rc2FBNXPLzPaKJ3L45Gt+T5=M<`BQ_z5v(Wl{tOhOFZC4S( zczne2zAjiDsbE$@n>)Z{@$27X$!!d+{O2=J^+Eu9wxn0HK`%9mr!QIsyDe~;9s+58 z1epoYo3*0}Vo>OiSJ*O}sA~OepA_ z4i<32u4YEs{j0>Kbf8$^K>fMQSP(zbCS&TCwvRdCNStAu#fw%DH5fXa?VlDDiMsjx zzLrAEP6gyr^hrREueKRyoRU=^&i%>zN_f}iMvDSgk0IPo5_$MfcjS5%AO`LS;2W1$ zc@e3Za{K%Y4}i2jUV{y7IvRjAOI@CZOorX}{!Aq&ZatoudtD!g9j0s*SyZfQXJCag z$;j`Y@nR??9(a9S1-nki(*a*AFajLuV@#x+Dr*k{e)b|7Y03LP(y5?roBqZx>7mb) zm2guW@f7lfhiQJYg zfu{YcHS7fnp`SFBvFE|HPl%A_imrk^MW=)Vaqpk}nPLCw3PK=|Ndp)iLR693ow1@T zZk0}r1oUKaR0B}>=lwLHS!;+!Ua3H#)IPaRnNpo1cSKA?lhV?z94$Rgoa}X)P}S`# zI+46vN=Dtlg8&Z0>zGgg3cy~#Gu6u>)4Jr$ZxK}{^_9sFpd)6$M8^L2b>4KtS*%4| zZ2mk07Z&TUL;7f(4r=x)co+GK>T@*{G8tZU2;<2Gxf$Hcj|Y~$>}ByRk@+tShFHSL zk9)7Y2A|-8E$3(lBKn$E5)qVyZYr!o67lb~??n7U>Y$veW<9Sdzl~VT=6p4OWTrE! zw*nrgwlQp>bW^mSALo-)J3q|ge)T&VIPbG?0a7vt*YKA4OM}Cv&l!hJ0k&z64;e%^ z)@9z8ODSnsVln{EM*)K1_e5VT`R`KnMfTboyJXA-VZUbxt;|+;sz^FXQE&B#{77;i zXx95`6Pq#BL;V(gN5@e;YI#1<0XWPzZC-4mL9>O#+-Eooi4Fh zT(9I)tpIXF`glxqJ5X|vjV3Yfwy$F1G!r3wdmtP5ZyID(;k$($yi_x zhx3PKDw@%W%Tg9c<%9g}$!EC6p%&ohB~jphD&pw_lKM|eb=KwpATBAm*8_+O-vC1X zC^Ch5asOJtKnF~zNI*Y#KBEIrOk2KEtUw5aU1Fvhc@Tx76KyxjM6s(&mLC4??9Mbq zS-%zy`iy)ye?s#9X)N|zhrR(`mIYj5c*!uhNbPPa{Irg-7Y{)m1iOQmo{p%~crtr1 za$Z-r95UQbU_zqCEr1I@Y%QWge}(o>+fydqb*0l9NR11Sl6FZd zkH6|vPw!)03<1kb*|A@HUaoH zyEQIZ06!HH^EZIm<2jUioK$E|QppjDsH`+Q=_KXC{_C=fecf&0>8xf?i+ZS zb%f`J_`*x5-xVWAdaya*MOJ#dsym3hAiVC8<>gM}?%N>^1QU(;Qpx1Zeps3 zh~KGYtqLKnS9ILd|7g4${Gm#FXZ@oz=tEs~H_)6M^jE#|67Fkvfk>0a@wk+*^7~10 z*Z>Ex$v9woEl@9(=ikL29(-{)@E}Bjr(nl%ZUs&Z1k((r+_5{SJm6+W59p7-Esf7 z7XT)rdWKg3zaZIJrV0;lkOF%<2&j|l0`6K>AQ3#vXfT>2wQj6i`A9~;!}m6;w!rXP zQYnymQUBGCEw4;-1nc=HXL!JoTobwf8_G23!14~&zUVsSVfi}m?Nx!{{gzlJ({J%n zpRpf-z>-w*)dcB;`a0v`;>r_O=M7pPay&OgUJ|1(CvJw==UbrD%!`Wf0>r6_4gio3 z?$z`U4hFj_2&%=9(NKH)+??NBp5dR&+{*H`@=h}?ZQxx77OQ@5p{y1+lML%$Fz=9V z3h>xFtrwgwBoRtnmw2d{SKZ5UScxh*t?(N?f7d(7a!B5_w-jM!6znlMn{dPna1-p& zbB#_k-2dtJa0f!e1 z5<$%g$s6WW7C?p3pT=Q+G9`hvbyNrNG`D}wZ})O}L5ha4$(lJmjvG11VG4y@AJBiy zJ|i9fVm&c-g@1ET2)%i{7!urS-V+H9FWrL4vX|>9cz>R^Cj!?VK-VU^4twm`o5veq zz*3f8sT|F?GE{l2cv0p5sN|)ei=yP%7g$g?lBY#YFgtdat(n36+cG#ZvLr&L-VezqX-bDG8rl7_=Q=wtt{I z$=uC>bc>D}Gdxe{4j-4lU-x@lSl0O(Sn(uM;=l4hNLXCF1qo$W9qY_WZ3n?Xp9pt% zw`mT!uP0a9(!GgH?Rdfxep`N>>5U&KT+%WpV4P11DeiY)RaD)w3lE-_e7SbXVaM5T zKy76oh;2>c8%xHoEs-LbNjg4o&Ak&SA>vfJVkipj*a#dnC{B)zDIe~#d7XZt224T! zTpi7rDy7$dR(?oE)6@UDBXH&t1W+(QzQ;vThkNoBaK468B+=~XP zPXA1?WC^Lfk2_Y!F8FlgltG4g8aLp9HZcXO^cMf8kzuntnsn72tD|Yxa>Y;Ln`+p# zdI>o^0r~*A-5U;UDtpNL#_>KEdkU$jm6;GzX&~ViHo;436$?4tu$bZ-{On1du%R3Bj4-t4c#l zXV4DE{!l1U9G1~9Nqvy^I+2qD?FK~qeG?BU1W|Q_Q0u8ZsBM!P;+7AMAWJZhqrvq@ z!dQ!{|5=I0C8ke{smkrE$crGbQQm?cUWKS)2Os^QSas44rG=-G&8P{ zk6%FjS%f^#UM{epMa?^%DX`zFT`Zee)q?*UUW0>iohw!hIhF{b${f@57@`vC(*0rbW8xl|Qc+{3#Eh!kveJ~Jc~_wYrQ zn9sRdsmHmJa`~{4SE^X}o@V<~TM8bfNU}f<+^-A3nr)G#O0R3?Cg+zP9J6 z^v?T39aa#RbQ{ei?rrM=f>Q5gV67@R>97Fz zESjk8JZ3zDpC=JvFj@RAX+S3y!{Na=VRu69dgni_ zbN}FdG|cx{Y?;>Wp5jnrn)#-lZXD%3K@y+xJzhypw`jAP= zTk7(Q_Iz8}mxv0$2n{T-+uMR#=AWgzK6fZ(V(>~nYLkyUL#QAU9b9z{WtlxKjufGZ8R`>_%cWZQ#cEm}Y* zOgs2(k_M4a-%W9AQ1N_2kwrW#@r)rT#(a!SBMcO2A=5o~Hl`JljJ~`V&8rhvwb-p}0-j5uSBIL9XT{n3%%eF4>bLb%2=ypv=Hn19Ix zGFH9(uIIAlm69O)@m^i-bP7Jd0LA+NeL^Sz*u?&r;?T3C>P(Lc*gypz565Z!OQzt1 z2NpWpncS?DFsXW;+XLN@Mh5bH#@y!lxF%DkMDvq{u7deCG9i~>mTT*#dXeawF^ZOz z6$1&A6e=RU(|BX_c)hoYD_;dxzr&t#-IMSf%8_p%5mD(JOs1hYT=4jAW^OQ^F~FdW zw4PsoJl+_;$5(PB8nVxT@r1l$aHz=7^hSNj?bd4D`JLYom|y;~=Y0@H+Z zUQP|8iKplIbv8HftYz;E`O{Xh2-9N7-E_?gdvJ|zV8ZnB`X8o>yB^kdd5ohOq=s`p z?73W>J?Xd?x%f!YGfJfN_lZOkpE}j5dg@kX#_ge(i(AD_nY&dQ9}eI=sE>o(n%4em z95m8@F1@m#4!+88EnovNV(XhgG@`P81GNvkq04fg1#o<@l%~HvhaAwx6>JG&S`RPR zn1=x%)+e7NP5MIy8Q)+--6KhgLbOkX?U}}=I;_vIh$JSON zD70Qs5z-g@D@H_^V~T%-?zrWap0jG-Z_CnV8{PfUAxZ8}1bM7lN@>JJI*j{(YTh)R z8t1zzZeXAd)&CyOR!W)Rj_z~+HHpJkP$>DJCvye^WfyGIqdcUdeS8xV#O@)cRS?GZ zr_K}&ku9Q+7S89dP}x%}fgJgGE{p6b}b5LPS{8y}IusK))X4A`^}0W2Xo}JxKVx+2Rb=9ORHR z1KNsqTe~9GM5K~R3&_|ip?~RH7@t6f>SauRnA1O~YJY-c`Fb(@ycz%FxfVNs(~2 zXvu&%K^_+tMVv|QLSdzb@$2{d_)}G0%)p#WVWGl77=!mrHJ47CQ6$i46CyjX5Q75A z+ftr&36gwH%$#Kr^_3;$F@tx$P$Q$BxDo5AmCrB zsi?Rpyo)^vl-}f$O$>s>Q&AF3Q3tCNGlAi%I}KmeJ2;eO=%R3^Onok|G<3HaK`q)7 zLg?rJ8LS4vzo6__Wsj$RN=yh+EIhwp)N{p{WVrRJD0;=^r^{F>b2JDHLmw-i3Rk;2 zghBkdav*KdHN^Us_}bm9q9uU1i>b3*))wxUuH}&|d;G5+6bz+(DCuy1am-zhQO6WYDa)&+{#T z(x?VR-ONsYZ^8Ck zr+ZaKQc7aULT`8~NVTfH?+umq)Em`dE3v%37qqP}FBQH}k*MkKYm^^;*D%aF-L8Xc zQwA#HmtH;4Uc-E!&dKBH_ck2(>ZFLeWPnEU+SP_PhGI2hN4D?utemeyXXoZji?73t zC?@espq8iT?L7xp*>``Y4M2}Ak?n&K7!we70BIsyhj~0->q`ZCC)0A>lY&yIv7IYo027p+Fpioh2oX{b(k@672 zO3l8HETIs_qwl$o4eR#JKR6ga6i~RAt4b9KR5dcxVw~%BVwdK!MezMEeM2{PEb%l?9Hn(KH74Ae)-8j@T3PJ@M{1!+xd-ZD7dko|qNFukRkB|-? z6R1~t9pH$0>d7LiJ?JkQj`J6BM;HTNBsE=X$U|Re)Jh9Mo}u9A7g+JfW+zZ`uIM$0 zqvi)cLZy-{tP6_z!J{yB=JZ%Zr)e#Ce#yQJ3uv$*^;nTyq*S_cSm$dwKA zzq&1;5EI8$yI%c$o=)d4`#5W}A8oQca|7~YDC*acf_xM@iF%EwlB_><9bcSV8|tk0 z#&iHt8{oWtU%14Ji}V-sq6FH`5{EPVU4>KZ4X&fMBtyEIJy!d78iql2A!MHN^3GvH zU)7EL=nNfJy6#uerV1&bc6~~!(G_A}@1VXCvw8Y!Khf<5#3Bcb&X}ZV9ZO&eC#G5> z98dnRZ>>o#*=x_hPuBY0Lh3YWR{c)#&8|4o~tiM@&oNte)TP7AVp~T|^Qy;J- z)Vhqzlk5fPmE06PW%X=7hXThFV7mwBO$ag+cgO&eET_&3 zp|-D2cP7_Q=vX>NsF4o0?<(9b$o+Cs_-7N++$KwBbMe0kxm z@g+(sQ}ESeE_q^p+Z+zChF&6iRB{}-K!gB5Irw zj0ugC77zB#*Z}d#C&4%$I!!zu)lrZ|Jj8HHnn!gY2hjeS5rN0zx@PtaHwGJ1?w`}G zT~fUx@RbeI9=G5U2sdh#y1j?#QuDN!sXxT30VV)&D>1)XqSWFqshHqS$nOG+t-66ZeRl#_w#Zt18_3x2)R zh$M?rtYTV{wxp7ntXOEHPKg6V9)G6|P@>r#E|Aq$s&|CdO1}}R2?dSAS_BsRUYS0e zfGn9^tjX!<;;tfMdBwC###`LCZV!{Yz6VJ43@A+j!nnsZtSL^byO{n+Fk?}quNfMh z1(o&~o_;HX+C!VPNT@lKK2@UF*wjv#d5(juzHW~db&U9yH@Mv!{uV%V9jJ?%)v_2(GAonos@C8s+i zL!{irsZNx=*VR@xzW#>DwPJfsMGsp2A~%foeM*_cBHo zY!!m%9mle{h~j_*7GTYSq0~~C640CH7qQ84SYm#uKc-P9>cv=q2HVlsd?p@x(XWy= z1>7#t%}DPO?jiX|E$cNjGD{Z4v*4Wft$y4~>QaNM7$n&3YDgQrtY4BqJEB(9V-XKV z+!S*0jgNjKlA9bsmCQLFd!!3glHYCR$OJLj@jB|%yuQ>Ih_qOZzofLsO z#$kKWjrm~VLbFjY<6x4=@447RYPyR4@2ZNH-;cCx8pso=t1?W?U956_g6TR30bgVY zU}Ho)9+DII@!Z7zBf(~#dJV(XKP;?dn{jn~k0V}k5efo5X%?~j>_LQBn~<#=Aa`if zx3v4{=r(eOl@VdG&4wx|it2B!;|kI{Vq^BKap=ahnr(jt%SY$&yQ=Bc+Pdm_vwc;T zcM572x#jyMFeXC4JV1Iov0GjJOi7l!ylWT#n3HLQG5^^ZEZ_WEbn0s-UFXp_mn(!l zhNnP1TrPN#354iIRb8p1wDe*g?tck0?2l+5{W68@G!NNMUtk1b$k9hzwO+} zYmZ@C!Uyl-yF`4KHoH35y}boe80vIM**^--yvVE2=k}!-vc?_Vp#P%rO7D$h36kN) z$vsFb8Wlh9&KQ~3kBf0S&-sk2{ra?2R*ZV2*jRW|;F=WbrJH2dC=cFm6i@ z%TOz!YLU=sXhIN~Qct-e(Bq7C&z5*E+5M?xyj#937n@NiUHK8!g>d$Ff^NqN;oN)Q zG?08t3LkMcCtkeS`y>Tr28G?gr(xI%d*$E?wZg1jRkZ4A3!>dvSs=S8?JbKyi4$s> zM=EFcXI)WYUgDg}0{NtAQXxw*Y%t0Tor^NJn-(GgeG4vkoeZ_zz%-5ttui5C%6SW? zMfH8_3g;#PE>z&^C_-8(GiS!xZ9pt{dss{mB>ZJLp*Xopn~rt>akGLsZ@=)zvz*3- zsJg}d*OR#2Fb&*{F8ZFpH6&D)NS2SJL?(5au|m0UEm1*h+XA(i_?qvTPo}BWraAJ`SN(8(Jyn6Rq#CSHcDDJw_@W+r^CL{_S8Osou(K3+`tS)+*baHz zcnWJ~@3UTehguiK4z&%e`g_`xpB3Uz4 zCZIMml;nyMrJ;E!ivw@`S)B!=(sW|ye$?bv`WbtMyh?ExU~7}q38Ae;Ae01$%U}8? zfQvhz#)8Q%R_wHP`^be}gcjEcm4!C8K0|T9ad*JGOI9S2Q<@X=E z5l>nGDSTVhmBcU2&dPZQl$Z;(CMImRm}=!vKjUjdrR2$B6Y(QfKX4)9G0CfuXoia> zYus0Sik#|;{=(*!8HDjHp>almRK@l$H^>(NH1&OTN8?e$yTnk@O__-Nr|N3sRrug> zPF)gGGFl`2ejUUI)vUquN?|yzwIHrE#H$l&+la<+EmY2FOQ(3`_iT;q6MJ;xR&;5K zlTCd3EF#O0aJI2`Q?kF2At`xt{906Phh5&k@b*C;zI9A(E}F3-S6$GhNa)uih3YkF z*+4*X2CPU;;C;%8fC=FiNbI`l9`*?V`FJq5i8$#b@6UMB8TU$Q!l~-dSV0?tByc)x z8UFJD$5{x*EpA5odpN9iN$*{s9ab|h8+(B=0Z(y)N9mVjnN!nYS;|`2rgl)}BI(@; zR@e28?^6p>V>kCThWX_WXA33wL`OcA;lWfX!*oenZED`gn={RUT+-`;v>btCLfs}ODq3pH+C4#fLf|w88FZZ93`$wm4e<5UQ^Xz@BZIF--O^o`Uyu?3L7BHPv`an@gGSm1gXm zxx?YT3!yL4WB#ozqNqkyWW~){uafd*ua(W^^xnU&+lfvIERKIZ2SP+iI$9O?bCvaf zMecUAEO<`jJiv`|GG45}+(r{`=>>&$HNant=RUYt_I|g?lJxIjd063ywDB%XvenlH z8GYqHg=f8AsB+Y{kTc!g|F}M=ZZ?d?J?E&ZB09K7(8b+{QUim(GsXExBv=m`a` zCK9@VCwPMmWDA7@S-6zk-1tBm6_YU#y7dxsZL+I+`H}?&94nLd8xqD1#j+Fi-sFL}f`YX-lZ zBY_C0jluogici z#Y%W%qOy0L`xHjbC&sxnUEVc*x}17;JQnCG0%v&qVI@)vLV!h~W-9oZS4w+I8xDQI z3d?;bE{WKWB?g*h-@?Jc$5zaJtt$5B)HMyK_mmN}EF2ad99{~A8zGak*!$WTyR>5D zkoxPr2vDdtUA}q}9cs-}-sini(`gtudhFRO{QHT?*n4q%~-TbP<=Q8f>mwWL8 zMq6DJp-b%{5cIRyREai$CEP=GBqC(^>ZC_-BLco>WH^RWRUg5ODUXErL(%SN>X#%J zJ)y(;cinIqypH726hH}`NX^K28b>e?SEdLg{S>XP8UlOyHIqbGmS5WMrg#MRdb_hPBa>fi#ZWfdt<7u$U7pL!)ZeCGN&efs>j0U&ei3 z#j;62)9Dz|3F*4rG!~I=ng*>S+4YcQGIaP3}7p$G;qZHBIvZ%>Fun;i7BHk z=(Vbwq+w5mLT-xF61nEi*Y=vg4iyD1f*RU5l@K@CB!!0g(RH5&5l?9QSSmq_|C2%> z1^EHY{4Zsrh+tbn5J(j;hX&8Tcu@KNl2LS{VIXeHqM-*7GJJ!@`KxalZ3A=<+L;U&X^`sScEdrH@ z6@r*^NM?BAO<{EQ-{8$>Ape(n;2SCP%9?=l8@HTdv8SU+@775s-k_CZLsDh#h>PF;S|h=Exjp`2z2b7?k(_yuKW1>stham&6U+zc29m% zbyHF}lD2FFYJkmMOd|HhZz-fm4_7DF;96bs*Ws{ZB0D1BiigjB_9SDSbgZMILfC}N z`5k903fSAx&ymVDst@bB+S_v|6n|KLdY(;+qmr)5i^M3AARq0$GR<{*qFJ{>k+{bY z6*icn|AbODu6ToT(z%s-E;#-c_ODE3{g;h^(@HCHETOH5zQ_u!Qzy?@i)QGO4qF(Q zIIm#6lJYtAtASP<#c3zt|KeD?%<^fZS&TCp#|bZoJ^`-#EQFtFn>3_;7t{5Af&qOr zLlvZ;(UEXFn+cIq_cAQZ?Pv+m)O!0zSN&aatwTl@&Dy#;{@Jza@K#z!!t7_5Pw@jk zf1We!)Wq_gHG1P+1WO{Lg70vvzjoR&TWamG$jxV{r7N{9x8BuUOqN?~EM1`P*3eDcKMcstIQ{>DAy*96c}|JM=`KR~Qvf?j%k%aQNT)*G$J8}m<6 z?>=?*GP1L)RH=(TD4yb^>BJU6|5{ou4f8BcKJ2JiyPVx7p01XRDN7p_R~3>n$HV$h zJ}sjhnO9(HEo)K%2wb-+qk*O>DAvMujX--qzv~KR~lgNvO6hz9B@_FoM zG4)zHKSc?*{{9#H!c6a$Ib0I|x~iYLVE89>mI5g72|rNJz=dWt4JG>kEi|vBpMTMc|)R2o0?wP1P;|CQ8kfP+EE7mrs@!rhLBf@+U3H0X5N(>3i_L=hE z#CZt8WI38kAG6C}bo)Ic_1$raVuW#4FOPpRVNNvj9QvcMR&YUWLB)UYPDf}mNCf!{ zoH#7M6kvQ;?O3t-syRypgyZ3vw0*3(!<>L6(N)OG6MooY8?Dp3nT=t}7Ookou;(3QnR7b%W7_z~r-B)RoOJv3NM9j5yM(~& z$E<3LhmFtn;fuW=^7S+^{o+=Z8?8wU@Xx$)YvG6nvwKs&y+z#x)zydj`?YYPP$<7pwGPv6V;fAhboz|7dHKgk@k6Ex4&^&r|bW!I`4R@-}jGmj1Ec2 z_=xQ6m62VC?95}2vS(3AMj0m~8QCLcj}Ss+k7Ly#d!$IoCPa~S=y#pZ@ALirK41Tw z$K!aMxA(c;wY}OG(L2R zF0{?_u+MxamwadS+)yA5<&w3pb3-JS=-!sEqH=>sLDYj zM2mWKYkz;Abjb@(L4kUDOzRh4saK)yPilAO%i%8}d> zn$ab#qmL??s<}1+8+wN{&8F77{V zg34hPW^u_vYkm>=3GJoJ)#O!?0Ru*MMMr7ZR4nkiyT6D!S&`(H)n$9XS1P^63Qq64 zOPyh+iH%xIp?kR8^2^}-=05ACfO^Y@*viue7sXol?C&w=rt|7$6eqtoUr>+vOBtrQ ze6?uC5@yLTM>;xEXefyLb@%X~B{j;ba9Rm}=Fh}47dGo>^EdjdGx2uM|)ptx4c)` z?HW|Q>Fu-dg>!G<-Kjl z;uv1c&{j{&zY2Lb%Up9|Qsx5}tAdB)u4Topvha0PA1NV~ug~P~y-XxAby{Q9KY<^P zo2!!l)Xq74LzmfB{i0S4ThS{?hqWjwO;)?2wkw(jp=FQt5^vC+%?K#gDSb|sSyT*m zDQ^KUP`ECs|5Uu4D6Vk?{MVf_yhpU&ekiwkm6=4N-VhM>HT@lTNk7cVE7@X++`lyYTRTnjhe5NZ<9{nY35HUCcW1YCVi_xYLAuOttAb^*-q&BKxJVMi3&yzNf3*?RvBjPubRC1R z5vK;0G-ytTmu3}ua&mHE;%Fd!_-hI%UF=pgZ}c&Tf^ph!?unFr7xDmnA3H@izP1H_ zY+dtXB2FMqpZd*3B2nkD&@+1lJId>)H?E#xiSCy`h|af(@bl-8on-8a$m%S#tn<_b zERM;A^?2VSn0ITS6}<82_td#osN36q_6kV_9|s&jV<2*iyUBY+g+R;i?Pd!W=@DrF z&LDjJTA%i}-WkUA=_a#&cbmKY(p@E2++a|=yBW+3fJ{$+71+(Uqu+FH9KzF z8dacOyJ`V{5@uO@)8BmGTY*CY8x+05Pa5gaztTnWUUoMOA<6vTsq zImm5Aw-KI>2q`hKIP%kMIzpyp29(LqPm#8Yf2Ro94;;=@>&3?sZHl*W4;_Hd!e_?| zem_7BG<;I58AWil$n=?X+lH?)0^Rvn0soQrUbIQrTy&fTd*a1=hgi8sG*Sv@8%i*< zbGU{Nq{_ERF7}ce%j?ioVTHmQ#yhO*6x2MZ4|{vUj)1@!+w;V zDW#;6r_(;aO>2Mw@f-IrK@x95ww-LGXGpmW z`Zb1BY43+5S1{Wk4ayG`4kf$xkpS<8zj*cgnssCcmjs95 zy!NY66LMP>Vp66@AmUFJFY8Ig5$T>)`FNXwc<=zzQAD?>PvhJJB}1v{vosMa)Bc%; zalxQAn?hHhw1Fqc2&fp8!Fk6h`02HP<=hBYxV~oc(-BF<6yP_ro(JAc((!~Ou}!7>OGsU+_;^@};Xe0zb|P1fN~ApUJ-?81C| zSdGaLj+s*qA0P4QdY*#Fh%OpS%|iOgGb{nSCI!>s%3Q54K4E)t8&r*BdD6F9c1$~B z_>qei_;#1|s&{NB*?dEXPq6u6TK5-O?%k*-vn8hcN#1$d8x#fFTP*V4#Vloo<4PA4 z?yi;;y?hwgBP(tVlM7h=j3~~p{s5h%4xFqs-`58)4$C}QbkSyOfkGseW*M0pInN`j zc@r)YF4}}ZG0qt`GWu!*^GeXMpE&@&S#rY*keV1b`FMyN5Yf*8T`bIYv7^^_kHWqU zh_|nT@VVZMjEt7{#&6tB+<}O(;9sO~o6Fc?+Reqk<(aU751$RGRTu8n456UCRJ)?b zMM8H&dD;mJso7psHLPg}fWK!R?D1Him*Ak_&}MLp!?*;ZhP}jnuk4d@)+;#YL*KfB z2mKKEgb4T&J-w0TzsTIp*Y~px|1-LjlE1Ipl)!GXH6|{V&|{CdB^Ka+@BH-s$!-x# ztGRO&*J#--FHP6NxBOr~4A!4X)DlFr=V=l;qr^3Rl2pm-BU?XPF_9{kW7IDqNS8$F zKIh>@xd$7nzSiBcVc?_VH7I+Wt>`aNe!ay~~kdn@|jG`wry{`e>8!*x^5vM8G{0ZgfANy? z6F^iH?70Rio7+>KO;57?W+R6>Cp|jxk!o6=ba=xbAhGBSPy*)8jW-B3A%$t48WGZB z2D|ugFcj>0X9=!aVeyu^q;2{e{*@pHL%=@xC0&f zENR#8m$WZ(g__Z^08g^!&PK!1*|iGyN`%p*V3OrA=&_|`&m>g=RIc*A+(v18Yl(VW z&{0Qh(R~fyW6X&PuZtiAvcG*3O|sq+cHgjQ;JYoXhvaq|!v(shj{t{TP;bIu*X*F4h!zxrQA(2QhW zu3>VPqa7fZoKh4w61bA!^9Cd?C7ya38+;PjOJ$9{L^#7PL72#Hxy^P(hE>{a9;y1( zf=xvtbi&PB)+(I2mq5%*_w&06sbUi)n}7KhXLtpRMBdYHPd{%UU+kZGh#Q2ac@70d zzg$41B@n<}PRG<)x9^Yy)y(*UtXhz%S#-;YSPNXAR)BtE8XD8wtXNLYyn%jeW3Jz;F`SQKJ7%G#XIVR zTCvp8=3^lq+{YkLdqmg4b4oCk_w@jW6Zdl_lg6w3#-8ZzCVkI;hCRE zLb@(9&hTH&n3x2OZBBc`*UpVjy>H|~d2b2msMw}A)xJNjF9e^sthiU&v6Lt|Qs1rj zF;LFb-8lFYU{~KQkC&#kM|qk1%lMdENPOJ(+{}{*{q>ZkIY)i#EwAiC^(wi3?(SIn zB2XyYT@fW2iukmkzB3NfyMT?sby+v6zr?ZT z)y_`>i4qM$aTp#9ze#~K0_Qp_&=FBxT+F{JS^YJ>J?M(zVBrDBrQgt#i0)m25UB`9 zyVw(H1PRRw>yjrc%4qqLUGY60+HL)F{NO!r7a|Ibrn-JMZ}36j-{PEh!fX(-(_x^2 zyJj${VjYs=IBN4SM$No%A_>)=M9x8JsAp4RcsQ2NeMa} ziUyZ^lUsA<)`+r7tZ?G-@!_pEvTk6ClTd`NtxyQY#l_AnRUy}-ef0h}-FT-Fo6Al# z`~NCFZE0YD`qB31(kV7Y+0}hxR(j@m%H##MM(!CovSf{{-fR)mPT}j#vLDM6 z12^;3IeDp@g}kQs2C|f%r;6FU!lN7(?0u4zU$OSy7Pc7#u<_M>O8Nc>lcPqVzZ!qN zV+`RA%J_CN>R*4oQ3%IHvbL*S!g&Oti+K4UNqIPI^Cr}H#-?8%{7{mvo&ckp;-v+S zgbm6^8+a{tFGBhGdu!sFG9x6+Cxwr;p`+TMe^Pw3Kl@p`$Qlwc$;lysYT~7RL@2X~ zNfnDQV76#XrXLr6zT;ej+KTOQSg@c5ZDrUpaMlU{FJhUMcIG}eR_JkLwRN{6o!xub zeRD`1-YI}5A;Jyu{z!fzenkT1vewe|d&TeYUzCYhX+SN9+RvO+ordb zpPWDnZwd$t8*gdK9r3Ciq5Kh&gf|H6&jy;~=>M&+jmEEdC30ZIQBnvepcL^yys8qlt1Wjg0f$uQj!IM~Cqg zNeVx)B%N?(L}UNiPJK)l5xYM5#whqj$V21AjGlKp%H+3)Guv>rrH1*B+->>1lC70Ek zooaE1Fun_?@9@i|aOQsH{HQot4^}SjA552ad9Hs^CGUz(zSjWt%}NeOG*#t>gBR~F zLO4-MuGP4W+KU#T;%zgLi`;#xoPn%;Q%StKc~Ck}OEV_CrHiibO%r2JIl*6`$+^n7 z^2&C3fSrpK>mB(!JYD>3Zs731iYA0;-Lnk|lrNbDJjYA?(gl|hSw^UYRk|15<^`SF zo|*mGQ+2oa`VuV+VFKyt57_xT;+c@7t{|&5?Jte(WFpw(UUcVh@y5#wit?sbv??YjGi#&pl) zF)B|x4VocpNC%VBk>Z3cAZmg&5=qWvi3B7ApUQ+AWW-_|u=YDyEZ7sY1x(G2W{Sod=$_>~5vy<@m&Eyy(@s~$mW|@--sml|=kCvLA K>MIr7kpBU)$i%t; literal 0 HcmV?d00001 diff --git a/vignettes/plots_files/figure-html/unnamed-chunk-4-1.png b/vignettes/plots_files/figure-html/unnamed-chunk-4-1.png new file mode 100644 index 0000000000000000000000000000000000000000..2224319c60717ae0646d3f702b31065946a07498 GIT binary patch literal 39399 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�S9`Op zrA*O_XFMZ;{zg`!hZHZ%!##e@Z6+#%k1j9v%(1YmJcgnK;mMMBqN5YQ{NzE|OPR9q z3M==ZhkQkJ{JKU8=03e_!3t0JX_MT+LA?qIWJAYr#EnKRmz4>$KYLYswEY5XN!BL0 zFC5Bl|0+Yfy;bf3R~%O8JC00$UBMZA&r+R(yHpK`#Tw#VvP=mQ1T5q>SzT1s)YKBo z7OFnD^`5aMZ)%Yrxh17;cpPqI&^WK})rlEl1s<-%0T!sbz`-#r3hQ^siJX?YN}wTA zV%TK_U43Rc-SF%gkAc~evH{j9kg3bpMKTe5WOTw- zNrrDv{n-sErseQ$fF?`rU>-BUo5me0jfo+x^;BR~&QoRoipi3CqgVv(40l=B8S6K9 ze8*kB+JBqjtm7+(waydQhVNaC!nlFH+`5ys#JZi>7Y?w&B|#AiQYkBet}p3W)skOl z<~cL*@4pqy#GC_4V~xKGwlrJXb?Oih5?Y&H$92n7^TK+gumv)uSpZ;(@7vk5Qi_O( z3_4KN)0u+Bw+^-|T&%}1E|SEtp*+gIJobFhi+Pc4c<}*r2aE25xAJ=R*naj|&S!B! z4utl~`*hC){sE^2U)TxHg5c$qt=w*LwMlUhtBWNW5eyg zS}O2o@Qj8M;hb(5`A0^FP}WMAdCop1Mx*1%==1w4NDO{Lh5Hq*e}^+hNLGLcm?@?( z{6BwN9_fugO1%7Ira}IGPz2IDk*XN{6HD-W=KY_4^&x|3?&!9T2caz%{G+OT@m!Ij HWyt>m`Ru)~ literal 0 HcmV?d00001 diff --git a/vignettes/plots_files/figure-html/unnamed-chunk-9-1.png b/vignettes/plots_files/figure-html/unnamed-chunk-9-1.png new file mode 100644 index 0000000000000000000000000000000000000000..5f30eea2d6d3c2912cd437959ff28c5eaaddead6 GIT binary patch literal 30088 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 Date: Wed, 1 Jun 2022 17:24:10 +0200 Subject: [PATCH 4/4] 0.6.7 --- DESCRIPTION | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 91d17e4..7c31dfc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: rats -Version: 0.6.6 -Date: 2019-07-18 +Version: 0.6.7 +Date: 2022-05-30 Title: Relative Abundance of Transcripts Encoding: UTF-8 Author: Kimon Froussios [aut], Kira Mourão [aut], Nick Schurch [cre] @@ -22,13 +22,13 @@ Imports: ggplot2 (>= 2.2.0), rtracklayer, rhdf5, - wasabi, GenomicRanges Suggests: ggbio, shiny, knitr, + rmarkdown, testthat URL: https://github.com/bartongroup/Rats, http://www.compbio.dundee.ac.uk BugReports: https://github.com/bartongroup/RATS/issues -RoxygenNote: 6.1.1 +RoxygenNote: 7.1.2