diff --git a/QoRTs-vignette.pdf b/QoRTs-vignette.pdf index ee35a25..ab5a89c 100644 Binary files a/QoRTs-vignette.pdf and b/QoRTs-vignette.pdf differ diff --git a/QoRTs.jar b/QoRTs.jar index 646480f..c93bf72 100644 Binary files a/QoRTs.jar and b/QoRTs.jar differ diff --git a/QoRTs_1.2.42.tar.gz b/QoRTs_1.2.42.tar.gz new file mode 100644 index 0000000..fe096d4 Binary files /dev/null and b/QoRTs_1.2.42.tar.gz differ diff --git a/README.md b/README.md index 5c557e9..1d01656 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# QoRTs v1.2.37 -(Compiled Mon May 1 14:23:33 EDT 2017) +# QoRTs v1.2.42 +(Compiled Fri Jun 2 12:23:55 EDT 2017) The [QoRTs software package](http://hartleys.github.io/QoRTs/) is a fast, efficient, and portable multifunction toolkit designed to assist in diff --git a/example-walkthrough.pdf b/example-walkthrough.pdf index f432f9c..08bf239 100644 Binary files a/example-walkthrough.pdf and b/example-walkthrough.pdf differ diff --git a/src/HartleyUtils/src/main/scala/internalUtils/genomicAnnoUtils.scala b/src/HartleyUtils/src/main/scala/internalUtils/genomicAnnoUtils.scala index a578be0..93ca039 100644 --- a/src/HartleyUtils/src/main/scala/internalUtils/genomicAnnoUtils.scala +++ b/src/HartleyUtils/src/main/scala/internalUtils/genomicAnnoUtils.scala @@ -154,24 +154,27 @@ object genomicAnnoUtils { } class EfficientGenomeSeqContainer_MFA(infile : String) extends EfficientGenomeSeqContainer { + //Implementation note: It is important that you never read from remainderIter without first emptying currentIter! + // Otherwise scala attempts to store the currentIter values. + // This even remains true if there are no external references to the attached currentIter. def switchToChrom(chrom : String){ - var iterPair = remainderIter.span(line => line != (">"+chrom)); - if(iterPair._2.hasNext){ - iterPair = iterPair._2.drop(1).span(line => line.charAt(0) != '>'); - } else { - iterPair = internalUtils.fileUtils.getLinesSmartUnzip(infile).span(line => line != (">"+chrom)); - if(iterPair._2.hasNext){ + report("Switching to Chromosome: " + chrom + " ["+getDateAndTimeString+"] ... ","debug"); + while(currentIter.hasNext) currentIter.next; + var iter = remainderIter.dropWhile(line => line != (">"+chrom)); + if(! iter.hasNext){ + iter = internalUtils.fileUtils.getLinesSmartUnzip(infile).dropWhile(line => line != (">"+chrom)); + if(iter.hasNext){ reportln("Returning to start of genome FASTA file. NOTE: for optimal performance, sort the FASTA file so that the chromosomes appear in the same order as in the BAM files.","note"); - iterPair = iterPair._2.drop(1).span(line => line.charAt(0) != '>'); } else { error("FATAL ERROR: Cannot find chromosome \""+chrom+"\" in genome FASTA file!") } } - reportln("Switching to Chromosome: " + chrom,"debug"); + val iterPair = iter.drop(1).span(line => line.charAt(0) != '>'); currentIter = iterPair._1.map(_.toUpperCase()); remainderIter = iterPair._2; clearBuffer(); currChrom = chrom; + report("done ["+getDateAndTimeString+"]\n","debug"); } var initialReader = internalUtils.fileUtils.getLinesSmartUnzip(infile); diff --git a/src/HartleyUtils/src/main/scala/runner/runner.scala b/src/HartleyUtils/src/main/scala/runner/runner.scala index ff0d67d..5626121 100644 --- a/src/HartleyUtils/src/main/scala/runner/runner.scala +++ b/src/HartleyUtils/src/main/scala/runner/runner.scala @@ -9,9 +9,9 @@ import internalUtils.commandLineUI._; object runner { - final val QORTS_VERSION = "1.2.37"; // REPLACE_THIS_QORTS_VERSION_VARIABLE_WITH_VERSION_NUMBER (note this exact text is used in a search-and-replace. Do not change it.) - final val QORTS_COMPILE_DATE = "Mon May 1 14:23:33 EDT 2017"; // REPLACE_THIS_QORTS_DATE_VARIABLE_WITH_DATE (note this exact text is used in a search-and-replace. Do not change it.) - final val QORTS_COMPILE_TIME : Long = 1493663013; // REPLACE_THIS_QORTS_DATE_VARIABLE_WITH_TIME (note this exact text is used in a search-and-replace. Do not change it.) + final val QORTS_VERSION = "1.2.42"; // REPLACE_THIS_QORTS_VERSION_VARIABLE_WITH_VERSION_NUMBER (note this exact text is used in a search-and-replace. Do not change it.) + final val QORTS_COMPILE_DATE = "Fri Jun 2 12:23:55 EDT 2017"; // REPLACE_THIS_QORTS_DATE_VARIABLE_WITH_DATE (note this exact text is used in a search-and-replace. Do not change it.) + final val QORTS_COMPILE_TIME : Long = 1496420635; // REPLACE_THIS_QORTS_DATE_VARIABLE_WITH_TIME (note this exact text is used in a search-and-replace. Do not change it.) final val QORTS_MAJOR_VERSION = QORTS_VERSION.split("\\.")(0); final val QORTS_MINOR_VERSION = QORTS_VERSION.split("\\.")(1); diff --git a/src/QoRTs/DESCRIPTION b/src/QoRTs/DESCRIPTION index 5b31d63..74d80d8 100644 --- a/src/QoRTs/DESCRIPTION +++ b/src/QoRTs/DESCRIPTION @@ -1,6 +1,6 @@ Package: QoRTs -Version: 1.2.37 -Date: 2017-05-01 +Version: 1.2.42 +Date: 2017-06-02 Title: Quality of RNA-seq Tool Authors@R: c(person("Stephen Hartley, PhD", "Developer", role = c("aut", "cre"), email = "QoRTs-contact@list.nih.gov")) diff --git a/src/QoRTs/NAMESPACE b/src/QoRTs/NAMESPACE index e81089b..5f895bc 100644 --- a/src/QoRTs/NAMESPACE +++ b/src/QoRTs/NAMESPACE @@ -16,6 +16,7 @@ export( build.plotter.colorByLane, build.plotter.colorByGroup, build.plotter.basic, + build.plotter.advanced, #Specific Plots: makePlot.qual.pair, diff --git a/src/QoRTs/R/external.plotting.func.R b/src/QoRTs/R/external.plotting.func.R index ad24c1e..1cf3cce 100644 --- a/src/QoRTs/R/external.plotting.func.R +++ b/src/QoRTs/R/external.plotting.func.R @@ -4413,7 +4413,9 @@ makePlot.legend.box <- function(plotter,debugMode = DEFAULTDEBUGMODE, singleEndM plotter.error.wrapper(plot.name, plotterFcn = function(){ plotter.NVC <- plotter; plot(0,0,col="transparent",xlim=c(0,1),ylim=c(0,1), axes=F,xlab="",ylab=""); - + + diff.text <- "Colored/Marked"; + #internal.plot.legend(plotter,"lines","bottomleft"); #internal.plot.legend(plotter,"points","bottomright"); if(is.null(plotter$title.annotations[["main.subtitle"]])){ @@ -4459,6 +4461,12 @@ makePlot.legend.box <- function(plotter,debugMode = DEFAULTDEBUGMODE, singleEndM } else if(plotter$plot.type == "colorByX"){ title.text <- paste0("Summary Plots, By ",plotter$title.highlight.name) title.cex <- fit.character.vector(title.text); + } else if(plotter$plot.type == "highlightByX"){ + title.text <- paste0("Summary Plots\n",plotter$title.annotations[["highlight.by.title.name"]],"=",plotter$title.annotations[["highlight"]]," Highlighted") + title.cex <- fit.character.vector(title.text); + } else if(plotter$plot.type == "colorByXhighlightByY"){ + title.text <- paste0("Summary Plots\n",plotter$title.annotations[["highlight.by.title.name"]],"=",plotter$title.annotations[["highlight"]]," Highlighted\n",diff.text," by ",plotter$title.annotations[["color.by.title.name"]]) + title.cex <- fit.character.vector(title.text); } else { title.text <- paste0("Summary Plots, Custom"); title.cex <- fit.character.vector(title.text); diff --git a/src/QoRTs/R/internal.plotting.func.R b/src/QoRTs/R/internal.plotting.func.R index 7f4f46e..ba0ff9a 100644 --- a/src/QoRTs/R/internal.plotting.func.R +++ b/src/QoRTs/R/internal.plotting.func.R @@ -2416,14 +2416,16 @@ internal.plot.legend <- function(plotter, legend.type, legend.pos, } else if(plotter$plot.type == "colorByLane"){ } else if(plotter$plot.type == "colorBySample"){ } else if(plotter$plot.type == "colorByX"){ + } else if(plotter$plot.type == "highlightByX"){ + } else if(plotter$plot.type == "colorByXhighlightByY"){ } else if(plotter$plot.type == "summary"){ #Do nothing. plot nothing. return(""); } else { - #Do nothing. Plot nothing. - return(""); + #??? + #return(""); } @@ -2578,6 +2580,9 @@ internal.get.main.title.fragment <- function(plotter, plot.type){ if(plotter$plot.type == "colorByGroup") return(paste0("\n",diff.text," by Group")); if(plotter$plot.type == "colorBySample") return(paste0("\n",diff.text," by Sample")); if(plotter$plot.type == "colorByX") return(paste0("\n",diff.text," by ",plotter$title.highlight.name)); + if(plotter$plot.type == "highlightByX"){ + return(paste0("\n",plotter$title.annotations[["highlight.by.title.name"]],"=",plotter$title.annotations[["highlight"]]," Highlighted")); + } if(plotter$plot.type == "colorByXhighlightByY"){ #return(paste0("\n",plotter$title.annotations[["highlight"]]," Highlighted, ",diff.text," by ",plotter$title.annotations[["color.by.title.name"]])); return(paste0("\n",plotter$title.annotations[["highlight.by.title.name"]],"=",plotter$title.annotations[["highlight"]]," Highlighted, ",diff.text," by ",plotter$title.annotations[["color.by.title.name"]])); diff --git a/src/QoRTs/R/plot.param.builders.R b/src/QoRTs/R/plot.param.builders.R index 7f25ef4..2b9ecd6 100644 --- a/src/QoRTs/R/plot.param.builders.R +++ b/src/QoRTs/R/plot.param.builders.R @@ -114,6 +114,8 @@ build.plotter.colorBySample <- function(res, plotter.params = list()){ final.params <- merge.plotting.params(defaultParams,plotter.params); compiled.params <- compile.plotting.params(final.params); + + return(build.plotter.color( res = res, compiled.params = compiled.params, @@ -159,6 +161,108 @@ build.plotter.colorByX <- function(res, color.by.name, color.by.title.name = col ######################################################### +build.plotter.advanced <- function(res, + colorBy = NULL, + color.title = "?", + highlightBy = NULL, + highlight = "CURR", + highlightTitle.singular = NULL, + highlightTitle.plural = highlightTitle.singular, + outgroup.title = "Other", + plotter.params = list()){ + if(is.null(highlightBy) && is.null(colorBy)){ + return(build.plotter.basic(res=res,plotter.params=plotter.params)); + } else if(is.null(highlightBy)){ + base.defaultParams <- QoRTs.default.plotting.params; + defaultParams <- merge.plotting.params(base.defaultParams,list(std.lines.alpha = 125)); + final.params <- merge.plotting.params(defaultParams,plotter.params); + compiled.params <- compile.plotting.params(final.params); + + if(length(colorBy) == nrow(res@decoder) && any(names(colorBy) != res@decoder$unique.ID)){ + stop("Error: colorBy vector must be named with unique ID's and be in the correct order!"); + } + + colorBy <- ifelse(is.na(colorBy),"NA",colorBy); + + return(build.plotter.color( + res = res, + compiled.params = compiled.params, + color.by = colorBy, + plot.type = "colorByX", + color.by.title.name = color.title, + title.annotations = list( + color.by.title.name = color.title) + )); + } else if(is.null(colorBy)){ + if(is.null(highlightTitle.singular)) highlightTitle.singular <- deparse(substitute(highlightBy)); + if(is.null(highlightTitle.plural)) highlightTitle.plural <- highlightTitle.singular; + + if(length(highlightBy) == nrow(res@decoder) && any(names(highlightBy) != res@decoder$unique.ID)){ + stop("Error: highlightBy vector must be named with unique.ID's and be in the same order as res@decoder$unique.ID"); + } + + base.defaultParams <- QoRTs.default.plotting.params; + defaultParams <- merge.plotting.params(base.defaultParams,list()); + final.params <- merge.plotting.params(defaultParams,plotter.params); + compiled.params <- compile.plotting.params(final.params); + + return(build.plotter.highlight(highlight, + res = res, + compiled.params = compiled.params, + highlight.by = highlightBy, + plot.type = "highlightByX", + offset.by = ifelse(highlightBy == highlight,"1","0"), + merge.offset.outgroup = TRUE, + title.annotations = list(highlight=highlight, + highlight.by.name=highlightTitle.plural, + highlight.by.title.name = highlightTitle.singular), + outgroup.name = paste0(outgroup.title), + highlightTitle.plural = highlightTitle.plural + )); + } else { + if(is.null(highlightTitle.singular)) highlightTitle.singular <- deparse(substitute(highlightBy)); + if(is.null(highlightTitle.plural)) highlightTitle.plural <- highlightTitle.singular; + + base.defaultParams <- QoRTs.default.plotting.params; + defaultParams <- merge.plotting.params(base.defaultParams,list(std.lines.alpha = 125)); + final.params <- merge.plotting.params(defaultParams,plotter.params); + compiled.params <- compile.plotting.params(final.params); + + if(length(colorBy) == nrow(res@decoder) && any(names(colorBy) != res@decoder$unique.ID)){ + stop("Error: colorBy vector must be named with unique ID's and be in the correct order!"); + } + if(length(highlightBy) == nrow(res@decoder) && any(names(highlightBy) != res@decoder$unique.ID)){ + stop("Error: highlightBy vector must be named with unique.ID's and be in the same order as res@decoder$unique.ID"); + } + + colorBy <- ifelse(is.na(colorBy),"NA",colorBy); + highlightLogical <- f.na(highlightBy == highlight); + highlightBy[!highlightLogical] <- outgroup.title; + + color.highlighted.by <- colorBy; + + plotter <- + build.plotter.highlight.and.color(curr.highlight = highlight, + res=res, + compiled.params=compiled.params, + highlight.by = highlightBy, + color.highlighted.by = color.highlighted.by, + title.annotations = list(highlight=highlight, + highlight.by.name=highlightTitle.plural, + highlight.by.title.name = highlightTitle.singular, + color.by.title.name = color.title), + plot.type="colorByXhighlightByY", + offset.by = color.highlighted.by, + merge.offset.outgroup = TRUE, + pch.matched.with.color = TRUE, + highlighted.by.name = highlightTitle.plural) + return(plotter) + } +} + +######################################################### +######################################################### + build.plotter.colorByVector <- function(res, colorBy, color.by.title.name = "?", plotter.params = list()){ base.defaultParams <- QoRTs.default.plotting.params; defaultParams <- merge.plotting.params(base.defaultParams,list(std.lines.alpha = 125)); @@ -180,6 +284,7 @@ build.plotter.colorByVector <- function(res, colorBy, color.by.title.name = "?", color.by.title.name = color.by.title.name)); } + build.plotter.colorAndHighlightByVector <- function(res, colorBy, color.by.title.name = "?", @@ -217,6 +322,7 @@ build.plotter.colorAndHighlightByVector <- function(res, return(plotter) } + build.plotter.colorAndHighlightBySampleVector <- function(res, colorBy, color.by.title.name = "?", highlightList, plotter.params = list()){ @@ -336,6 +442,131 @@ build.plotter.basic.helper <- function(res, offset.by, compiled.params, plot.typ ################################################################################################################## ################################################################################################################## + +build.plotter.advanced.internal <- function(curr.highlight, res, compiled.params, highlight.by, color.highlighted.by, plot.type, offset.by = color.highlighted.by, merge.offset.outgroup = TRUE, pch.matched.with.color = TRUE, highlighted.by.name = "Samples",title.annotations=list()){ + if(! is.null(check.isValid(res))){ + #THROW AN ERROR! + stop("Error parsing results: ", check.isValid(res)); + } + if(length(highlight.by) != length(color.highlighted.by)) stop("error: length(highlight.by) != length(color.highlighted.by)\n length(highlight.by) = ",length(highlight.by),", length(color.highlighted.by) = ",length(color.highlighted.by)); + if(length(highlight.by) != length(res@decoder$unique.ID)) stop("error: length(highlight.by) != length(res@decoder$unique.ID)\n length(highlight.by) = ",length(highlight.by),", length(res@decoder$unique.ID) = ",length(res@decoder$unique.ID)); + if(! (curr.highlight %in% highlight.by)){ + stop("FATAL ERROR! ","Cannot find highlighted element ", curr.highlight," in the highlight list!"); + } + + #plotParams <- new("QoRT_Plotter"); + #plotParams@res <- res; + #plotParams@plot.type <- plot.type; + title.highlight.name <- curr.highlight; + showLegend <- compiled.params@showLegend; + nvc.colors <- compiled.params@nvc.colors; + nvc.colors.light <- compiled.params@nvc.colors.light; + + is.highlighted <- highlight.by == curr.highlight; + lanebam.ct <- length(highlight.by); + hl.by.factor <- color.highlighted.by[is.highlighted ]; + hl.by.factor.levels <- sort(unique(hl.by.factor)); + + if(length(hl.by.factor.levels) > length(compiled.params@by.colors)) { + message("WARNING WARNING WARNING: Too many categories to color! (Max = ",length(compiled.params@by.colors),", curr = ",length(hl.by.factor.levels),") Add more colors? Falling back to a rainbow palette"); + compiled.params@by.colors <- rainbow(length(hl.by.factor.levels)); + } + if(pch.matched.with.color){ + if(length(hl.by.factor.levels) > length(compiled.params@by.pch)){ + message("WARNING WARNING WARNING: Too many categories to mark distinct with pch! (Max = ",length(compiled.params@by.pch),", curr = ",length(hl.by.factor.levels),") Add more colors? Falling back to a repeating pattern."); + compiled.params@by.pch <- rep(compiled.params@by.pch, ceiling( length(hl.by.factor.levels) / length(compiled.params@by.pch))); + } + legend.points.pch <- compiled.params@by.pch[1:length(hl.by.factor.levels)]; + } else { + legend.points.pch <- rep(compiled.params@highlight.points.pch[1], length(hl.by.factor.levels)); + } + + legend.params <- data.frame(name = c(hl.by.factor.levels, paste0("Other ",highlighted.by.name)), + lines.col = c(compiled.params@by.colors[1:length(hl.by.factor.levels)], compiled.params@highlight.color[2]), + lines.lty = c(rep(compiled.params@highlight.lines.lty[1],length(hl.by.factor.levels)), compiled.params@highlight.lines.lty[2]), + points.pch = c(legend.points.pch, compiled.params@highlight.points.pch[2]), + points.col = c(compiled.params@by.colors[1:length(hl.by.factor.levels)], compiled.params@highlight.color[2]), + stringsAsFactors=F + ); + + lines.col <- sapply(1:lanebam.ct, FUN=function(i){ + if(! is.highlighted[i]){ return(compiled.params@highlight.color[2]); + } else {return( legend.params$lines.col[ legend.params$name == color.highlighted.by[i] ] );} + }); + points.col <- sapply(1:lanebam.ct, FUN=function(i){ + if(! is.highlighted[i]){ return(compiled.params@highlight.color[2]); + } else {return( legend.params$points.col[ legend.params$name == color.highlighted.by[i] ] );} + }); + + if(pch.matched.with.color){ + #message("!!!"); + if(length(hl.by.factor.levels) > length(compiled.params@by.pch)) stop("to many categories in by.colors! Add more pch values to compiled.params@by.pch!"); + points.pch <- sapply(1:lanebam.ct, FUN=function(i){ + if(! is.highlighted[i]){ return(compiled.params@highlight.points.pch[2]); + } else {return( legend.params$points.pch[ legend.params$name == color.highlighted.by[i] ] );} + }); + #message(paste("compiled.params@highlight.points.pch: ",compiled.params@highlight.points.pch,collapse=",")); + #message(paste("compiled.params@highlight.points.pch: ",compiled.params@highlight.points.pch,collapse=",")); + #message(paste("points.pch: ",points.pch,collapse=",")); + } else { + points.pch <- ifelse(is.highlighted, compiled.params@highlight.points.pch[1], compiled.params@highlight.points.pch[2]) + } + + + + if(merge.offset.outgroup){ + offset.by.vals <- sort(unique(offset.by[is.highlighted])); + if( all(offset.by %in% offset.by.vals)){ + offset.ct <- length(offset.by.vals) ; + } else { + offset.ct <- length(offset.by.vals) + 1; + } + } else { + offset.by.vals <- sort(unique(offset.by)); + offset.ct <- length(offset.by.vals) ; + } + if(offset.ct %% 2 == 0){ + offsets <- (((1:offset.ct) / (offset.ct)) ); + offsets <- offsets - ( offsets[ offset.ct / 2 + 1] + offsets[ offset.ct / 2 ] ) / 2 + } else { + offsets <- (((1:offset.ct) / (offset.ct)) - 0.5 ); + offsets <- offsets - offsets[ (offset.ct + 1) / 2 ]; + } + + lanebam.offset.indices <- sapply(1:lanebam.ct, FUN=function(i){ + if(any(offset.by.vals == offset.by[i])){ + which(offset.by.vals == offset.by[i]); + } else { + offset.ct; + } + }); + lanebam.offsets <- offsets[lanebam.offset.indices]; + + lanebam.params <- data.frame( plot.priority = ifelse(is.highlighted, 2,1), + unique.ID = res@decoder$unique.ID, + lines.col = lines.col, + points.col = points.col, + points.pch = points.pch, + lines.lty = ifelse(is.highlighted, compiled.params@highlight.lines.lty[1], compiled.params@highlight.lines.lty[2]), + lines.lwd = ifelse(is.highlighted, compiled.params@highlight.lines.lwd[1], compiled.params@highlight.lines.lwd[2]), + lines.alpha = ifelse(is.highlighted, compiled.params@highlight.lines.alpha[1], compiled.params@highlight.lines.alpha[2]), + points.alpha = ifelse(is.highlighted, compiled.params@highlight.points.alpha[1], compiled.params@highlight.points.alpha[2]), + horiz.offsets = lanebam.offsets, + vert.offsets = lanebam.offsets, + stringsAsFactors=F + ); + lanebam.params$lines.tcol <- color2transparent(lanebam.params$lines.col,lanebam.params$lines.alpha); + lanebam.params$points.tcol <- color2transparent(lanebam.params$points.col,lanebam.params$points.alpha); + + plotParams <- generate.plotter(res = res, plot.type = plot.type, title.highlight.name = title.highlight.name, legend.params = legend.params, showLegend = showLegend, nvc.colors = nvc.colors, nvc.colors.light = nvc.colors.light, lanebam.params = lanebam.params,randomize.plot.order=compiled.params@randomize.plot.order, + title.annotations=c(title.annotations,compiled.params@plot.annotation)) + return(plotParams); +} + +################################################################################################################## +################################################################################################################## +################################################################################################################## + build.plotter.highlight.and.color <- function(curr.highlight, res, compiled.params, highlight.by, color.highlighted.by, plot.type, offset.by = color.highlighted.by, merge.offset.outgroup = TRUE, pch.matched.with.color = TRUE, highlighted.by.name = "Samples",title.annotations=list()){ if(! is.null(check.isValid(res))){ #THROW AN ERROR! @@ -667,7 +898,9 @@ build.plotter.highlight.OLD <- function(curr.highlight, res, compiled.params, hi build.plotter.highlight <- function(curr.highlight, res, - title.highlight.name=curr.highlight, compiled.params, highlight.by, plot.type, offset.by, merge.offset.outgroup = TRUE,title.annotations=list()){ + title.highlight.name=curr.highlight, compiled.params, highlight.by, plot.type, offset.by, merge.offset.outgroup = TRUE,title.annotations=list(), + outgroup.name = "Other", + highlightTitle.plural = "Samples", highlightTitle.singular = "Sample"){ if(! is.null(check.isValid(res))){ #THROW AN ERROR! stop("Error parsing results: ", check.isValid(res)); @@ -691,7 +924,7 @@ build.plotter.highlight <- function(curr.highlight, res, is.highlighted <- highlight.by %in% curr.highlight; lanebam.ct <- length(highlight.by); - legend.params <- data.frame(name = c(title.highlight.name,"Other Samples"), + legend.params <- data.frame(name = c(title.highlight.name,paste0(outgroup.name," ",highlightTitle.plural)), lines.col = compiled.params@highlight.color, lines.lty = compiled.params@highlight.lines.lty, points.pch = compiled.params@highlight.points.pch, diff --git a/src/QoRTs/R/read.files.R b/src/QoRTs/R/read.files.R index 4673d0f..ca14525 100644 --- a/src/QoRTs/R/read.files.R +++ b/src/QoRTs/R/read.files.R @@ -174,7 +174,7 @@ expandAndCheckDecoder <- function(decoder) { subsetDecoder <- decoder[ decoder$sample.ID == samp,]; if(nrow(subsetDecoder) > 1){ if(length(unique(subsetDecoder$group.ID)) != 1){ - stop("Decoder error: sample ",samp," has inconsistent group.ID depending on decoder row: (",paste0(unique,collapse=","),")"); + stop("Decoder error: sample ",samp," has inconsistent group.ID depending on decoder row: (sample.ID=",samp," found in: ",paste0(unique(subsetDecoder$group.ID),collapse=","),")"); } } } diff --git a/src/QoRTs/man/build.plotter.Rd b/src/QoRTs/man/build.plotter.Rd index 165989d..fdcf2a3 100644 --- a/src/QoRTs/man/build.plotter.Rd +++ b/src/QoRTs/man/build.plotter.Rd @@ -9,6 +9,7 @@ \alias{build.plotter.colorBySample} \alias{build.plotter.basic} \alias{build.plotter.colorByX} +\alias{build.plotter.advanced} \alias{QoRTs.default.plotting.params} \alias{plotter} \title{ @@ -41,11 +42,24 @@ color.by.title.name = color.by.name, plotter.params = list()) + build.plotter.advanced(res, + colorBy = NULL, + color.title = "?", + highlightBy = NULL, + highlight = "CURR", + highlightTitle.singular = NULL, + highlightTitle.plural = highlightTitle.singular, + outgroup.title = "Other", + plotter.params = list()) + } \arguments{ \item{res}{ A \code{QoRT_QC_Results} object, created by \code{\link{read.qc.results.data}}. } + + + \item{curr.sample}{ A character string. For the sample highlight summary plots, this should be the sample.ID of the sample that is to be @@ -100,6 +114,28 @@ \item{lane.column.name}{ The name of the column in the decoder containing the "lane" names. } + + \item{colorBy}{ + A named character vector. Each unique colorBy string will be assigned a unique color. The names of colorBy must match \code{res@decoder$unique.ID}, and must be in the same order. + } + \item{color.title}{ + A character string. This is the title of the colorby category, used in the titles and figure legends. + } + \item{highlightBy}{ + A named character vector. Used to determine which replicates to highlight. The names of colorBy must match \code{res@decoder$unique.ID}, and must be in the same order. + } + \item{highlight}{ + A character string. Replicates where highlight equals highlightBy will be highlighted. + } + \item{highlightTitle.singular}{ + A character string. The singular form of the name of the category highlighted. + } + \item{highlightTitle.plural}{ + A character string. The plural form of the name of the category highlighted. + } + \item{outgroup.title}{ + A character string. The description of the non-highlighted category. Used in the figure legends. + } } \value{ A QoRT_Plotter reference object used to create QC summary plots. Depending on which plotter is used, samples/lane-bams can be organized by group, sample, lane, or any arbitrary variable found in the decoder. @@ -130,6 +166,81 @@ plotter.HSCBL <- build.plotter.highlightSample.colorByLane("SAMP1", res); makePlot.insert.size(plotter.HSCBL); makePlot.legend.over("topright",plotter.HSCBL); + + +#FOR ADVANCED USERS: +# With the build.plotter.advanced function, you can +# set coloring and highlighting to match anything you +# want. +# The parameters are a little more complex... + +#In order to control color, you must create a named +# vector with names equal to the unique.ID's +# in the decoder, and in the same order: +# (this requirement is purely to prevent mistakes) + +#For example: to color each sample differently: +colorBy <- res@decoder$sample.ID +names(colorBy) <- res@decoder$unique.ID; + +plotter <- build.plotter.advanced(res, colorBy = colorBy); +makePlot.insert.size(plotter); +makePlot.legend.over("topright",plotter); + +#Now, to highlight a subgroup of the dataset, you +# must set the "highlightBy" parameter to a +# named vector with names equal to the decoder +# unique.ID's, and in the same order. +# (this requirement is purely to prevent mistakes) +#Then you must tell the plotter which subgroup +# you want to highlight using the "highlight" +# parameter. + +#For example, to highlight all lanebams in lane L1: +highlightBy <- res@decoder$lane.ID +names(highlightBy) <- res@decoder$unique.ID; + +plotter <- build.plotter.advanced(res, + highlightBy = highlightBy, + highlight = "L1"); +makePlot.insert.size(plotter); +makePlot.legend.over("topright",plotter); + +#Other parameters are available to change the title +# and legends: +plotter <- build.plotter.advanced(res, + highlightBy = highlightBy, + highlight = "L1", + highlightTitle.singular = "Lane", + highlightTitle.plural = "Lanes", + outgroup.title = "Other"); +makePlot.insert.size(plotter); +makePlot.legend.over("topright",plotter); + +#You can also color and highlight together. +# If you do this, only the "highlighted" group will be +# colored, all the others will be colored gray and will be +# drawn in the background. This can be useful for finding +# biases that are restricted to a subset of the data. + +plotter <- build.plotter.advanced(res, + colorBy = colorBy, + highlightBy = highlightBy, + highlight = "L1", + color.title = "sample", + highlightTitle.singular = "Lane", + highlightTitle.plural = "Lanes", + outgroup.title = "Other" +); +makePlot.insert.size(plotter); +makePlot.legend.over("topright",plotter); + + +#You can make multiplots using a given plotter object by +# using the "makeMultiPlot.withPlotter" function: + +#makeMultiPlot.withPlotter(plotter); + } \seealso{