Mercurial > repos > iuc > edger
changeset 0:9bdff28ae1b1 draft
planemo upload for repository https://github.com/galaxyproject/tools-iuc/tree/master/tools/edger commit eac022c9c6e51e661c1513306b9fefdad673487d
author | iuc |
---|---|
date | Tue, 07 Nov 2017 08:18:14 -0500 |
parents | |
children | 2a16413ec60d |
files | edger.R edger.xml test-data/Mut1.counts test-data/Mut2.counts test-data/Mut3.counts test-data/WT1.counts test-data/WT2.counts test-data/WT3.counts test-data/anno.txt test-data/edgeR_Mut-WT.tsv test-data/edgeR_Mut-WT_2fact.tsv test-data/edgeR_Mut-WT_2fact_anno.tsv test-data/edgeR_Mut-WT_anno.tsv test-data/edgeR_Mut-WT_filt.tsv test-data/edgeR_WT-Mut.tsv test-data/edgeR_WT-Mut_2fact_anno.tsv test-data/edgeR_normcounts.tsv test-data/edgeR_normcounts_anno.tsv test-data/factorinfo.txt test-data/matrix.txt |
diffstat | 20 files changed, 1576 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/edger.R Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,718 @@ +# This tool takes in a matrix of feature counts as well as gene annotations and +# outputs a table of top expressions as well as various plots for differential +# expression analysis +# +# ARGS: htmlPath", "R", 1, "character" -Path to html file linking to other outputs +# outPath", "o", 1, "character" -Path to folder to write all output to +# filesPath", "j", 2, "character" -JSON list object if multiple files input +# matrixPath", "m", 2, "character" -Path to count matrix +# factFile", "f", 2, "character" -Path to factor information file +# factInput", "i", 2, "character" -String containing factors if manually input +# annoPath", "a", 2, "character" -Path to input containing gene annotations +# contrastData", "C", 1, "character" -String containing contrasts of interest +# cpmReq", "c", 2, "double" -Float specifying cpm requirement +# cntReq", "z", 2, "integer" -Integer specifying minimum total count requirement +# sampleReq", "s", 2, "integer" -Integer specifying cpm requirement +# normCounts", "x", 0, "logical" -String specifying if normalised counts should be output +# rdaOpt", "r", 0, "logical" -String specifying if RData should be output +# lfcReq", "l", 1, "double" -Float specifying the log-fold-change requirement +# pValReq", "p", 1, "double" -Float specifying the p-value requirement +# pAdjOpt", "d", 1, "character" -String specifying the p-value adjustment method +# normOpt", "n", 1, "character" -String specifying type of normalisation used +# robOpt", "b", 0, "logical" -String specifying if robust options should be used +# lrtOpt", "t", 0, "logical" -String specifying whether to perform LRT test instead +# +# OUT: +# MDS Plot +# BCV Plot +# QL Plot +# MD Plot +# Expression Table +# HTML file linking to the ouputs +# Optional: +# Normalised counts Table +# RData file +# +# Author: Shian Su - registertonysu@gmail.com - Jan 2014 +# Modified by: Maria Doyle - Oct 2017 (some code taken from the DESeq2 wrapper) + +# Record starting time +timeStart <- as.character(Sys.time()) + +# setup R error handling to go to stderr +options( show.error.messages=F, error = function () { cat( geterrmessage(), file=stderr() ); q( "no", 1, F ) } ) + +# we need that to not crash galaxy with an UTF8 error on German LC settings. +loc <- Sys.setlocale("LC_MESSAGES", "en_US.UTF-8") + +# Load all required libraries +library(methods, quietly=TRUE, warn.conflicts=FALSE) +library(statmod, quietly=TRUE, warn.conflicts=FALSE) +library(splines, quietly=TRUE, warn.conflicts=FALSE) +library(edgeR, quietly=TRUE, warn.conflicts=FALSE) +library(limma, quietly=TRUE, warn.conflicts=FALSE) +library(scales, quietly=TRUE, warn.conflicts=FALSE) +library(getopt, quietly=TRUE, warn.conflicts=FALSE) + +################################################################################ +### Function Delcaration +################################################################################ +# Function to sanitise contrast equations so there are no whitespaces +# surrounding the arithmetic operators, leading or trailing whitespace +sanitiseEquation <- function(equation) { + equation <- gsub(" *[+] *", "+", equation) + equation <- gsub(" *[-] *", "-", equation) + equation <- gsub(" *[/] *", "/", equation) + equation <- gsub(" *[*] *", "*", equation) + equation <- gsub("^\\s+|\\s+$", "", equation) + return(equation) +} + +# Function to sanitise group information +sanitiseGroups <- function(string) { + string <- gsub(" *[,] *", ",", string) + string <- gsub("^\\s+|\\s+$", "", string) + return(string) +} + +# Function to change periods to whitespace in a string +unmake.names <- function(string) { + string <- gsub(".", " ", string, fixed=TRUE) + return(string) +} + +# Generate output folder and paths +makeOut <- function(filename) { + return(paste0(opt$outPath, "/", filename)) +} + +# Generating design information +pasteListName <- function(string) { + return(paste0("factors$", string)) +} + +# Create cata function: default path set, default seperator empty and appending +# true by default (Ripped straight from the cat function with altered argument +# defaults) +cata <- function(..., file=opt$htmlPath, sep="", fill=FALSE, labels=NULL, + append=TRUE) { + if (is.character(file)) + if (file == "") + file <- stdout() + else if (substring(file, 1L, 1L) == "|") { + file <- pipe(substring(file, 2L), "w") + on.exit(close(file)) + } + else { + file <- file(file, ifelse(append, "a", "w")) + on.exit(close(file)) + } + .Internal(cat(list(...), file, sep, fill, labels, append)) +} + +# Function to write code for html head and title +HtmlHead <- function(title) { + cata("<head>\n") + cata("<title>", title, "</title>\n") + cata("</head>\n") +} + +# Function to write code for html links +HtmlLink <- function(address, label=address) { + cata("<a href=\"", address, "\" target=\"_blank\">", label, "</a><br />\n") +} + +# Function to write code for html images +HtmlImage <- function(source, label=source, height=600, width=600) { + cata("<img src=\"", source, "\" alt=\"", label, "\" height=\"", height) + cata("\" width=\"", width, "\"/>\n") +} + +# Function to write code for html list items +ListItem <- function(...) { + cata("<li>", ..., "</li>\n") +} + +TableItem <- function(...) { + cata("<td>", ..., "</td>\n") +} + +TableHeadItem <- function(...) { + cata("<th>", ..., "</th>\n") +} + +################################################################################ +### Input Processing +################################################################################ + +# Collect arguments from command line +args <- commandArgs(trailingOnly=TRUE) + +# Get options, using the spec as defined by the enclosed list. +# Read the options from the default: commandArgs(TRUE). +spec <- matrix(c( + "htmlPath", "R", 1, "character", + "outPath", "o", 1, "character", + "filesPath", "j", 2, "character", + "matrixPath", "m", 2, "character", + "factFile", "f", 2, "character", + "factInput", "i", 2, "character", + "annoPath", "a", 2, "character", + "contrastData", "C", 1, "character", + "cpmReq", "c", 1, "double", + "totReq", "y", 0, "logical", + "cntReq", "z", 1, "integer", + "sampleReq", "s", 1, "integer", + "normCounts", "x", 0, "logical", + "rdaOpt", "r", 0, "logical", + "lfcReq", "l", 1, "double", + "pValReq", "p", 1, "double", + "pAdjOpt", "d", 1, "character", + "normOpt", "n", 1, "character", + "robOpt", "b", 0, "logical", + "lrtOpt", "t", 0, "logical"), + byrow=TRUE, ncol=4) +opt <- getopt(spec) + + +if (is.null(opt$matrixPath) & is.null(opt$filesPath)) { + cat("A counts matrix (or a set of counts files) is required.\n") + q(status=1) +} + +if (is.null(opt$cpmReq)) { + filtCPM <- FALSE +} else { + filtCPM <- TRUE +} + +if (is.null(opt$cntReq) || is.null(opt$sampleReq)) { + filtSmpCount <- FALSE +} else { + filtSmpCount <- TRUE +} + +if (is.null(opt$totReq)) { + filtTotCount <- FALSE +} else { + filtTotCount <- TRUE +} + +if (is.null(opt$lrtOpt)) { + wantLRT <- FALSE +} else { + wantLRT <- TRUE +} + +if (is.null(opt$rdaOpt)) { + wantRda <- FALSE +} else { + wantRda <- TRUE +} + +if (is.null(opt$annoPath)) { + haveAnno <- FALSE +} else { + haveAnno <- TRUE +} + +if (is.null(opt$normCounts)) { + wantNorm <- FALSE +} else { + wantNorm <- TRUE +} + +if (is.null(opt$robOpt)) { + wantRobust <- FALSE +} else { + wantRobust <- TRUE +} + + +if (!is.null(opt$filesPath)) { + # Process the separate count files (adapted from DESeq2 wrapper) + library("rjson") + parser <- newJSONParser() + parser$addData(opt$filesPath) + factorList <- parser$getObject() + factors <- sapply(factorList, function(x) x[[1]]) + filenamesIn <- unname(unlist(factorList[[1]][[2]])) + sampleTable <- data.frame(sample=basename(filenamesIn), + filename=filenamesIn, + row.names=filenamesIn, + stringsAsFactors=FALSE) + for (factor in factorList) { + factorName <- factor[[1]] + sampleTable[[factorName]] <- character(nrow(sampleTable)) + lvls <- sapply(factor[[2]], function(x) names(x)) + for (i in seq_along(factor[[2]])) { + files <- factor[[2]][[i]][[1]] + sampleTable[files,factorName] <- lvls[i] + } + sampleTable[[factorName]] <- factor(sampleTable[[factorName]], levels=lvls) + } + rownames(sampleTable) <- sampleTable$sample + rem <- c("sample","filename") + factors <- sampleTable[, !(names(sampleTable) %in% rem), drop=FALSE] + + #read in count files and create single table + countfiles <- lapply(sampleTable$filename, function(x){read.delim(x, row.names=1)}) + counts <- do.call("cbind", countfiles) + +} else { + # Process the single count matrix + counts <- read.table(opt$matrixPath, header=TRUE, sep="\t", stringsAsFactors=FALSE) + row.names(counts) <- counts[, 1] + counts <- counts[ , -1] + countsRows <- nrow(counts) + + # Process factors + if (is.null(opt$factInput)) { + factorData <- read.table(opt$factFile, header=TRUE, sep="\t") + factors <- factorData[, -1, drop=FALSE] + } else { + factors <- unlist(strsplit(opt$factInput, "|", fixed=TRUE)) + factorData <- list() + for (fact in factors) { + newFact <- unlist(strsplit(fact, split="::")) + factorData <- rbind(factorData, newFact) + } # Factors have the form: FACT_NAME::LEVEL,LEVEL,LEVEL,LEVEL,... The first factor is the Primary Factor. + + # Set the row names to be the name of the factor and delete first row + row.names(factorData) <- factorData[, 1] + factorData <- factorData[, -1] + factorData <- sapply(factorData, sanitiseGroups) + factorData <- sapply(factorData, strsplit, split=",") + factorData <- sapply(factorData, make.names) + # Transform factor data into data frame of R factor objects + factors <- data.frame(factorData) + } +} + + # if annotation file provided +if (haveAnno) { + geneanno <- read.table(opt$annoPath, header=TRUE, sep="\t", stringsAsFactors=FALSE) +} + +#Create output directory +dir.create(opt$outPath, showWarnings=FALSE) + +# Split up contrasts separated by comma into a vector then sanitise +contrastData <- unlist(strsplit(opt$contrastData, split=",")) +contrastData <- sanitiseEquation(contrastData) +contrastData <- gsub(" ", ".", contrastData, fixed=TRUE) + +bcvOutPdf <- makeOut("bcvplot.pdf") +bcvOutPng <- makeOut("bcvplot.png") +qlOutPdf <- makeOut("qlplot.pdf") +qlOutPng <- makeOut("qlplot.png") +mdsOutPdf <- makeOut("mdsplot.pdf") +mdsOutPng <- makeOut("mdsplot.png") +mdOutPdf <- character() # Initialise character vector +mdOutPng <- character() +topOut <- character() +for (i in 1:length(contrastData)) { + mdOutPdf[i] <- makeOut(paste0("mdplot_", contrastData[i], ".pdf")) + mdOutPng[i] <- makeOut(paste0("mdplot_", contrastData[i], ".png")) + topOut[i] <- makeOut(paste0("edgeR_", contrastData[i], ".tsv")) +} # Save output paths for each contrast as vectors +normOut <- makeOut("edgeR_normcounts.tsv") +rdaOut <- makeOut("edgeR_analysis.RData") +sessionOut <- makeOut("session_info.txt") + +# Initialise data for html links and images, data frame with columns Label and +# Link +linkData <- data.frame(Label=character(), Link=character(), stringsAsFactors=FALSE) +imageData <- data.frame(Label=character(), Link=character(), stringsAsFactors=FALSE) + +# Initialise vectors for storage of up/down/neutral regulated counts +upCount <- numeric() +downCount <- numeric() +flatCount <- numeric() + +################################################################################ +### Data Processing +################################################################################ + +# Extract counts and annotation data +data <- list() +data$counts <- counts +if (haveAnno) { + data$genes <- geneanno +} else { + data$genes <- data.frame(GeneID=row.names(counts)) +} + +# If filter crieteria set, filter out genes that do not have a required cpm/counts in a required number of +# samples. Default is no filtering +preFilterCount <- nrow(data$counts) + +if (filtCPM || filtSmpCount || filtTotCount) { + + if (filtTotCount) { + keep <- rowSums(data$counts) >= opt$cntReq + } else if (filtSmpCount) { + keep <- rowSums(data$counts >= opt$cntReq) >= opt$sampleReq + } else if (filtCPM) { + keep <- rowSums(cpm(data$counts) >= opt$cpmReq) >= opt$sampleReq + } + + data$counts <- data$counts[keep, ] + data$genes <- data$genes[keep, , drop=FALSE] +} + +postFilterCount <- nrow(data$counts) +filteredCount <- preFilterCount-postFilterCount + +# Creating naming data +samplenames <- colnames(data$counts) +sampleanno <- data.frame("sampleID"=samplenames, factors) + + +# Generating the DGEList object "data" +data$samples <- sampleanno +data$samples$lib.size <- colSums(data$counts) +data$samples$norm.factors <- 1 +row.names(data$samples) <- colnames(data$counts) +data <- new("DGEList", data) + +# Name rows of factors according to their sample +row.names(factors) <- names(data$counts) +factorList <- sapply(names(factors), pasteListName) + +formula <- "~0" +for (i in 1:length(factorList)) { + formula <- paste(formula, factorList[i], sep="+") +} + +formula <- formula(formula) +design <- model.matrix(formula) + +for (i in 1:length(factorList)) { + colnames(design) <- gsub(factorList[i], "", colnames(design), fixed=TRUE) +} + +# Calculating normalising factor, estimating dispersion +data <- calcNormFactors(data, method=opt$normOpt) + +if (wantRobust) { + data <- estimateDisp(data, design=design, robust=TRUE) +} else { + data <- estimateDisp(data, design=design) +} + +# Generate contrasts information +contrasts <- makeContrasts(contrasts=contrastData, levels=design) + +################################################################################ +### Data Output +################################################################################ + +# Plot MDS +labels <- names(counts) +png(mdsOutPng, width=600, height=600) +# Currently only using a single factor +plotMDS(data, labels=labels, col=as.numeric(factors[, 1]), cex=0.8, main="MDS Plot") +imageData[1, ] <- c("MDS Plot", "mdsplot.png") +invisible(dev.off()) + +pdf(mdsOutPdf) +plotMDS(data, labels=labels, cex=0.5) +linkData[1, ] <- c("MDS Plot.pdf", "mdsplot.pdf") +invisible(dev.off()) + +# BCV Plot +png(bcvOutPng, width=600, height=600) +plotBCV(data, main="BCV Plot") +imgName <- "BCV Plot" +imgAddr <- "bcvplot.png" +imageData <- rbind(imageData, c(imgName, imgAddr)) +invisible(dev.off()) + +pdf(bcvOutPdf) +plotBCV(data, main="BCV Plot") +linkName <- paste0("BCV Plot.pdf") +linkAddr <- paste0("bcvplot.pdf") +linkData <- rbind(linkData, c(linkName, linkAddr)) +invisible(dev.off()) + +# Generate fit +if (wantLRT) { + + fit <- glmFit(data, design) + +} else { + + if (wantRobust) { + fit <- glmQLFit(data, design, robust=TRUE) + } else { + fit <- glmQLFit(data, design) + } + + # Plot QL dispersions + png(qlOutPng, width=600, height=600) + plotQLDisp(fit, main="QL Plot") + imgName <- "QL Plot" + imgAddr <- "qlplot.png" + imageData <- rbind(imageData, c(imgName, imgAddr)) + invisible(dev.off()) + + pdf(qlOutPdf) + plotQLDisp(fit, main="QL Plot") + linkName <- "QL Plot.pdf" + linkAddr <- "qlplot.pdf" + linkData <- rbind(linkData, c(linkName, linkAddr)) + invisible(dev.off()) +} + + # Save normalised counts (log2cpm) +if (wantNorm) { + normalisedCounts <- cpm(data, normalized.lib.sizes=TRUE, log=TRUE) + normalisedCounts <- data.frame(data$genes, normalisedCounts) + write.table (normalisedCounts, file=normOut, row.names=FALSE, sep="\t") + linkData <- rbind(linkData, c("edgeR_normcounts.tsv", "edgeR_normcounts.tsv")) +} + + +for (i in 1:length(contrastData)) { + if (wantLRT) { + res <- glmLRT(fit, contrast=contrasts[, i]) + } else { + res <- glmQLFTest(fit, contrast=contrasts[, i]) + } + + status = decideTestsDGE(res, adjust.method=opt$pAdjOpt, p.value=opt$pValReq, + lfc=opt$lfcReq) + sumStatus <- summary(status) + + # Collect counts for differential expression + upCount[i] <- sumStatus["1", ] + downCount[i] <- sumStatus["-1", ] + flatCount[i] <- sumStatus["0", ] + + # Write top expressions table + top <- topTags(res, n=Inf, sort.by="PValue") + write.table(top, file=topOut[i], row.names=FALSE, sep="\t") + + linkName <- paste0("edgeR_", contrastData[i], ".tsv") + linkAddr <- paste0("edgeR_", contrastData[i], ".tsv") + linkData <- rbind(linkData, c(linkName, linkAddr)) + + # Plot MD (log ratios vs mean difference) using limma package + pdf(mdOutPdf[i]) + limma::plotMD(res, status=status, + main=paste("MD Plot:", unmake.names(contrastData[i])), + col=alpha(c("firebrick", "blue"), 0.4), values=c("1", "-1"), + xlab="Average Expression", ylab="logFC") + + abline(h=0, col="grey", lty=2) + + linkName <- paste0("MD Plot_", contrastData[i], ".pdf") + linkAddr <- paste0("mdplot_", contrastData[i], ".pdf") + linkData <- rbind(linkData, c(linkName, linkAddr)) + invisible(dev.off()) + + png(mdOutPng[i], height=600, width=600) + limma::plotMD(res, status=status, + main=paste("MD Plot:", unmake.names(contrastData[i])), + col=alpha(c("firebrick", "blue"), 0.4), values=c("1", "-1"), + xlab="Average Expression", ylab="logFC") + + abline(h=0, col="grey", lty=2) + + imgName <- paste0("MD Plot_", contrastData[i], ".png") + imgAddr <- paste0("mdplot_", contrastData[i], ".png") + imageData <- rbind(imageData, c(imgName, imgAddr)) + invisible(dev.off()) +} +sigDiff <- data.frame(Up=upCount, Flat=flatCount, Down=downCount) +row.names(sigDiff) <- contrastData + +# Save relevant items as rda object +if (wantRda) { + if (wantNorm) { + save(counts, data, status, normalisedCounts, labels, factors, fit, res, top, contrasts, design, + file=rdaOut, ascii=TRUE) + } else { + save(counts, data, status, labels, factors, fit, res, top, contrasts, design, + file=rdaOut, ascii=TRUE) + } + linkData <- rbind(linkData, c("edgeR_analysis.RData", "edgeR_analysis.RData")) +} + +# Record session info +writeLines(capture.output(sessionInfo()), sessionOut) +linkData <- rbind(linkData, c("Session Info", "session_info.txt")) + +# Record ending time and calculate total run time +timeEnd <- as.character(Sys.time()) +timeTaken <- capture.output(round(difftime(timeEnd, timeStart), digits=3)) +timeTaken <- gsub("Time difference of ", "", timeTaken, fixed=TRUE) + +################################################################################ +### HTML Generation +################################################################################ + +# Clear file +cat("", file=opt$htmlPath) + +cata("<html>\n") + +cata("<body>\n") +cata("<h3>edgeR Analysis Output:</h3>\n") +cata("Links to PDF copies of plots are in 'Plots' section below.<br />\n") + +HtmlImage(imageData$Link[1], imageData$Label[1]) + +for (i in 2:nrow(imageData)) { + HtmlImage(imageData$Link[i], imageData$Label[i]) +} + +cata("<h4>Differential Expression Counts:</h4>\n") + +cata("<table border=\"1\" cellpadding=\"4\">\n") +cata("<tr>\n") +TableItem() +for (i in colnames(sigDiff)) { + TableHeadItem(i) +} +cata("</tr>\n") +for (i in 1:nrow(sigDiff)) { + cata("<tr>\n") + TableHeadItem(unmake.names(row.names(sigDiff)[i])) + for (j in 1:ncol(sigDiff)) { + TableItem(as.character(sigDiff[i, j])) + } + cata("</tr>\n") +} +cata("</table>") + +cata("<h4>Plots:</h4>\n") +for (i in 1:nrow(linkData)) { + if (grepl(".pdf", linkData$Link[i])) { + HtmlLink(linkData$Link[i], linkData$Label[i]) + } +} + +cata("<h4>Tables:</h4>\n") +for (i in 1:nrow(linkData)) { + if (grepl(".tsv", linkData$Link[i])) { + HtmlLink(linkData$Link[i], linkData$Label[i]) + } +} + +if (wantRda) { + cata("<h4>R Data Objects:</h4>\n") + for (i in 1:nrow(linkData)) { + if (grepl(".RData", linkData$Link[i])) { + HtmlLink(linkData$Link[i], linkData$Label[i]) + } + } +} + +cata("<p>Alt-click links to download file.</p>\n") +cata("<p>Click floppy disc icon associated history item to download ") +cata("all files.</p>\n") +cata("<p>.tsv files can be viewed in Excel or any spreadsheet program.</p>\n") + +cata("<h4>Additional Information</h4>\n") +cata("<ul>\n") + +if (filtCPM || filtSmpCount || filtTotCount) { + if (filtCPM) { + tempStr <- paste("Genes without more than", opt$cmpReq, + "CPM in at least", opt$sampleReq, "samples are insignificant", + "and filtered out.") + } else if (filtSmpCount) { + tempStr <- paste("Genes without more than", opt$cntReq, + "counts in at least", opt$sampleReq, "samples are insignificant", + "and filtered out.") + } else if (filtTotCount) { + tempStr <- paste("Genes without more than", opt$cntReq, + "counts, after summing counts for all samples, are insignificant", + "and filtered out.") + } + + ListItem(tempStr) + filterProp <- round(filteredCount/preFilterCount*100, digits=2) + tempStr <- paste0(filteredCount, " of ", preFilterCount," (", filterProp, + "%) genes were filtered out for low expression.") + ListItem(tempStr) +} +ListItem(opt$normOpt, " was the method used to normalise library sizes.") +if (wantLRT) { + ListItem("The edgeR likelihood ratio test was used.") +} else { + if (wantRobust) { + ListItem("The edgeR quasi-likelihood test was used with robust settings (robust=TRUE with estimateDisp and glmQLFit).") + } else { + ListItem("The edgeR quasi-likelihood test was used.") + } +} +if (opt$pAdjOpt!="none") { + if (opt$pAdjOpt=="BH" || opt$pAdjOpt=="BY") { + tempStr <- paste0("MD-Plot highlighted genes are significant at FDR ", + "of ", opt$pValReq," and exhibit log2-fold-change of at ", + "least ", opt$lfcReq, ".") + ListItem(tempStr) + } else if (opt$pAdjOpt=="holm") { + tempStr <- paste0("MD-Plot highlighted genes are significant at adjusted ", + "p-value of ", opt$pValReq," by the Holm(1979) ", + "method, and exhibit log2-fold-change of at least ", + opt$lfcReq, ".") + ListItem(tempStr) + } +} else { + tempStr <- paste0("MD-Plot highlighted genes are significant at p-value ", + "of ", opt$pValReq," and exhibit log2-fold-change of at ", + "least ", opt$lfcReq, ".") + ListItem(tempStr) +} +cata("</ul>\n") + +cata("<h4>Summary of experimental data:</h4>\n") + +cata("<p>*CHECK THAT SAMPLES ARE ASSOCIATED WITH CORRECT GROUP(S)*</p>\n") + +cata("<table border=\"1\" cellpadding=\"3\">\n") +cata("<tr>\n") +TableHeadItem("SampleID") +TableHeadItem(names(factors)[1], " (Primary Factor)") + + if (ncol(factors) > 1) { + for (i in names(factors)[2:length(names(factors))]) { + TableHeadItem(i) + } + cata("</tr>\n") + } + +for (i in 1:nrow(factors)) { + cata("<tr>\n") + TableHeadItem(row.names(factors)[i]) + for (j in 1:ncol(factors)) { + TableItem(as.character(unmake.names(factors[i, j]))) + } + cata("</tr>\n") +} +cata("</table>") + +for (i in 1:nrow(linkData)) { + if (grepl("session_info", linkData$Link[i])) { + HtmlLink(linkData$Link[i], linkData$Label[i]) + } +} + +cata("<table border=\"0\">\n") +cata("<tr>\n") +TableItem("Task started at:"); TableItem(timeStart) +cata("</tr>\n") +cata("<tr>\n") +TableItem("Task ended at:"); TableItem(timeEnd) +cata("</tr>\n") +cata("<tr>\n") +TableItem("Task run time:"); TableItem(timeTaken) +cata("<tr>\n") +cata("</table>\n") + +cata("</body>\n") +cata("</html>")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/edger.xml Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,733 @@ +<tool id="edger" name="edgeR" version="3.16.5"> + <description> + Perform differential expression of count data + </description> + + <requirements> + <requirement type="package" version="3.16.5">bioconductor-edger</requirement> + <requirement type="package" version="0.2.15">r-rjson</requirement> + <requirement type="package" version="1.20.0">r-getopt</requirement> + <!-- required for alpha function used with plotMD --> + <requirement type="package" version="0.4.1">r-scales</requirement> + <!-- This should be in limma conda now - check why still needed? --> + <requirement type="package" version="1.4.30">r-statmod</requirement> + </requirements> + + <version_command><![CDATA[ + echo $(R --version | grep version | grep -v GNU)", edgeR version" $(R --vanilla --slave -e "library(edgeR); cat(sessionInfo()\$otherPkgs\$edgeR\$Version)" 2> /dev/null | grep -v -i "WARNING: ")", scales version" $(R --vanilla --slave -e "library(scales); cat(sessionInfo()\$otherPkgs\$scales\$Version)" 2> /dev/null | grep -v -i "WARNING: ")", rjson version" $(R --vanilla --slave -e "library(rjson); cat(sessionInfo()\$otherPkgs\$rjson\$Version)" 2> /dev/null | grep -v -i "WARNING: ")", getopt version" $(R --vanilla --slave -e "library(getopt); cat(sessionInfo()\$otherPkgs\$getopt\$Version)" 2> /dev/null | grep -v -i "WARNING: ") + ]]></version_command> + + <command detect_errors="exit_code"><![CDATA[ +#import json +Rscript '$__tool_directory__/edger.R' + +-R '$outReport' +-o '$outReport.files_path' + +#if $input.format=="files": + + ## Adapted from DESeq2 wrapper + #set $temp_factor_names = list() + #for $fact in $input.rep_factor: + #set $temp_factor = list() + #for $g in $fact.rep_group: + #set $count_files = list() + #for $file in $g.countsFile: + $count_files.append(str($file)) + #end for + $temp_factor.append( {str($g.groupName): $count_files} ) + #end for + + $temp_factor.reverse() + $temp_factor_names.append([str($fact.factorName), $temp_factor]) + #end for + -j '#echo json.dumps(temp_factor_names)#' + +#elif $input.format=="matrix": + -m '$input.counts' + #if $input.fact.ffile=='yes': + -f '$input.fact.finfo' + #else: + -i '${ '|'.join( ['%s::%s' % ($x.factorName, $x.groupNames) for x in $input.fact.rep_factor] ) }' + #end if +#end if + +#if $anno.annoOpt=='yes': + -a '$anno.geneanno' +#end if + +-C '${ ','.join( ['%s' % $x.contrast for x in $rep_contrast] ) }' + +#if $f.filt.filt_select == 'yes': + #if $f.filt.cformat.format_select == 'cpm': + -c '$f.filt.cformat.cpmReq' + -s '$f.filt.cformat.cpmSampleReq' + #elif $f.filt.cformat.format_select == 'counts': + -z '$f.filt.cformat.cntReq' + #if $f.filt.cformat.samples.count_select == 'total': + -y + #elif $f.filt.cformat.samples.count_select == 'sample': + -s '$f.filt.cformat.samples.cntSampleReq' + #end if + #end if +#end if + +#if $out.normCounts: + -x +#end if +#if $out.rdaOption: + -r +#end if + +-l '$adv.lfc' +-p '$adv.pVal' +-d '$adv.pAdjust' +-n '$adv.normalisationOption' +#if $adv.robOption: + -b +#end if +#if $adv.lrtOption: + -t +#end if + +&& +mkdir ./output_dir + +&& +cp '$outReport.files_path'/*.tsv output_dir/ + ]]></command> + + <inputs> + + <!-- Counts and Factors --> + <conditional name="input"> + <param name="format" type="select" label="Count Files or Matrix?" + help="You can choose to input either separate count files (one per sample) or a single count matrix"> + <option value="files">Separate Count Files</option> + <option value="matrix">Single Count Matrix</option> + </param> + + <when value="files"> + <repeat name="rep_factor" title="Factor" min="1"> + <param name="factorName" type="text" label="Name" help="Name of experiment factor of interest (e.g. Genotype). One factor must be entered and there must be two or more groups per factor. Optional additional factors (e.g. Batch) can be entered using the Insert Factor button below, see Help section for more information. NOTE: Please only use letters, numbers or underscores."> + <sanitizer> + <valid initial="string.letters,string.digits"><add value="_" /></valid> + </sanitizer> + </param> + <repeat name="rep_group" title="Group" min="2" default="2"> + <param name="groupName" type="text" label="Name" + help="Name of group that the counts files(s) belong to (e.g. WT or Mut). NOTE: Please only use letters, numbers or underscores (case sensitive)."> + <sanitizer> + <valid initial="string.letters,string.digits"><add value="_" /></valid> + </sanitizer> + </param> + <param name="countsFile" type="data" format="tabular" multiple="true" label="Counts file(s)"/> + </repeat> + </repeat> + </when> + + <when value="matrix"> + <param name="counts" type="data" format="tabular" label="Count Matrix"/> + + <conditional name="fact"> + <param name="ffile" type="select" label="Input factor information from file?" + help="You can choose to input the factor and group information for the samples from a file or manually enter below."> + <option value="no">No</option> + <option value="yes">Yes</option> + </param> + <when value="yes"> + <param name="finfo" type="data" format="tabular" label="Factor File"/> + </when> + <when value="no" > + <repeat name="rep_factor" title="Factor" min="1"> + <param name="factorName" type="text" label="Factor Name" + help="Name of experiment factor of interest (e.g. Genotype). One factor must be entered and there must be two or more groups per factor. Additional factors (e.g. Batch) can be entered using the Insert Factor button below, see Help section below. NOTE: Please only use letters, numbers or underscores."> + <validator type="empty_field" /> + <validator type="regex" message="Please only use letters, numbers or underscores">^[\w]+$</validator> + </param> + <param name="groupNames" type="text" label="Groups" + help="Enter the group names for the samples separated with commas e.g. WT,WT,WT,Mut,Mut,Mut. The order of the names must match the order of the samples in the columns of the count matrix. NOTE: Please only use letters, numbers or underscores (case sensitive)."> + <validator type="empty_field" /> + <validator type="regex" message="Please only use letters, numbers or underscores, and separate levels by commas">^[\w,]+$</validator> + </param> + </repeat> + </when> + </conditional> + </when> + </conditional> + + <!-- Gene Annotations --> + <conditional name="anno"> + <param name="annoOpt" type="select" label="Use Gene Annotations?" + help="If you provide an annotation file, annotations will be added to the table(s) of differential expression results to provide descriptions for each gene. See Help section below."> + <option value="no">No</option> + <option value="yes">Yes</option> + </param> + <when value="yes"> + <param name="geneanno" type="data" format="tabular" label="Gene Annotations"/> + </when> + <when value="no" /> + </conditional> + + <!-- Contrasts --> + <repeat name="rep_contrast" title="Contrast" min="1" default="1"> + <param name="contrast" type="text" label="Contrast of Interest" help="Names of two groups to compare separated by a hyphen e.g. Mut-WT. If the order is Mut-WT the fold changes in the results will be up/down in Mut relative to WT. If you have more than one contrast enter each separately using the Insert Contrast button below. For more info, see Chapter 8 in the limma User's guide: https://www.bioconductor.org/packages/release/bioc/vignettes/limma/inst/doc/usersguide.pdf"> + <validator type="empty_field" /> + <validator type="regex" message="Please only use letters, numbers or underscores">^[\w-]+$</validator> + </param> + </repeat> + + <!-- Filter Options --> + <section name="f" expanded="false" title="Filter Low Counts"> + <conditional name="filt"> + <param name="filt_select" type="select" label="Filter lowly expressed genes?" help="Treat genes with very low expression as unexpressed and filter out. See the Filter Low Counts section below for more information. Default: No"> + <option value="no" selected="true">No</option> + <option value="yes">Yes</option> + </param> + <when value="yes"> + <conditional name="cformat"> + <param name="format_select" type="select" label="Filter on CPM or Count values?" help="It is slightly better to base the filtering on count-per-million (CPM) rather than the raw count values so as to avoid favoring genes expressed in samples sequenced to a higher depth. "> + <option value="cpm">CPM</option> + <option value="counts">Counts</option> + </param> + <when value="cpm"> + <param name="cpmReq" type="float" value="1" min="0" label="Minimum CPM" help="Treat genes with CPM below this value as unexpressed and filter out. See the Filter Low Counts section below for more information."/> + <param name="cpmSampleReq" type="integer" value="0" min="0" label="Minimum Samples" + help="Filter out all genes that do not meet the Minimum CPM in at least this many samples. See the Filter Low Counts section below for more information."/> + </when> + <when value="counts"> + <param name="cntReq" type="integer" value="0" min="0" label="Minimum Count" help="Filter out all genes that do not meet this minimum count. You can choose below to apply this filter to the total count for all samples or specify the number of samples under Minimum Samples. See the Filter Low Counts section below for more information." /> + <conditional name="samples"> + <param name="count_select" type="select" label="Filter on Total Count or per Sample Count values?" > + <option value="total">Total</option> + <option value="sample">Sample</option> + </param> + <when value="total"> + <param name="totReq" type="boolean" truevalue="1" falsevalue="0" checked="false" label="Filter on Total Count" help="Apply the Minimum Count filter to genes after summing counts for all samples. See the Filter Low Counts section below for more information." /> + </when> + <when value="sample"> + <param name="cntSampleReq" type="integer" value="0" min="0" label="Minimum Samples" + help="Filter out all genes that do not meet the Minimum Count in at least this many samples. See the Filter Low Counts section below for more information."/> + </when> + </conditional> + </when> + </conditional> + </when> + <when value="no" /> + </conditional> + </section> + + <!-- Output Options --> + <section name="out" expanded="false" title="Output Options"> + <param name="normCounts" type="boolean" truevalue="1" falsevalue="0" checked="false" + label="Output Normalised Counts Table?" + help="Output a file containing the normalised counts, these are in log2 counts per million (logCPM). Default: No"> + </param> + <param name="rdaOption" type="boolean" truevalue="1" falsevalue="0" checked="false" + label="Output RData file?" + help="Output all the data used by R to construct the plots and tables, can be loaded into R. A link to the RData file will be provided in the HTML report. Default: No"> + </param> + </section> + + <!-- Advanced Options --> + <section name="adv" expanded="false" title="Advanced Options"> + <param name="lfc" type="float" value="0" min="0" + label="Minimum Log2 Fold Change" + help="Genes above this threshold and below the p-value threshold are considered significant and highlighted in the MD plot. Default: 0."/> + <param name="pVal" type="float" value="0.05" min="0" max="1" + label="P-Value Adjusted Threshold" + help="Genes below this threshold are considered significant and highlighted in the MD plot. If either BH(1995) or BY(2001) are selected then this value is a false-discovery-rate control. If Holm(1979) is selected then this is an adjusted p-value for family-wise error rate. Default: 0.05."/> + <param name="pAdjust" type="select" label="P-Value Adjustment Method" help="Default: BH"> + <option value="BH" selected="true">Benjamini and Hochberg (1995)</option> + <option value="BY">Benjamini and Yekutieli (2001)</option> + <option value="holm">Holm (1979)</option> + <option value="none">None</option> + </param> + <param name="normalisationOption" type="select" label="Normalisation Method" help="Default: TMM"> + <option value="TMM" selected="true">TMM</option> + <option value="RLE">RLE</option> + <option value="upperquartile">Upperquartile</option> + <option value="none">None (Don't normalise)</option> + </param> + <param name="robOption" type="boolean" truevalue="1" falsevalue="0" checked="true" label="Use Robust Settings?" help="Using robust settings is usually recommended to protect against outlier genes. Default: Yes" /> + <param name="lrtOption" type="boolean" truevalue="1" falsevalue="0" checked="false" label="Use Likelihood Ratio Test?" help="Use likelihood ratio test instead of quasi-likelihood F-test. Default: No"/> + </section> + + </inputs> + + <outputs> + <data name="outReport" format="html" label="${tool.name} on ${on_string}: Report" /> + <collection name="outTables" type="list" label="${tool.name} on ${on_string}: Tables"> + <discover_datasets pattern="(?P<name>.+)\.tsv$" format="tabular" directory="output_dir" visible="false" /> + </collection> + </outputs> + + <tests> + <!-- Ensure report is output --> + <test> + <param name="format" value="matrix" /> + <param name="counts" value="matrix.txt" /> + <repeat name="rep_factor"> + <param name="factorName" value="Genotype"/> + <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT" /> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="WT-Mut" /> + </repeat> + <param name="normalisationOption" value="TMM" /> + <output_collection name="outTables" count="2"> + <element name="edgeR_Mut-WT" ftype="tabular" file="edgeR_Mut-WT.tsv" /> + <element name="edgeR_WT-Mut" ftype="tabular" file="edgeR_WT-Mut.tsv" /> + </output_collection> + <output name="outReport" > + <assert_contents> + <has_text text="edgeR Analysis Output" /> + <has_text text="quasi-likelihood" /> + <not_has_text text="likelihood ratio" /> + <not_has_text text="RData" /> + </assert_contents> + </output> + </test> + <!-- Ensure annotation file input works --> + <test> + <param name="format" value="matrix" /> + <param name="annoOpt" value="yes" /> + <param name="geneanno" value="anno.txt" /> + <param name="counts" value="matrix.txt" /> + <repeat name="rep_factor"> + <param name="factorName" value="Genotype"/> + <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT" /> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <param name="normalisationOption" value="TMM" /> + <output_collection name="outTables" count="1"> + <element name="edgeR_Mut-WT" ftype="tabular" file="edgeR_Mut-WT_anno.tsv" /> + </output_collection> + </test> + <!-- Ensure RData file can be output --> + <test> + <param name="format" value="matrix" /> + <param name="rdaOption" value="true" /> + <param name="counts" value="matrix.txt" /> + <repeat name="rep_factor"> + <param name="factorName" value="Genotype"/> + <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT" /> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <param name="normalisationOption" value="TMM" /> + <output name="outReport" > + <assert_contents> + <has_text text="RData" /> + </assert_contents> + </output> + </test> + <!-- Ensure secondary factors work --> + <test> + <param name="format" value="matrix" /> + <param name="counts" value="matrix.txt" /> + <repeat name="rep_factor"> + <param name="factorName" value="Genotype"/> + <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT" /> + </repeat> + <repeat name="rep_factor"> + <param name="factorName" value="Batch"/> + <param name="groupNames" value="b1,b2,b3,b1,b2,b3"/> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <param name="normalisationOption" value="TMM" /> + <output_collection name="outTables" count="1" > + <element name="edgeR_Mut-WT" ftype="tabular" file="edgeR_Mut-WT_2fact.tsv" /> + </output_collection> + </test> + <!-- Ensure factors file input works --> + <test> + <param name="format" value="matrix" /> + <param name="ffile" value="yes" /> + <param name="finfo" value="factorinfo.txt" /> + <param name="counts" value="matrix.txt" /> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <param name="normalisationOption" value="TMM" /> + <output_collection name="outTables" count="1"> + <element name="edgeR_Mut-WT" ftype="tabular" file="edgeR_Mut-WT_2fact.tsv" /> + </output_collection> + </test> + <!-- Ensure normalised counts file output works--> + <test> + <param name="format" value="matrix" /> + <param name="normCounts" value="true" /> + <param name="counts" value="matrix.txt" /> + <repeat name="rep_factor"> + <param name="factorName" value="Genotype"/> + <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT" /> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <param name="normalisationOption" value="TMM" /> + <output_collection name="outTables" count="2"> + <element name="edgeR_Mut-WT" ftype="tabular" file="edgeR_Mut-WT.tsv" /> + <element name="edgeR_normcounts" ftype="tabular" file="edgeR_normcounts.tsv" /> + </output_collection> + </test> + <!-- Ensure likelihood ratio option works --> + <test> + <param name="format" value="matrix" /> + <param name="counts" value="matrix.txt" /> + <repeat name="rep_factor"> + <param name="factorName" value="Genotype"/> + <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT" /> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <param name="normalisationOption" value="TMM" /> + <param name="lrtOption" value="true" /> + <output name="outReport" > + <assert_contents> + <has_text text="likelihood ratio" /> + <not_has_text text="quasi-likelihood" /> + </assert_contents> + </output> + </test> + <!-- Ensure multiple counts files input works --> + <test> + <param name="format" value="files" /> + <repeat name="rep_factor"> + <param name="factorName" value="Genotype"/> + <repeat name="rep_group"> + <param name="groupName" value="WT"/> + <param name="countsFile" value="WT1.counts,WT2.counts,WT3.counts"/> + </repeat> + <repeat name="rep_group"> + <param name="groupName" value="Mut"/> + <param name="countsFile" value="Mut1.counts,Mut2.counts,Mut3.counts"/> + </repeat> + </repeat> + <repeat name="rep_factor"> + <param name="factorName" value="Batch"/> + <repeat name="rep_group"> + <param name="groupName" value="b1"/> + <param name="countsFile" value="WT1.counts,Mut1.counts"/> + </repeat> + <repeat name="rep_group"> + <param name="groupName" value="b2"/> + <param name="countsFile" value="WT2.counts,Mut2.counts"/> + </repeat> + <repeat name="rep_group"> + <param name="groupName" value="b3"/> + <param name="countsFile" value="WT3.counts,Mut3.counts"/> + </repeat> + </repeat> + <param name="annoOpt" value="yes" /> + <param name="geneanno" value="anno.txt" /> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="WT-Mut" /> + </repeat> + <param name="normCounts" value="true" /> + <output_collection name="outTables" count="3"> + <element name="edgeR_Mut-WT" ftype="tabular" file="edgeR_Mut-WT_2fact_anno.tsv" /> + <element name="edgeR_WT-Mut" ftype="tabular" file="edgeR_WT-Mut_2fact_anno.tsv" /> + <element name="edgeR_normcounts" ftype="tabular" file="edgeR_normcounts_anno.tsv" /> + </output_collection> + </test> + <!-- Ensure filtering on CPM in Mnimum Samples works --> + <test> + <param name="format" value="matrix" /> + <param name="counts" value="matrix.txt" /> + <repeat name="rep_factor"> + <param name="factorName" value="Genotype"/> + <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT" /> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <param name="normalisationOption" value="TMM" /> + <param name="filt_select" value="yes" /> + <param name="format_select" value="cpm" /> + <!-- real cpmReq values would be a lot lower + this is just for this tiny test dataset --> + <param name="cpmReq" value="1000" /> + <param name="cpmSampleReq" value="3" /> + <output name="outReport" > + <assert_contents> + <has_text text="CPM in at least" /> + <not_has_text text="after summing counts for all samples" /> + <not_has_text text="counts in at least" /> + </assert_contents> + </output> + <output_collection name="outTables" count="1" > + <element name="edgeR_Mut-WT" ftype="tabular" file="edgeR_Mut-WT_filt.tsv" /> + </output_collection> + </test> + <!-- Ensure filtering on Count in Minmum Samples works --> + <test> + <param name="format" value="matrix" /> + <param name="counts" value="matrix.txt" /> + <repeat name="rep_factor"> + <param name="factorName" value="Genotype"/> + <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT" /> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <param name="normalisationOption" value="TMM" /> + <param name="filt_select" value="yes" /> + <param name="format_select" value="counts" /> + <param name="cntReq" value="10" /> + <param name="count_select" value="sample" /> + <param name="cntSampleReq" value="3" /> + <output name="outReport" > + <assert_contents> + <has_text text="counts in at least" /> + <not_has_text text="after summing counts for all samples" /> + <not_has_text text="CPM in at least" /> + </assert_contents> + </output> + <output_collection name="outTables" count="1" > + <element name="edgeR_Mut-WT" ftype="tabular" file="edgeR_Mut-WT_filt.tsv" /> + </output_collection> + </test> + <!-- Ensure filtering on Total Count works --> + <test> + <param name="format" value="matrix" /> + <param name="counts" value="matrix.txt" /> + <repeat name="rep_factor"> + <param name="factorName" value="Genotype"/> + <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT" /> + </repeat> + <repeat name="rep_contrast"> + <param name="contrast" value="Mut-WT" /> + </repeat> + <param name="normalisationOption" value="TMM" /> + <param name="filt_select" value="yes" /> + <param name="format_select" value="counts" /> + <!-- real cntReq values would be a lot lower + this is just for this tiny test dataset --> + <param name="cntReq" value="1000" /> + <param name="count_select" value="total" /> + <param name="totReq" value="true" /> + <output name="outReport" > + <assert_contents> + <has_text text="after summing counts for all samples" /> + <not_has_text text="counts in at least" /> + <not_has_text text="CPM in at least" /> + </assert_contents> + </output> + <output_collection name="outTables" count="1" > + <element name="edgeR_Mut-WT" ftype="tabular" file="edgeR_Mut-WT_filt.tsv" /> + </output_collection> + </test> + </tests> + + <help><![CDATA[ +.. class:: infomark + +**What it does** + +Given a counts matrix, or a set of counts files, for example from **featureCounts**, and optional information about the genes, this tool +produces plots and tables useful in the analysis of differential gene expression. + +This tool uses the `edgeR`_ quasi-likelihood pipeline (edgeR-quasi) for differential expression analysis. This statistical methodology uses negative binomial generalized linear models, but with F-tests instead of likelihood ratio tests. This method provides stricter error rate control than other negative binomial based pipelines, including the traditional edgeR pipelines or DESeq2. While the limma pipelines are recommended for large-scale datasets, because of their speed and flexibility, the edgeR-quasi pipeline gives better performance in low-count situations. For the data analyzed in this `edgeR workflow article`_ ,the edgeR-quasi, limma-voom and limma-trend pipelines are all equally suitable and give similar results. + +.. _edgeR: http://www.bioconductor.org/packages/release/bioc/html/edgeR.html +.. _edgeR workflow article: https://f1000research.com/articles/5-1438 + +----- + +**Inputs** + +**Counts Data:** + +The counts data can either be input as separate counts files (one sample per file) or a single count matrix (one sample per column). The rows correspond to genes, and columns correspond to the counts for the samples. Values must be tab separated, with the first row containing the sample/column labels and the first column containing the row/gene labels. Gene identifiers can be of any type but must be unique and not repeated within a counts file. + +Example - **Separate Count Files**: + + ========== ======= + **GeneID** **WT1** + ---------- ------- + 11287 1699 + 11298 1905 + 11302 6 + 11303 2099 + 11304 356 + 11305 2528 + ========== ======= + +Example - **Single Count Matrix**: + + ========== ======= ======= ======= ======== ======== ======== + **GeneID** **WT1** **WT2** **WT3** **Mut1** **Mut2** **Mut3** + ---------- ------- ------- ------- -------- -------- -------- + 11287 1699 1528 1601 1463 1441 1495 + 11298 1905 1744 1834 1345 1291 1346 + 11302 6 8 7 5 6 5 + 11303 2099 1974 2100 1574 1519 1654 + 11304 356 312 337 361 397 346 + 11305 2528 2438 2493 1762 1942 2027 + ========== ======= ======= ======= ======== ======== ======== + +**Factor Information:** +Enter factor names and groups in the tool form, or provide a tab-separated file that has the samples in the same order as listed in the columns of the counts matrix. The second column should contain the primary factor levels (e.g. WT, Mut) with optional additional columns for any secondary factors. + +Example: + + ========== ============ ========= + **Sample** **Genotype** **Batch** + ---------- ------------ --------- + WT1 WT b1 + WT2 WT b2 + WT3 WT b3 + Mut1 Mut b1 + Mut2 Mut b2 + Mut3 Mut b3 + ========== ============ ========= + +*Factor Name:* The name of the experimental factor being investigated e.g. Genotype, Treatment. One factor must be entered and spaces must not be used. Optionally, additional factors can be included, these are variables that might influence your experiment e.g. Batch, Gender, Subject. If additional factors are entered, edgeR will fit an additive linear model. + +*Groups:* The names of the groups for the factor. These must be entered in the same order as the samples (to which the groups correspond) are listed in the columns of the counts matrix. Spaces must not be used and if entered into the tool form above, the values should be separated by commas. + + +**Gene Annotations:** +Optional input for gene annotations, this can contain more +information about the genes than just an ID number. The annotations will +be available in the differential expression results table and the optional normalised counts table. + +Example: + + ========== ========== =================================================== + **GeneID** **Symbol** **GeneName** + ---------- ---------- --------------------------------------------------- + 1287 Pzp pregnancy zone protein + 1298 Aanat arylalkylamine N-acetyltransferase + 1302 Aatk apoptosis-associated tyrosine kinase + 1303 Abca1 ATP-binding cassette, sub-family A (ABC1), member 1 + 1304 Abca4 ATP-binding cassette, sub-family A (ABC1), member 4 + 1305 Abca2 ATP-binding cassette, sub-family A (ABC1), member 2 + ========== ========== =================================================== + +**Contrasts of Interest:** +The contrasts you wish to make between levels. +A common contrast would be a simple difference between two levels: "Mut-WT" +represents the difference between the mutant and wild type genotypes. +Multiple contrasts must be entered separately using the Insert Contrast button, spaces must not be used. + +**Filter Low Counts:** +Genes with very low counts across all libraries provide little evidence for differential expression. +In the biological point of view, a gene must be expressed at some minimal level before +it is likely to be translated into a protein or to be biologically important. In addition, the +pronounced discreteness of these counts interferes with some of the statistical approximations +that are used later in the pipeline. These genes should be filtered out prior to further +analysis. +As a rule of thumb, genes are dropped if they can’t possibly be expressed in all the samples +for any of the conditions. Users can set their own definition of genes being expressed. Usually +a gene is required to have a count of 5-10 in a library to be considered expressed in that +library. Users should also filter with count-per-million (CPM) rather than filtering on the +counts directly, as the latter does not account for differences in library sizes between samples. + +Option to ignore the genes that do not show significant levels of +expression, this filtering is dependent on two criteria: CPM/count and number of samples. You can specify to filter on CPM (Minimum CPM) or count (Minimum Count) values: + + * **Minimum CPM:** This is the minimum count per million that a gene must have in at + least the number of samples specified under Minimum Samples. + + * **Minimum Count:** This is the minimum count that a gene must have. It can be combined with either Filter + on Total Count or Minimum Samples. + + * **Filter on Total Count:** This can be used with the Minimum Count filter to keep genes + with a minimum total read count. + + * **Minimum Samples:** This is the number of samples in which the Minimum CPM/Count + requirement must be met in order for that gene to be kept. + +If the Minimum Samples filter is applied, only genes that exhibit a CPM/count greater than the required amount in at least the number of samples specified will be used for analysis. Care should be taken to +ensure that the sample requirement is appropriate. In the case of an experiment +with two experimental groups each with two members, if there is a change from +insignificant CPM/count to significant CPM/count but the sample requirement is set to 3, +then this will cause that gene to fail the criteria. When in doubt simply do not +filter or consult the `edgeR workflow article`_ for filtering recommendations. + +**Advanced Options:** + +By default error rate for multiple testing is controlled using Benjamini and +Hochberg's false discovery rate control at a threshold value of 0.05. However +there are options to change this to custom values. + + * **Minimum log2-fold-change Required:** + In addition to meeting the requirement for the adjusted statistic for + multiple testing, the observation must have an absolute log2-fold-change + greater than this threshold to be considered significant, thus highlighted + in the MD plot. + + * **Adjusted Threshold:** + Set the threshold for the resulting value of the multiple testing control + method. Only observations whose statistic falls below this value is + considered significant, thus highlighted in the MD plot. + + * **P-Value Adjustment Method:** + Change the multiple testing control method, the options are BH(1995) and + BY(2001) which are both false discovery rate controls. There is also + Holm(1979) which is a method for family-wise error rate control. + +**Normalisation Method:** +The most obvious technical factor that affects the read counts, other than gene expression +levels, is the sequencing depth of each RNA sample. edgeR adjusts any differential expression +analysis for varying sequencing depths as represented by differing library sizes. This is +part of the basic modeling procedure and flows automatically into fold-change or p-value +calculations. It is always present, and doesn’t require any user intervention. +The second most important technical influence on differential expression is one that is less +obvious. RNA-seq provides a measure of the relative abundance of each gene in each RNA +sample, but does not provide any measure of the total RNA output on a per-cell basis. +This commonly becomes important when a small number of genes are very highly expressed +in one sample, but not in another. The highly expressed genes can consume a substantial +proportion of the total library size, causing the remaining genes to be under-sampled in that +sample. Unless this RNA composition effect is adjusted for, the remaining genes may falsely +appear to be down-regulated in that sample . The edgeR `calcNormFactors` function normalizes for RNA composition by finding a set of scaling factors for the library sizes that minimize the log-fold changes between the samples for most genes. The default method for computing these scale factors uses a trimmed mean of M values (TMM) between each pair of samples. We call the product of the original library size and the scaling factor the *effective library size*. The effective library size replaces the original library size in all downsteam analyses. TMM is the recommended method for most RNA-Seq data where the majority (more than half) of the genes are believed not differentially expressed between any pair of the samples. You can change the normalisation method under **Advanced Options** above. For more information, see the `calcNormFactors` section in the `edgeR User's Guide`_. + +**Robust Settings** +Option to use robust settings. Using robust settings (robust=TRUE) with the edgeR estimateDisp and glmQLFit functions is usually recommended to protect against outlier genes. This is turned on by default. Note that it is only used with the quasi-likelihood F test method. For more information, see the `edgeR workflow article`_. + +**Test Method** +Option to use the likelihood ratio test instead of the quasi-likelihood F test. For more information, see the `edgeR workflow article`_. + +.. _edgeR User's Guide: http://www.bioconductor.org/packages/release/bioc/html/edgeR.html + +----- + +**Outputs** + +This tool outputs + + * a table of differentially expressed genes for each contrast of interest + * a HTML report with plots and additional information + +Optionally, under **Output Options** you can choose to output + + * a normalised counts table + * an RData file + +----- + +**Citations** + +Please try to cite the appropriate articles when you publish results obtained using software, as such citation is the main means by which the authors receive credit for their work. For the edgeR method itself, please cite Robinson et al., 2010, and for this tool (which was developed from the Galaxy limma-voom tool) please cite Liu et al., 2015. + + ]]></help> + <citations> + <citation type="doi">10.1093/bioinformatics/btp616</citation> + <citation type="doi">10.1093/nar/gkv412</citation> + </citations> +</tool>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/Mut1.counts Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +GeneID Mut1 +11287 1463 +11298 1345 +11302 5 +11303 1574 +11304 361 +11305 1762
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/Mut2.counts Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +GeneID Mut2 +11287 1441 +11298 1291 +11302 6 +11303 1519 +11304 397 +11305 1942
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/Mut3.counts Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +GeneID Mut3 +11287 1495 +11298 1346 +11302 5 +11303 1654 +11304 346 +11305 2027
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/WT1.counts Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +GeneID WT1 +11287 1699 +11298 1905 +11302 6 +11303 2099 +11304 356 +11305 2528
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/WT2.counts Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +GeneID WT2 +11287 1528 +11298 1744 +11302 8 +11303 1974 +11304 312 +11305 2438
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/WT3.counts Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +GeneID WT3 +11287 1601 +11298 1834 +11302 7 +11303 2100 +11304 337 +11305 2493
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/anno.txt Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +EntrezID Symbol GeneName Chr Length +11287 Pzp pregnancy zone protein 6 4681 +11298 Aanat arylalkylamine N-acetyltransferase 11 1455 +11302 Aatk apoptosis-associated tyrosine kinase 11 5743 +11303 Abca1 ATP-binding cassette, sub-family A (ABC1), member 1 4 10260 +11304 Abca4 ATP-binding cassette, sub-family A (ABC1), member 4 3 7248 +11305 Abca2 ATP-binding cassette, sub-family A (ABC1), member 2 2 8061 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/edgeR_Mut-WT.tsv Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +"GeneID" "logFC" "logCPM" "F" "PValue" "FDR" +"11304" 0.458203001410391 15.530162861746 32.6285109553746 6.943370724917e-06 4.1660224349502e-05 +"11287" 0.188840644104212 17.6536729774735 20.5671667733158 0.000135453949597801 0.000406361848793403 +"11298" -0.138359578382475 17.6815280107154 10.8470695851279 0.00306012801564425 0.00612025603128849 +"11303" -0.0561156581317604 17.8897677663033 1.50815092591008 0.231329593888878 0.346994390833318 +"11305" -0.0579340818829784 18.1615839598046 1.09689306676368 0.305382540289637 0.366459048347564 +"11302" -0.0682406105165454 10.0898264751075 0.137130529665157 0.884266488139469 0.884266488139469
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/edgeR_Mut-WT_2fact.tsv Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +"GeneID" "logFC" "logCPM" "F" "PValue" "FDR" +"11287" 0.189281291475186 17.6499778192954 198.646314971919 7.90598427634257e-09 4.74359056580554e-08 +"11298" -0.13798041694802 17.6843133699537 96.2224552671758 4.15830411749776e-06 1.24749123524933e-05 +"11304" 0.458490715244216 15.526484673111 14.5864146735617 0.00244295799161999 0.00488591598323999 +"11303" -0.0560600217169691 17.8909334307093 6.5300693781724 0.0442859767053646 0.0664289650580469 +"11305" -0.0585095825423414 18.1629882429457 1.07140336604322 0.32103822810743 0.385245873728916 +"11302" -0.0716631320244627 10.0898336653124 0.376796260571098 0.878304702615846 0.878304702615846
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/edgeR_Mut-WT_2fact_anno.tsv Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +"EntrezID" "Symbol" "GeneName" "Chr" "Length" "logFC" "logCPM" "F" "PValue" "FDR" +11287 "Pzp" "pregnancy zone protein" 6 4681 0.189281947498313 17.6499778192954 198.646315096405 7.90598424818912e-09 4.74359054891347e-08 +11298 "Aanat" "arylalkylamine N-acetyltransferase" 11 1455 -0.137980416947824 17.6843133699537 96.2224553233548 4.15830411749738e-06 1.24749123524921e-05 +11304 "Abca4" "ATP-binding cassette, sub-family A (ABC1), member 4" 3 7248 0.45849071524422 15.526484673111 14.5864146737822 0.00244295799149183 0.00488591598298366 +11303 "Abca1" "ATP-binding cassette, sub-family A (ABC1), member 1" 4 10260 -0.0560600215744048 17.8909334307093 6.53006938009001 0.0442859767053567 0.066428965058035 +11305 "Abca2" "ATP-binding cassette, sub-family A (ABC1), member 2" 2 8061 -0.0585095828508861 18.1629882429457 1.07140336564628 0.321038228193371 0.385245873832045 +11302 "Aatk" "apoptosis-associated tyrosine kinase" 11 5743 -0.0716631320197652 10.0898336653124 0.376796260576848 0.878304702615841 0.878304702615841
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/edgeR_Mut-WT_anno.tsv Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +"EntrezID" "Symbol" "GeneName" "Chr" "Length" "logFC" "logCPM" "F" "PValue" "FDR" +11304 "Abca4" "ATP-binding cassette, sub-family A (ABC1), member 4" 3 7248 0.458203001410391 15.530162861746 32.6285109553746 6.943370724917e-06 4.1660224349502e-05 +11287 "Pzp" "pregnancy zone protein" 6 4681 0.188840644104212 17.6536729774735 20.5671667733158 0.000135453949597801 0.000406361848793403 +11298 "Aanat" "arylalkylamine N-acetyltransferase" 11 1455 -0.138359578382475 17.6815280107154 10.8470695851279 0.00306012801564425 0.00612025603128849 +11303 "Abca1" "ATP-binding cassette, sub-family A (ABC1), member 1" 4 10260 -0.0561156581317604 17.8897677663033 1.50815092591008 0.231329593888878 0.346994390833318 +11305 "Abca2" "ATP-binding cassette, sub-family A (ABC1), member 2" 2 8061 -0.0579340818829784 18.1615839598046 1.09689306676368 0.305382540289637 0.366459048347564 +11302 "Aatk" "apoptosis-associated tyrosine kinase" 11 5743 -0.0682406105165454 10.0898264751075 0.137130529665157 0.884266488139469 0.884266488139469
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/edgeR_Mut-WT_filt.tsv Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,6 @@ +"GeneID" "logFC" "logCPM" "F" "PValue" "FDR" +"11287" 0.187201149217925 17.6526225386971 165.500659651998 5.18054239620105e-10 2.59027119810053e-09 +"11298" -0.140077523013286 17.6838446963123 82.0496288033128 2.92613742709898e-06 7.31534356774746e-06 +"11304" 0.456820345055957 15.5288695886958 25.2675517854784 6.46433259176098e-05 0.00010773887652935 +"11303" -0.0578468398229744 17.8912127135125 5.26103367901545 0.0384341523491632 0.048042690436454 +"11305" -0.0593023205976883 18.1634104549086 0.864302521617601 0.363623540536245 0.363623540536245
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/edgeR_WT-Mut.tsv Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +"GeneID" "logFC" "logCPM" "F" "PValue" "FDR" +"11304" -0.458203001410391 15.530162861746 32.6285109553746 6.943370724917e-06 4.1660224349502e-05 +"11287" -0.188840644104212 17.6536729774735 20.5671667733158 0.000135453949597801 0.000406361848793403 +"11298" 0.138359578382475 17.6815280107154 10.8470695851279 0.00306012801564425 0.00612025603128849 +"11303" 0.0561156581317604 17.8897677663033 1.50815092591008 0.231329593888878 0.346994390833318 +"11305" 0.0579340818829784 18.1615839598046 1.09689306676368 0.305382540289637 0.366459048347564 +"11302" 0.0682406105165454 10.0898264751075 0.137130529665157 0.884266488139469 0.884266488139469
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/edgeR_WT-Mut_2fact_anno.tsv Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +"EntrezID" "Symbol" "GeneName" "Chr" "Length" "logFC" "logCPM" "F" "PValue" "FDR" +11287 "Pzp" "pregnancy zone protein" 6 4681 -0.189281947498313 17.6499778192954 198.646315096405 7.90598424818912e-09 4.74359054891347e-08 +11298 "Aanat" "arylalkylamine N-acetyltransferase" 11 1455 0.137980416947824 17.6843133699537 96.2224553233548 4.15830411749738e-06 1.24749123524921e-05 +11304 "Abca4" "ATP-binding cassette, sub-family A (ABC1), member 4" 3 7248 -0.45849071524422 15.526484673111 14.5864146737822 0.00244295799149183 0.00488591598298366 +11303 "Abca1" "ATP-binding cassette, sub-family A (ABC1), member 1" 4 10260 0.0560600215744048 17.8909334307093 6.53006938009001 0.0442859767053567 0.066428965058035 +11305 "Abca2" "ATP-binding cassette, sub-family A (ABC1), member 2" 2 8061 0.0585095828508861 18.1629882429457 1.07140336564628 0.321038228193371 0.385245873832045 +11302 "Aatk" "apoptosis-associated tyrosine kinase" 11 5743 0.0716631320197652 10.0898336653124 0.376796260576848 0.878304702615841 0.878304702615841
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/edgeR_normcounts.tsv Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +"GeneID" "Mut1" "Mut2" "Mut3" "WT1" "WT2" "WT3" +"11287" 17.7717801382127 17.7103668584544 17.7656984572699 17.6075444214943 17.5078565133576 17.5637960881114 +"11298" 17.6504754185442 17.55181161064 17.6142553019077 17.7726234935868 17.6985800110028 17.7597848438911 +"11302" 9.64041099082467 9.8551982993804 9.60469198931215 9.52851478148979 9.97869946791847 9.78190633986473 +"11303" 17.8772707356813 17.7864068634935 17.9114914356477 17.9125147871338 17.8772755854201 17.9551530504837 +"11304" 15.753577788623 15.8510977521242 15.6551142861549 15.3537170121875 15.2168364952853 15.3165751633072 +"11305" 18.0400277799982 18.1407817993511 18.2048423497925 18.1807759635442 18.1818136580236 18.2026167343562
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/edgeR_normcounts_anno.tsv Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +"EntrezID" "Symbol" "GeneName" "Chr" "Length" "Mut1" "Mut2" "Mut3" "WT1" "WT2" "WT3" +11287 "Pzp" "pregnancy zone protein" 6 4681 17.7717801382127 17.7103668584544 17.7656984572699 17.6075444214943 17.5078565133576 17.5637960881114 +11298 "Aanat" "arylalkylamine N-acetyltransferase" 11 1455 17.6504754185442 17.55181161064 17.6142553019077 17.7726234935868 17.6985800110028 17.7597848438911 +11302 "Aatk" "apoptosis-associated tyrosine kinase" 11 5743 9.64041099082467 9.8551982993804 9.60469198931215 9.52851478148979 9.97869946791847 9.78190633986473 +11303 "Abca1" "ATP-binding cassette, sub-family A (ABC1), member 1" 4 10260 17.8772707356813 17.7864068634935 17.9114914356477 17.9125147871338 17.8772755854201 17.9551530504837 +11304 "Abca4" "ATP-binding cassette, sub-family A (ABC1), member 4" 3 7248 15.753577788623 15.8510977521242 15.6551142861549 15.3537170121875 15.2168364952853 15.3165751633072 +11305 "Abca2" "ATP-binding cassette, sub-family A (ABC1), member 2" 2 8061 18.0400277799982 18.1407817993511 18.2048423497925 18.1807759635442 18.1818136580236 18.2026167343562
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/factorinfo.txt Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +Sample Genotype Batch +Mut1 Mut b1 +Mut2 Mut b2 +Mut3 Mut b3 +WT1 WT b1 +WT2 WT b2 +WT3 WT b3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/matrix.txt Tue Nov 07 08:18:14 2017 -0500 @@ -0,0 +1,7 @@ +GeneID Mut1 Mut2 Mut3 WT1 WT2 WT3 +11287 1463 1441 1495 1699 1528 1601 +11298 1345 1291 1346 1905 1744 1834 +11302 5 6 5 6 8 7 +11303 1574 1519 1654 2099 1974 2100 +11304 361 397 346 356 312 337 +11305 1762 1942 2027 2528 2438 2493