---
title: "`r params$title`"
author: "`r params$author`"
date: "`r format(Sys.time(), '%d %B %Y')`"
output:
  html_document:
    self_contained: yes
    code_folding: hide
    mathjax: default
    number_sections: yes
    theme: yeti
    toc: yes
    toc_depth: 2
    toc_float:
      collapsed: no
      smooth_scroll: no
params:
  title:
    label: Title of the report
    value: RNASeq QC Report (produced by hermes)
    input: text
  author:
    label: Author(s) of the report
    value:
    - Firstname Lastname (Department)
    - Firstname Lastname (Department)
    input: text
  input_summarized_experiment:
    label: '[REQUIRED] Name of the `SummarizedExperiment` object to use as input'
    value: summarized_experiment
    input: text
  output_data_file:
    label: '[REQUIRED] Path to binary file where filtered and normalized `HermesData`
      object should be saved'
    value: ~/output.rda
    input: file
  min_cpm:
    label: Minimum CPM for each gene within the sample
    value: 1
    input: numeric
  min_cpm_prop:
    label: Minimum proportion of samples with acceptable CPM of certain gene
    value: 0.25
    input: numeric
  min_corr:
    label: Minimum Pearson correlation coefficient of CPM between samples
    value: 0.5
    input: numeric
  min_depth:
    label: Minimum library depth for low depth flagging. If `NULL`, this will be calculated
      as the first quartile minus 1.5 times the inter-quartile range of the library
      size (depth) of all samples.
    value: null
    input: numeric
  top_gene_n_top:
    label: Number of reported top genes (please provide either this or `top_gene_min_threshold`)
    value: 10
    input: numeric
  top_gene_min_threshold:
    label: Minimum expression level threshold for reported top genes
    value: null
    input: numeric
  pca_assay_name:
    label: Assay with normalized counts to use (`cpm`, `tpm`, `rpkm`, or `voom`)
    value: tpm
    input: text
  pca_batch_var:
    label: Batch variable name used for coloring samples in the PCA analysis
    value: SEX
    input: text
  cor_method:
    label: Method for correlation sample count vectors (`pearson`, `kendall`, or `spearman`)
    value: pearson
    input: text
  show_output:
    label: Include all outputs (plots, tables). Omitting them can be useful for debugging.
    value: yes
    input: checkbox
editor_options:
  chunk_output_type: console
---

```{r setup, message = FALSE}
# No further user input required below this point.
# Developers might change code below if needed.

# Define name and version of this report template. Version should be updated
# in each release.
template_name <- "qc_report"
template_version <- "1.0.0"

# Specify knitr options.
knitr::opts_chunk$set(
  cache = FALSE, # Set `TRUE` to enable rmarkdown cache.
  cache.lazy = FALSE,
  eval = TRUE,
  echo = TRUE,
  message = TRUE,
  warning = TRUE,
  error = FALSE # Important to have `FALSE` here in order to stop after an error.
)

# Load all required packages.
library(hermes)
```


```{r}
# Load Data and get object HermesData
se <- get(params$input_summarized_experiment)
stopifnot(is(se, "SummarizedExperiment"))

# Section 1 - Pre Filtering, with added QC flags
control <- control_quality(params$min_cpm, params$min_cpm_prop, params$min_corr, params$min_depth)

object_original <- HermesData(se) %>%
  add_quality_flags(control)

# Section 2 - Post Filtering & Normalization

object_filtered_normalized <- object_original %>%
  filter() %>%
  normalize()

# QC reference default values: Reference object for standard quality control setting.
control_default <- control_quality()

object_default_qc_flags <- HermesData(se) %>%
  add_quality_flags(control_default)
```

# Template and Session Info {.tabset}

This template is `r template_name` version `r template_version`.

## Session Info {-}

This report file was generated by `r Sys.info()[["user"]]` on `r Sys.time()` in directory
`r getwd()` using `hermes` version `r packageVersion("hermes")`.

## Details {-}

```{r session_info, results = "asis"}
sessionInfo()
```

# Dataset Summary

The dataset used is "`r params$input_summarized_experiment`".
The data set was composed of <b>`r ncol(object_original)`</b> samples and <b>`r nrow(object_original)`</b> genes.

## Technical Metrics {.tabset}

### Histogram of Library Sizes

First, we check how the distribution of library sizes looks like across all samples. The median library size is <b>`r sprintf("%0.3G", median(colSums(counts(object_original))))`</b>.
According to [Standards, Guidelines and Best Practices for RNA-Seq (The ENCODE Consortium)](https://www.encodeproject.org/documents/cede0cbe-d324-4ce7-ace4-f0c3eddf5972/@@download/attachment/ENCODE%20Best%20Practices%20for%20RNA_v2.pdf "ENCODE Project Homepage"), the sequencing depth/library size is usually determined by the goals of the experiment and the nature of the RNA sample. The minimum library size required is around 20-30 million aligned reads.

```{r genes_hist_libdepth, results = "asis", include = params$show_output}
draw_libsize_hist(object_original)
```

### Q-Q Plot of Library Sizes

The distribution of library sizes is then compared to the normal distribution. The linearity of the points will suggest if the distribution of library sizes is normally distributed.

```{r genes_qqplot_libdepth, results = "asis", include = params$show_output}
draw_libsize_qq(object_original)
```

### Density Plot of (Log) Counts Distributions

In this plot, each line represents density of expression of all the genes within one sample. Lines that deviate from the majority may suggest inconsistent read depth or technical failure of the samples. The peaks in log2 (count) distribution indicate the log2(count) value at which the majority of genes are expressed.

```{r genes_density_libdepth, results = "asis", include = params$show_output}
draw_libsize_densities(object_original)
```

## Gene filtering {.tabset}

This step is necessary to flag out genes with low expression. Genes with very low counts across all libraries provide little evidence for differential expression and they interfere with some of the statistical analyses conducted later in the pipeline. Therefore, these genes should be filtered out prior to the analysis.

There are many ways to filter out genes with lower counts. When there are n biological replicates in each group, we usually filter on a minimum counts per million threshold present in at least n samples. In this dataset, we choose to retain genes if they are expressed at a counts-per-million (CPM) above <b> `r params$min_cpm` </b> in at least in <b> `r (params$min_cpm_prop)*100`% </b> of the samples. These thresholds can be modified.

### Stacked Barplot of Low Expression Genes by Chromosome

This barplot shows the chromosomes with their proportions of low expression genes.

```{r, include = params$show_output}
draw_genes_barplot(object_original) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))
```

### Genes with extremely high counts

```{r}
object_tg <- top_genes(
  object_original,
  n_top = params$top_gene_n_top,
  min_threshold = params$top_gene_min_threshold
)
```

This bar plot shows the shows the expression counts (y axis) for each of the <b> `r nrow(object_tg)` </b> top genes (x-axis) with.

```{r, include = params$show_output}
autoplot(object_tg, y_lab = "Maximum Count", title = "Top genes")
```

### Genes with high variability

```{r}
object_sds <- top_genes(
  object_original,
  summary_fun = rowSds,
  n_top = params$top_gene_n_top,
  min_threshold = params$top_gene_min_threshold
)
```

This bar plot shows the shows the expression standard deviation (y axis) for each of the <b> `r nrow(object_tg)` </b> top genes (x-axis) with.

```{r, include = params$show_output}
autoplot(
  object_sds,
  y_lab = "Standard Deviation across samples",
  title = "Top variability genes"
)
```

## Sample filtering {.tabset}

This step is necessary to filter out samples with low depth or technical failure. There are three approaches:

### Low depth samples

Identified either by lower quartile minus 1.5*IQR (default) or user-defined threshold: <b>`r ifelse(is.null(params$min_depth), "still default here", params$min_depth)`</b>

### Correlation between samples

Humans usually have a similar RNAseq profile; therefore, correlation of RNAseq vectors between patients should be high. If a patient's average correlation score with the other patients is lower than a threshold (default = `r control_default$min_corr`, <b>`r params$min_corr` </b> used in this report for `r params$cor_method`'s method), it is likely that the sample preparation went wrong. We are flagging such samples here as technical failures.

Correlation matrix between the sample vectors of counts from a specified assay, containing quality flags (`TechnicalFailureFlag`, `LowDepthFlag`) describing the original input samples:

```{r}
object_cor <- hermes::correlate(object_original, method = params$cor_method)
```

```{r, include = params$show_output}
autoplot(
  object_cor,
  row_names_gp = grid::gpar(fontsize = 8),
  column_names_gp = grid::gpar(fontsize = 8)
)
```

### Boxplot of non-zero genes per sample

In this plot, each data point represents the number of non-zero expressed genes in a sample. Samples with a lower number non-zero count genes may be also of interest.

```{r, include = params$show_output}
draw_nonzero_boxplot(object_original)
```

# Filtering and Normalization Effects

In this section we look at the results after filtering and normalizing the RNAseq counts.

1. Top level <b> gene </b> numbers

Total number of genes before filtering: <b>`r nrow(object_original)` </b> <br />
Total number of genes after filtering: <b> `r nrow(object_filtered_normalized)`</b> <br />
Rate of passing: <b> `r round((100/nrow(object_original))*nrow(object_filtered_normalized),1)`% </b> <br>

2. Top level <b> sample </b> numbers

Total number of samples before filtering: <b>`r ncol(object_original)` </b> <br />
Total number of samples after filtering: <b> `r ncol(object_filtered_normalized)`</b> <br />
Rate of passing: <b> `r round((100/ncol(object_original))*ncol(object_filtered_normalized),1)`% </b> <br>

## Technical Metrics After Sample Filtering {.tabset}

Here we use the counts assay of the filtered object, i.e. less samples might be included here.

### Histogram of Library Sizes

```{r , results = "asis", include = params$show_output}
draw_libsize_hist(object_filtered_normalized)
```

### Q-Q Plot of Library Sizes

```{r , results = "asis", include = params$show_output}
draw_libsize_qq(object_filtered_normalized)
```

### Density Plot of (Log) Counts Distributions

```{r , results = "asis", include = params$show_output}
draw_libsize_densities(object_filtered_normalized)
```

## Principal Components Analyses for batch effects {.tabset}

Batch effects are unwanted sources of variation caused by different processing date, handling personnel, reagent lots, equipment/machines, etc. Batch effects is a big challenge faced in biological research, especially towards translational research and precision medicine.

PCA `r ifelse(is.null(params$pca_batch_var), "is not performed because 'pca_batch_var' was not provided", paste("is performed with batch variable", params$pca_batch_var))`.

Background: If batch information is provided in the column data, principal component analysis will be performed below on autosomes for checking batch effect. In general, it is a good sign to see that data points from different batches are mixing up well. This suggests that the batch effect is negligible.

Note that genes with constant counts across all samples are excluded from the analysis internally. Centering and scaling is applied internally.

### PCA before normalization

Here the original counts are used, after filtering samples and genes as described above.

```{r, eval = !is.null(params$pca_batch_var), include = params$show_output}
object_pca <- calc_pca(object_filtered_normalized, assay_name = "counts")

autoplot(
  object_pca,
  label = TRUE,
  label.repel = TRUE,
  data = as.data.frame(colData(object_filtered_normalized)),
  colour = params$pca_batch_var
)
```

### PCA after normalization

In this analysis the `r params$pca_assay_name` assay is used.

```{r, eval = !is.null(params$pca_batch_var), include = params$show_output}
object_norm_pca <- calc_pca(
  object_filtered_normalized,
  assay_name = params$pca_assay_name
)

autoplot(
  object_norm_pca,
  label = TRUE,
  label.repel = TRUE,
  data = as.data.frame(colData(object_filtered_normalized)),
  colour = params$pca_batch_var
)
```

## Comparing QC results on samples

### Technical failure flags

We list the samples where the default technical failure flags are
different from the resulting ones, using the custom correlation score threshold:

```{r}
df_comp_tech_failure <- data.frame(
  default = get_tech_failure(object_default_qc_flags),
  result = get_tech_failure(object_original)
)
```

```{r, include = params$show_output}
DT::datatable(subset(df_comp_tech_failure, default != result))
```

### Low depth flags

Next we list the samples where the default low depth flags are different from the resulting ones, using the custom depth threshold:

```{r}
df_comp_low_depth <- data.frame(
  default = get_low_depth(object_default_qc_flags),
  result = get_low_depth(object_original)
)
```

```{r, include = params$show_output}
DT::datatable(subset(df_comp_low_depth, default != result))
```

## Comparing QC results on genes

We list the genes where the default low expression flags are
different from the resulting ones, using the custom CPM and proportion thresholds:

```{r}
df_comp_low_expression <- data.frame(
  default = get_low_expression(object_default_qc_flags),
  result = get_low_expression(object_original)
)
```

```{r, include = params$show_output}
DT::datatable(subset(df_comp_low_expression, default != result))
```

# Output

The used `HermesData` object called `object_filtered_normalized` has been saved in `r params$output_data_file` if that file did not exist beforehand.

```{r}
if (!file.exists(params$output_data_file)) {
  save(object_filtered_normalized, file = params$output_data_file)
}
```

