#' Check whether pandoc and pandoc-citeproc are available
#'
#' @author Charlotte Soneson
#'
#' @param ignorePandoc logical. If TRUE, just give a warning if pandoc or
#' pandoc-citeproc is not available. If FALSE, stop.
#'
#' @keywords internal
#' @noRd
#'
#' @return A logical(1), indicating whether pandoc can be run or not.
#' In addition, raises either a warning or an error (depending on the
#' value of \code{ignorePandoc}) if pandoc or pandoc-citeproc is not
#' available.
#'
#' @importFrom rmarkdown pandoc_available pandoc_exec
#'
.checkPandoc <- function(ignorePandoc) {
# nocov start
## Initialize output to TRUE
doRender <- TRUE
## First check whether pandoc is available
if (!rmarkdown::pandoc_available()) {
doRender <- FALSE
## If pandoc is not available, either give a warning or an error,
## depending on the value of ignorePandoc
if (ignorePandoc) {
## If ignorePandoc is TRUE, just give a warning
warning("pandoc is not available! ",
"The final report will not be generated.",
immediate. = TRUE)
} else {
## If ignorePandoc is FALSE, stop
stop("pandoc is not available!")
}
} else {
## If pandoc is available, check for pandoc-citeproc
## Only do this if the pandoc version is <2.11, since
## pandoc-citeproc is not included (or needed) in v2.11 and later.
if (!rmarkdown::pandoc_available(version = "2.11")) {
## TRUE if the available pandoc version is not 2.11 or newer
## pandoc-citeproc should be found in the path, or in the
## same folder as the pandoc executable
if (Sys.which("pandoc-citeproc") == "" &&
!file.exists(file.path(dirname(rmarkdown::pandoc_exec()),
"pandoc-citeproc"))) {
doRender <- FALSE
## pandoc-citeproc is required, but not found
if (ignorePandoc) {
## If ignorePandoc is TRUE, just give a warning
warning("pandoc-citeproc is not available! ",
"The final report will not be generated.",
immediate. = TRUE)
} else {
## If ignorePandoc is FALSE, stop
stop("pandoc-citeproc is not available!")
}
}
}
}
return(doRender)
# nocov end
}
#' Generate alevin/alevin-fry summary report
#'
#' Generate a report summarizing the main aspects of an alevin/alevin-fry
#' quantification run. The report generation assumes that alevin/alevin-fry
#' has been run with the --dumpFeatures flag to generate the necessary
#' output files.
#'
#' @param baseDir (Only used for alevin output) Path to the output directory
#' from the alevin run (should be the directory containing the
#' \code{alevin} directory).
#' @param mapDir (Only used for alevin-fry output) Path to the output directory
#' from the salmon alevin run (should be the directory containing the
#' \code{map.rad} file).
#' @param permitDir (Only used for alevin-fry output) Path to the output
#' directory from the permit list generation step (should be
#' the directory containing the \code{all_freq.tsv} file).
#' @param quantDir (Only used for alevin-fry output) Path to the output
#' directory from the alevin-fry quantification step (should be
#' the directory containing the \code{alevin} directory).
#' @param simpleafQuantDir (Only used for simpleaf output) Path to the output
#' directory from the simpleaf run (should be the directory containing the
#' \code{af_map} and \code{af_quant} directories).
#' @param sampleId Sample ID, will be used to set the title for the report.
#' @param outputFile File name of the output report. The file name extension
#' must be either \code{.html} or \code{.pdf}, and consistent with the value
#' of \code{outputFormat}.
#' @param outputDir Path to the output directory where the report will be
#' generated.
#' @param outputFormat The format of the output report. Either
#' \code{"html_document"}, \code{"pdf_document"},
#' \code{"BiocStyle::html_document"} or \code{"BiocStyle::pdf_document"}.
#' The file name extension of \code{outputFile} must be consistent with this
#' choice.
#' @param showCode Logical, whether to display the R code in the report.
#' @param forceOverwrite Logical, whether to force overwrite an existing report
#' with the same name in the output directory.
#' @param knitrProgress Logical, whether to display the progress of \code{knitr}
#' when generating the report.
#' @param quiet Logical, whether to show progress messages.
#' @param ignorePandoc Logical, determines what to do if \code{pandoc} or
#' \code{pandoc-citeproc} is missing (if \code{Sys.which("pandoc")} or
#' \code{Sys.which("pandoc-citeproc")} returns ""). If \code{ignorePandoc}
#' is TRUE, only a warning is given. The figures will be generated, but not
#' the final report. If \code{ignorePandoc} is FALSE (default), the
#' execution stops immediately.
#' @param customCBList Named list with custom set(s) of barcodes to provide
#' summary statistics/plots for, in addition to the whitelists generated by
#' alevin.
#' @param ... Other arguments that will be passed to \code{rmarkdown::render}.
#'
#' @author Charlotte Soneson
#'
#' @details When the function is called, a .Rmd template file will be copied
#' into the output directory, and \code{rmarkdown::render} will be called to
#' generate the final report. If there is already a .Rmd file with the same
#' name in the output directory, the function will raise an error and stop,
#' to avoid overwriting the existing file. The reason for this behaviour is
#' that the copied template in the output directory will be deleted once
#' the report is generated.
#'
#' @name qcReport
#'
#' @importFrom rmarkdown render
#' @importFrom tools file_ext file_path_sans_ext
#' @importFrom methods is
#' @import dplyr
#'
#' @return Generates a summary report in the \code{outputDir} directory, and
#' returns (invisibly) the name of the generated report.
#'
#' @examples
#' alevinQCReport(
#' baseDir = system.file("extdata/alevin_example_v0.14",
#' package = "alevinQC"),
#' sampleId = "example", outputFile = "alevinReport.html",
#' outputDir = tempdir(), forceOverwrite = TRUE)
#'
#' alevinFryQCReport(
#' mapDir = system.file("extdata/alevinfry_example_v0.5.0/map",
#' package = "alevinQC"),
#' permitDir = system.file("extdata/alevinfry_example_v0.5.0/permit",
#' package = "alevinQC"),
#' quantDir = system.file("extdata/alevinfry_example_v0.5.0/quant",
#' package = "alevinQC"),
#' sampleId = "example", outputFile = "alevinFryReport.html",
#' outputDir = tempdir(), forceOverwrite = TRUE)
#'
#' simpleafQCReport(
#' simpleafQuantDir = system.file("extdata/alevinfry_example_piscem_v0.6.0",
#' package = "alevinQC"),
#' sampleId = "example", outputFile = "simpleafReport.html",
#' outputDir = tempdir(), forceOverwrite = TRUE)
#'
NULL
#' @rdname qcReport
#' @export
alevinQCReport <- function(baseDir, sampleId, outputFile, outputDir = "./",
outputFormat = NULL, showCode = FALSE,
forceOverwrite = FALSE, knitrProgress = FALSE,
quiet = FALSE, ignorePandoc = FALSE,
customCBList = list(), ...) {
.alevinQCReport(baseDir = baseDir, mapDir = NULL, permitDir = NULL,
quantDir = NULL, quantMethod = "alevin",
sampleId = sampleId, outputFile = outputFile,
outputDir = outputDir, outputFormat = outputFormat,
showCode = showCode, forceOverwrite = forceOverwrite,
knitrProgress = knitrProgress, quiet = quiet,
ignorePandoc = ignorePandoc,
customCBList = customCBList, ...)
}
#' @rdname qcReport
#' @export
simpleafQCReport <- function(simpleafQuantDir, sampleId,
outputFile, outputDir = "./",
outputFormat = NULL, showCode = FALSE,
forceOverwrite = FALSE, knitrProgress = FALSE,
quiet = FALSE, ignorePandoc = FALSE,
customCBList = list(), ...) {
if (length(customCBList) != 0) {
warning("custom CB lists are currently not implemented for ",
"alevin-fry QC reports")
}
mapDir <- file.path(simpleafQuantDir, "af_map")
permitDir <- file.path(simpleafQuantDir, "af_quant")
quantDir <- file.path(simpleafQuantDir, "af_quant")
if (!dir.exists(mapDir)) {
stop("The provided simpleaf quant output directory doesn't contain ",
"the `af_map` folder; Cannot proceed. Please run ",
"alevinFryQCReport() and provide mapDir, permitDir, quantDir ",
"explicitly. If produced by calling `simpleaf quant`, the ",
"permitDir and `quantDir` is the same and is named as `af_quant` ",
"under the simpleaf quant output directory.")
}
if (!dir.exists(quantDir)) {
stop("The provided simpleaf quant output directory doesn't contain ",
"the `af_quant` folder; Cannot proceed. Please run ",
"alevinFryQCReport() and provide mapDir, permitDir, quantDir ",
"explicitly. If produced by calling `simpleaf quant`, the ",
"permitDir and `quantDir` is the same and is named as `af_quant` ",
"under the simpleaf quant output directory.")
}
.alevinQCReport(baseDir = NULL, mapDir = mapDir, permitDir = permitDir,
quantDir = quantDir, quantMethod = "alevin-fry",
sampleId = sampleId, outputFile = outputFile,
outputDir = outputDir, outputFormat = outputFormat,
showCode = showCode, forceOverwrite = forceOverwrite,
knitrProgress = knitrProgress, quiet = quiet,
ignorePandoc = ignorePandoc,
customCBList = list(), ...)
}
#' @rdname qcReport
#' @export
alevinFryQCReport <- function(mapDir, permitDir, quantDir, sampleId,
outputFile, outputDir = "./",
outputFormat = NULL, showCode = FALSE,
forceOverwrite = FALSE, knitrProgress = FALSE,
quiet = FALSE, ignorePandoc = FALSE,
customCBList = list(), ...) {
if (length(customCBList) != 0) {
warning("custom CB lists are currently not implemented for ",
"alevin-fry QC reports")
}
.alevinQCReport(baseDir = NULL, mapDir = mapDir, permitDir = permitDir,
quantDir = quantDir, quantMethod = "alevin-fry",
sampleId = sampleId, outputFile = outputFile,
outputDir = outputDir, outputFormat = outputFormat,
showCode = showCode, forceOverwrite = forceOverwrite,
knitrProgress = knitrProgress, quiet = quiet,
ignorePandoc = ignorePandoc,
customCBList = list(), ...)
}
#' @keywords internal
#' @noRd
#' @author Charlotte Soneson
.alevinQCReport <- function(baseDir, mapDir, permitDir, quantDir,
quantMethod, sampleId, outputFile, outputDir = "./",
outputFormat = NULL, showCode = FALSE,
forceOverwrite = FALSE, knitrProgress = FALSE,
quiet = FALSE, ignorePandoc = FALSE,
customCBList = list(), ...) {
## This function was inspired by code from Nicholas Hamilton, provided at
## http://stackoverflow.com/questions/37097535/generate-report-in-r
## If possible, set output format based on the extension of outputFile, if
## the output format is not provided
if (is.null(outputFormat)) {
if (tools::file_ext(outputFile) == "pdf") {
outputFormat <- "pdf_document"
} else {
outputFormat <- "html_document"
}
}
## Check if pandoc and pandoc-citeproc are available
doRender <- .checkPandoc(ignorePandoc)
## ---------------------------------------------------------------------- ##
## --------------------- Check input arguments -------------------------- ##
## ---------------------------------------------------------------------- ##
## ------------------------ outputFormat -------------------------------- ##
## Raise an error if outputFormat is not one of the allowed
if (!(outputFormat %in% c("pdf_document", "html_document",
"BiocStyle::html_document",
"BiocStyle::pdf_document"))) {
stop("The provided outputFormat is currently not supported. Please ",
"use either 'html_document', 'pdf_document', ",
"'BiocStyle::html_document' or 'BiocStyle::pdf_document'.",
call. = FALSE)
}
## Raise an error if the output format and file name extension don't match
if (gsub("BiocStyle::", "", outputFormat) !=
paste0(tools::file_ext(outputFile), "_document")) {
stop("File name extension of outputFile (.",
tools::file_ext(outputFile),
") doesn't agree with the ",
"outputFormat, should be .",
sub("BiocStyle::", "", sub("_document$", "",
outputFormat)), call. = FALSE)
}
## ----------------------- input directory ------------------------------ ##
## Normalize directory paths
if (!is.null(baseDir)) {
baseDir <- normalizePath(baseDir)
}
if (!is.null(mapDir)) {
mapDir <- normalizePath(mapDir)
}
if (!is.null(permitDir)) {
permitDir <- normalizePath(permitDir)
}
if (!is.null(quantDir)) {
quantDir <- normalizePath(quantDir)
}
## Check that all required input files are available
if (quantMethod == "alevin") {
checkAlevinInputFiles(baseDir)
} else if (quantMethod == "alevin-fry") {
checkAlevinFryInputFiles(mapDir = mapDir, permitDir = permitDir,
quantDir = quantDir)
}
## sampleId must be a character string of length 1
if (!is(sampleId, "character") || length(sampleId) != 1) {
stop("sampleId must be a character string")
}
## --------------------- custom barcode list ---------------------------- ##
if (length(customCBList) > 0) {
if (!is(customCBList, "list")) {
stop("'customCBList' must be a list")
}
if (any(is.null(names(customCBList))) ||
any(names(customCBList) == "")) {
stop("'customCBList' must be a named list")
}
if (!all(vapply(customCBList, function(cbl) is(cbl, "character"),
FALSE))) {
stop("'customCBList' must be a named list of character vectors")
}
}
## ------------------------- output files ------------------------------- ##
outputReport <- file.path(outputDir, basename(outputFile))
outputRmd <- file.path(
outputDir,
paste0(tools::file_path_sans_ext(basename(outputFile)), ".Rmd")
)
## Report
if (file.exists(outputReport)) {
if (!forceOverwrite) {
stop("The file ", outputReport,
" already exists. Please remove or rename the file, provide ",
"another value of outputFile, or set forceOverwrite = TRUE.",
call. = FALSE)
} else {
if (!quiet) {
warning("The file ", outputReport,
" already exists and will be overwritten, since ",
"forceOverwrite = TRUE.", immediate. = TRUE,
call. = FALSE)
}
}
}
## ------------------------- Rmd template ------------------------------- ##
## Path to the template file
templateFile <- system.file("extdata",
"alevin_report_template.Rmd",
package = "alevinQC")
if (file.exists(templateFile)) {
if (file.exists(outputRmd)) {
stop("There is already an .Rmd file ", outputRmd,
". Please remove or rename this file, or choose another ",
"outputFile name.", call. = FALSE)
} else {
file.copy(from = templateFile, to = outputRmd, overwrite = FALSE)
}
} else {
stop("The Rmd template file ", templateFile, " does not exist.",
call. = FALSE)
}
## ------------------- Fix output file name if needed ------------------- ##
## For BiocStyle::pdf_document, we need to supply the output file name
## without the extension
## (see https://github.com/Bioconductor/BiocStyle/issues/73)
if (outputFormat == "BiocStyle::pdf_document") {
outputFile <- tools::file_path_sans_ext(outputFile)
}
## ---------------------------------------------------------------------- ##
## ----------------------- Process the arguments ------------------------ ##
## ---------------------------------------------------------------------- ##
args <- list(...)
args$input <- outputRmd
args$output_format <- outputFormat
args$output_file <- outputFile
args$quiet <- !knitrProgress
args$run_pandoc <- doRender
## ---------------------------------------------------------------------- ##
## ------------------------ Render the report --------------------------- ##
## ---------------------------------------------------------------------- ##
outputFile <- do.call("render", args = args)
## ---------------------------------------------------------------------- ##
## --------------------- Remove temporary file -------------------------- ##
## ---------------------------------------------------------------------- ##
file.remove(outputRmd)
invisible(outputFile)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.