[med-svn] [r-bioc-limma] 03/11: Imported Upstream version 3.24.13+dfsg

Andreas Tille tille at debian.org
Fri Jul 31 17:11:22 UTC 2015


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-bioc-limma.

commit 802f30859a7f383b1faddcac7eb85088d13cc9a1
Author: Andreas Tille <tille at debian.org>
Date:   Sun Jul 19 18:14:10 2015 +0200

    Imported Upstream version 3.24.13+dfsg
---
 DESCRIPTION                       |  15 +-
 NAMESPACE                         |  18 +-
 R/alias2Symbol.R                  |  28 ++-
 R/arrayWeights.R                  |   7 +-
 R/auROC.R                         |  55 +++++
 R/background-normexp.R            |   6 +-
 R/classes.R                       |   2 +-
 R/dups.R                          |   8 +-
 R/fitFDistRobustly.R              |   6 +-
 R/genas.R                         |  19 +-
 R/geneset-camera.R                |  11 +-
 R/geneset-fry.R                   | 138 ++++++++++++
 R/geneset-ids2indices.R           |  14 ++
 R/geneset-roast.R                 |  14 +-
 R/geneset-romer.R                 | 435 +++++++++++++++-----------------------
 R/goana.R                         | 221 +++++++++++--------
 R/kegga.R                         | 277 ++++++++++++++++++++++++
 R/lmfit.R                         |  35 +--
 R/loessFit.R                      |  10 +-
 R/neqc.R                          |  22 +-
 R/norm.R                          |  24 ++-
 R/plot.R                          |  64 ------
 R/plotMD.R                        | 116 ++++++++++
 R/plotMDS.R                       |  80 ++++---
 R/plotWithHighlights.R            |  56 ++---
 R/plotdensities.R                 |  40 ++--
 R/plots-ma.R                      |  18 +-
 R/predFCm.R                       |  80 +++----
 R/read.idat.R                     |  24 ++-
 R/roc.R                           |  20 --
 R/sepchannel.R                    |   6 +-
 R/squeezeVar.R                    |   4 +-
 R/toptable.R                      |   3 +-
 R/venn.R                          |  73 +++++--
 R/voom.R                          |   6 +-
 R/write.R                         |  17 +-
 build/vignette.rds                | Bin 230 -> 231 bytes
 inst/CITATION                     |  25 ++-
 inst/NEWS.Rd                      | 113 ++++++++++
 inst/doc/changelog.txt            | 297 ++++++++++++++++++++++++--
 inst/doc/intro.pdf                | Bin 46191 -> 46191 bytes
 man/01Introduction.Rd             |  20 +-
 man/02classes.Rd                  |  15 ++
 man/03reading.Rd                  |  14 ++
 man/04Background.Rd               |  15 ++
 man/05Normalization.Rd            |  15 ++
 man/06linearmodels.Rd             |  18 ++
 man/07SingleChannel.Rd            |  15 ++
 man/08Tests.Rd                    |  14 ++
 man/09Diagnostics.Rd              |  36 +++-
 man/10GeneSetTests.Rd             |  34 ++-
 man/11RNAseq.Rd                   |  32 ++-
 man/EList.Rd                      |   1 +
 man/arrayWeights.Rd               |   2 +-
 man/arrayWeightsQuick.Rd          |   2 +-
 man/asmalist.Rd                   |   4 +-
 man/auROC.Rd                      |  14 +-
 man/backgroundcorrect.Rd          |   4 +-
 man/barcodeplot.Rd                |  25 ++-
 man/decideTests.Rd                |   7 +-
 man/diffSplice.Rd                 |   4 +-
 man/ebayes.Rd                     |   8 +-
 man/genas.Rd                      |  10 +
 man/getEAWP.Rd                    |   2 +-
 man/goana.MArrayLM.Rd             |  89 --------
 man/goana.Rd                      | 111 ++++++++--
 man/imageplot.Rd                  |   2 +-
 man/lmFit.Rd                      |   7 +-
 man/malist.Rd                     |   2 +-
 man/mdplot.Rd                     |  40 ++--
 man/modifyWeights.Rd              |   2 +-
 man/normalizeRobustSpline.Rd      |  14 +-
 man/normalizeWithinArrays.Rd      |   2 +-
 man/normalizebetweenarrays.Rd     |   2 +-
 man/normexpfit.Rd                 |   6 +-
 man/normexpsignal.Rd              |   6 +-
 man/plot.Rd                       |  94 --------
 man/plotDensities.Rd              |  12 +-
 man/plotExons.Rd                  |   2 +-
 man/plotMD.Rd                     | 133 ++++++++++++
 man/plotMDS.Rd                    |  34 +--
 man/plotSplice.Rd                 |   5 +-
 man/plotWithHighlights.Rd         |  96 +++++++++
 man/plotma.Rd                     |  49 +++--
 man/plotma3by2.Rd                 |   2 +
 man/predFCm.Rd                    |  59 +++---
 man/propTrueNull.Rd               |   7 +-
 man/rankSumTestwithCorrelation.Rd |   5 +-
 man/read.idat.Rd                  |   9 +-
 man/read.maimages.Rd              |   7 +
 man/readGPRHeader.Rd              |   8 +-
 man/readImaGeneHeader.Rd          |   2 +-
 man/readgal.Rd                    |   2 +-
 man/rglist.Rd                     |   2 +-
 man/roast.Rd                      |  29 ++-
 man/romer.Rd                      |  34 +--
 man/topGO.Rd                      |  24 ++-
 man/topSplice.Rd                  |   4 +-
 man/toptable.Rd                   |   8 +
 man/venn.Rd                       |   9 +-
 man/voom.Rd                       |  11 +-
 man/voomWithQualityWeights.Rd     |  34 +--
 man/vooma.Rd                      |   2 +-
 src/weighted_lowess.c             |  80 ++++---
 tests/limma-Tests.R               |  13 +-
 tests/limma-Tests.Rout.save       | 229 ++++++++++++--------
 vignettes/intro.Rnw               |  49 +++++
 107 files changed, 2802 insertions(+), 1253 deletions(-)

diff --git a/DESCRIPTION b/DESCRIPTION
index e9e786b..b7fe377 100755
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,15 +1,15 @@
 Package: limma
-Version: 3.22.1
-Date: 2014/10/20
+Version: 3.24.13
+Date: 2015-07-07
 Title: Linear Models for Microarray Data
 Description: Data analysis, linear models and differential expression for microarray data.
-Author: Gordon Smyth [cre,aut], Matthew Ritchie [ctb], Jeremy Silver [ctb], James Wettenhall [ctb], Natalie Thorne [ctb], Davis McCarthy [ctb], Di Wu [ctb], Yifang Hu [ctb], Wei Shi [ctb], Belinda Phipson [ctb], Alicia Oshlack [ctb], Carolyn de Graaf [ctb], Mette Langaas [ctb], Egil Ferkingstad [ctb], Marcus Davy [ctb], Francois Pepin [ctb], Dongseok Choi [ctb]
+Author: Gordon Smyth [cre,aut], Matthew Ritchie [ctb], Jeremy Silver [ctb], James Wettenhall [ctb], Natalie Thorne [ctb], Davis McCarthy [ctb], Di Wu [ctb], Yifang Hu [ctb], Wei Shi [ctb], Belinda Phipson [ctb], Alicia Oshlack [ctb], Carolyn de Graaf [ctb], Mette Langaas [ctb], Egil Ferkingstad [ctb], Marcus Davy [ctb], Francois Pepin [ctb], Dongseok Choi [ctb], Aaron Lun [ctb]
 Maintainer: Gordon Smyth <smyth at wehi.edu.au>
 License: GPL (>=2)
 Depends: R (>= 2.3.0), methods
-Suggests: statmod (>= 1.2.2), splines, locfit, MASS, ellipse, affy,
-        vsn, AnnotationDbi, org.Hs.eg.db, GO.db, illuminaio, BiasedUrn
-LazyLoad: yes
+Suggests: affy, AnnotationDbi, BiasedUrn, Biobase, ellipse, GO.db,
+        illuminaio, KEGGREST, locfit, MASS, org.Hs.eg.db, splines,
+        statmod (>= 1.2.2), vsn
 URL: http://bioinf.wehi.edu.au/limma
 biocViews: ExonArray, GeneExpression, Transcription,
         AlternativeSplicing, DifferentialExpression,
@@ -19,4 +19,5 @@ biocViews: ExonArray, GeneExpression, Transcription,
         ProprietaryPlatforms, TwoChannel, RNASeq, BatchEffect,
         MultipleComparison, Normalization, Preprocessing,
         QualityControl
-Packaged: 2014-10-21 00:24:11 UTC; biocbuild
+NeedsCompilation: yes
+Packaged: 2015-07-09 01:26:56 UTC; biocbuild
diff --git a/NAMESPACE b/NAMESPACE
index 226c493..e2431e7 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -12,6 +12,9 @@ S3method("[",RGList)
 S3method("[",EList)
 S3method("[",EListRaw)
 S3method(anova,MAList)
+S3method(as.data.frame,EList)
+S3method(as.data.frame,EListRaw)
+S3method(as.data.frame,MAList)
 S3method(as.data.frame,MArrayLM)
 S3method(as.matrix,MAList)
 S3method(as.matrix,EList)
@@ -54,8 +57,11 @@ S3method("dimnames<-",RGList)
 S3method("dimnames<-",EList)
 S3method("dimnames<-",EListRaw)
 S3method(fitted,MArrayLM)
+S3method(fry,default)
 S3method(goana,default)
 S3method(goana,MArrayLM)
+S3method(kegga,default)
+S3method(kegga,MArrayLM)
 S3method(length,MAList)
 S3method(length,MArrayLM)
 S3method(length,RGList)
@@ -65,6 +71,7 @@ S3method(merge,MAList)
 S3method(merge,RGList)
 S3method(merge,EList)
 S3method(merge,EListRaw)
+S3method(mroast,default)
 S3method(roast,default)
 S3method(romer,default)
 S3method(rbind,MAList)
@@ -81,15 +88,18 @@ S3method(summary,TestResults)
 S3method(normalizeVSN,default)
 S3method(normalizeVSN,RGList)
 S3method(normalizeVSN,EListRaw)
-S3method(plot,RGList)
-S3method(plot,MAList)
-S3method(plot,EList)
-S3method(plot,MArrayLM)
 S3method(plotMA,default)
 S3method(plotMA,RGList)
 S3method(plotMA,MAList)
+S3method(plotMA,EListRaw)
 S3method(plotMA,EList)
 S3method(plotMA,MArrayLM)
+S3method(plotMD,default)
+S3method(plotMD,RGList)
+S3method(plotMD,MAList)
+S3method(plotMD,EListRaw)
+S3method(plotMD,EList)
+S3method(plotMD,MArrayLM)
 S3method(plotMDS,default)
 S3method(plotMDS,MDS)
 S3method(plotFB,default)
diff --git a/R/alias2Symbol.R b/R/alias2Symbol.R
index ecac981..855e9fd 100644
--- a/R/alias2Symbol.R
+++ b/R/alias2Symbol.R
@@ -4,27 +4,26 @@ alias2Symbol <- function(alias,species="Hs",expand.symbols=FALSE)
 #  Convert a set of alias names to official gene symbols
 #  via Entrez Gene identifiers
 #  Di Wu, Gordon Smyth and Yifang Hu
-#  4 Sep 2008. Last revised 29 September 2013
+#  4 Sep 2008. Last revised 16 Jan 2015.
 {
 	alias <- as.character(alias)
 	species <- match.arg(species,c("Dm","Hs","Mm","Rn"))
 	DB <- paste("org",species,"eg","db",sep=".")
 	ALIAS2EG <- paste("org",species,"egALIAS2EG",sep=".")
 	SYMBOL <- paste("org",species,"egSYMBOL",sep=".")
-	suppressPackageStartupMessages(require("AnnotationDbi",character.only=TRUE))
 	suppressPackageStartupMessages(require(DB,character.only=TRUE))
 	if(expand.symbols)
 	{
-		alias <- intersect(alias,Rkeys(get(ALIAS2EG)))
-		eg <- mappedLkeys(get(ALIAS2EG)[alias])
-		mappedRkeys(get(SYMBOL)[eg])
+		alias <- intersect(alias,AnnotationDbi::Rkeys(get(ALIAS2EG)))
+		eg <- AnnotationDbi::mappedLkeys(get(ALIAS2EG)[alias])
+		AnnotationDbi::mappedRkeys(get(SYMBOL)[eg])
 	}
 	else
 	{
-		isSymbol <- alias %in% Rkeys(get(SYMBOL)) 
-		alias2 <- intersect(alias[!isSymbol],Rkeys(get(ALIAS2EG)))
-		eg <- mappedLkeys(get(ALIAS2EG)[alias2])
-		c(alias[isSymbol],mappedRkeys(get(SYMBOL)[eg]))
+		isSymbol <- alias %in% AnnotationDbi::Rkeys(get(SYMBOL)) 
+		alias2 <- intersect(alias[!isSymbol],AnnotationDbi::Rkeys(get(ALIAS2EG)))
+		eg <- AnnotationDbi::mappedLkeys(get(ALIAS2EG)[alias2])
+		c(alias[isSymbol],AnnotationDbi::mappedRkeys(get(SYMBOL)[eg]))
 
 	}
 }
@@ -33,28 +32,27 @@ alias2SymbolTable <- function(alias,species="Hs")
 #  Convert a vector of alias names to the vector of corresponding official gene symbols
 #  via Entrez Gene identifiers
 #  Di Wu, Gordon Smyth and Yifang Hu
-#  Created 3 Sep 2009.  Last modified 29 September Dec 2013.
+#  Created 3 Sep 2009.  Last modified 16 Jan 2015.
 {
 	alias <- as.character(alias)
 	species <- match.arg(species,c("Dm","Hs","Mm","Rn"))
 	DB <- paste("org",species,"eg","db",sep=".")
 	ALIAS2EG <- paste("org",species,"egALIAS2EG",sep=".")
 	SYMBOL <- paste("org",species,"egSYMBOL",sep=".")
-	suppressPackageStartupMessages(require("AnnotationDbi",character.only=TRUE))
 	suppressPackageStartupMessages(require(DB,character.only=TRUE))
 
-	isSymbol <- alias %in% Rkeys(get(SYMBOL))
+	isSymbol <- alias %in% AnnotationDbi::Rkeys(get(SYMBOL))
 	Symbol <- alias
 	Symbol[!isSymbol] <- NA
 
 	OtherAliases <- alias[!isSymbol]
-	isAlias <- OtherAliases %in% Rkeys(get(ALIAS2EG))
+	isAlias <- OtherAliases %in% AnnotationDbi::Rkeys(get(ALIAS2EG))
 	if(!any(isAlias)) return(Symbol)
 	OtherAliases <- OtherAliases[isAlias]
 
-	AliasTbl <- toTable(get(ALIAS2EG)[OtherAliases])
+	AliasTbl <- AnnotationDbi::toTable(get(ALIAS2EG)[OtherAliases])
 	if(anyDuplicated(AliasTbl$alias_symbol)) warning("Multiple symbols ignored for one or more aliases")
-	SymbolTbl <- toTable(get(SYMBOL)[AliasTbl$gene_id])
+	SymbolTbl <- AnnotationDbi::toTable(get(SYMBOL)[AliasTbl$gene_id])
 	m <- match(OtherAliases,AliasTbl$alias_symbol)
 	GeneID <- AliasTbl$gene_id[m]
 	m <- match(GeneID,SymbolTbl$gene_id)
diff --git a/R/arrayWeights.R b/R/arrayWeights.R
index 1b72a68..abf47d2 100644
--- a/R/arrayWeights.R
+++ b/R/arrayWeights.R
@@ -3,7 +3,7 @@ arrayWeights <- function(object, design=NULL, weights=NULL, var.design=NULL, met
 #	Matt Ritchie 7 Feb 2005.
 #	Gordon Smyth simplified argument checking to use getEAWP, 9 Mar 2008.
 #	Cynthia Liu added var.design argument so that variance model can be modified by user, 22 Sep 2014
-#	Last modified 7 Oct 2014.
+#	Last modified 27 Oct 2014.
 {
 #	Check arguments
 	y <- getEAWP(object)
@@ -211,7 +211,7 @@ arrayWeights <- function(object, design=NULL, weights=NULL, var.design=NULL, met
 
 voomWithQualityWeights <- function(counts, design=NULL, lib.size=NULL, normalize.method="none",
                          plot=FALSE, span=0.5, var.design=NULL, method="genebygene", maxiter=50,
-                         tol=1e-10, trace=FALSE, replace.weights=TRUE, ...)
+                         tol=1e-10, trace=FALSE, replace.weights=TRUE, col=NULL, ...)
 #	Combine voom weights with sample-specific weights estimated by arrayWeights() function for RNA-seq data
 #	Matt Ritchie and Cynthia Liu, 22 Sept 2014.
 #       Last modified 7 Oct 2014.
@@ -227,11 +227,12 @@ voomWithQualityWeights <- function(counts, design=NULL, lib.size=NULL, normalize
     wts <- asMatrixWeights(aw, dim(v))*v$weights
     attr(wts, "arrayweights") <- NULL
     if(plot) {
-        barplot(aw, names=seq(1:length(aw)), main="Sample-specific weights", ylab="Weight", xlab="Sample")
+        barplot(aw, names=1:length(aw), main="Sample-specific weights", ylab="Weight", xlab="Sample", col=col)
         abline(h=1, col=2, lty=2)
     }
     if(replace.weights) {
       v$weights <- wts
+      v$sample.weights <- aw
       return(v)
     } else {
         return(wts)
diff --git a/R/auROC.R b/R/auROC.R
new file mode 100755
index 0000000..57dc8d2
--- /dev/null
+++ b/R/auROC.R
@@ -0,0 +1,55 @@
+#  ROC.R
+
+auROC <- function(truth, stat=NULL)
+#	Area under Receiver Operating Curve for empirical data
+#	Gordon Smyth
+#	21 Dec 2003. Last modified 28 April 2015.
+{
+#	Don't allow any NA
+	if(any(is.na(truth))) return(NA)
+
+#	Make logical and integer vectors
+	ntests <- length(truth)
+	truthl <- as.logical(truth)
+	truthi <- as.integer(truthl)
+
+#	Return NA if truth is always the same
+	npos <- sum(truthi)
+	if(npos==0 || npos==ntests) return(NA)
+
+	if(is.null(stat)) {
+		sensitivity <- cumsum(truthi) / npos
+		return( mean(sensitivity[!truthl]) )
+	}
+	
+#	From here, stat is not NULL
+
+#	Check stat
+	stat <- as.vector(stat)
+	if(length(stat) != ntests) stop("lengths differ")
+	if(any(is.na(stat))) return(NA)
+
+#	From here, stat is not NA
+
+#	Sort truth by stat
+	o <- order(stat,decreasing=TRUE)
+	truthi <- truthi[o]
+	truthl <- truthl[o]
+	stat <- stat[o]
+	sensitivity <- cumsum(truthi) / npos
+
+#	Replace sensitivities with averages for tied stat
+	i <- 1:(ntests-1)
+	iseq2prev <- stat[i]==stat[i+1]
+	if(any(iseq2prev)) {
+		iseq2prev <- c(FALSE,iseq2prev)
+		tied.first <- which(!iseq2prev)
+		tied.last <- c(tied.first[-1]-1,ntests)
+		sensitivity.last <- sensitivity[tied.last]
+		sensitivity.previous <- c(0,sensitivity.last[-length(sensitivity.last)])
+		sensitivity.average <- (sensitivity.last+sensitivity.previous)/2
+		sensitivity <- rep(sensitivity.average, tied.last-tied.first+1)
+	}
+
+	mean(sensitivity[!truthl])
+}
diff --git a/R/background-normexp.R b/R/background-normexp.R
index be51be8..7c976d0 100644
--- a/R/background-normexp.R
+++ b/R/background-normexp.R
@@ -26,7 +26,7 @@ normexp.fit <- function(x, method="saddle", n.pts=NULL, trace=FALSE)
 #	Estimate parameters of normal+exponential convolution model
 #	Pure R Version Gordon Smyth 24 Aug 2002.
 #	Version with C by Jeremy Silver 29 Oct 2007.
-#	Last modified 25 Sept 2008.
+#	Last modified 14 January 2015.
 {
 	isna <- is.na(x)
 	if(any(isna)) x <- x[!isna]
@@ -40,8 +40,8 @@ normexp.fit <- function(x, method="saddle", n.pts=NULL, trace=FALSE)
 	if(method=="nlminblog") method <- "mle"
 
 	if(method=="rma") {
-		require(affy)
-		out <- bg.parameters(x)
+		if(!requireNamespace("affy",quietly=TRUE)) stop("affy package required but is not available")
+		out <- affy::bg.parameters(x)
 		return(list(par=c(out$mu,log(out$sigma),-log(out$alpha))))
 	}
 
diff --git a/R/classes.R b/R/classes.R
index 8c5a6be..9f6b2db 100755
--- a/R/classes.R
+++ b/R/classes.R
@@ -142,7 +142,7 @@ dimnames.MArrayLM <- function(x) dimnames(x$coefficients)
 #  Gordon Smyth
 #  17 Dec 2005. Last modified 23 March 2009.
 {
-	exprmatrices <- c("R","G","Rb","Gb","M","A","E","weights")
+	exprmatrices <- c("R","G","Rb","Gb","M","A","E","Eb","weights")
 	for (a in exprmatrices) if(!is.null(x[[a]])) dimnames(x[[a]]) <- value
 	for(a in names(x$other)) dimnames(x$other[[a]]) <- value
 	if(!is.null(x$targets)) row.names(x$targets) <- value[[2]]
diff --git a/R/dups.R b/R/dups.R
index 1118a1d..90430bf 100755
--- a/R/dups.R
+++ b/R/dups.R
@@ -33,7 +33,7 @@ uniquegenelist <- function(genelist,ndups=2,spacing=1) {
 duplicateCorrelation <- function(object,design=NULL,ndups=2,spacing=1,block=NULL,trim=0.15,weights=NULL)
 #	Estimate the correlation between duplicates given a series of arrays
 #	Gordon Smyth
-#	25 Apr 2002. Last revised 28 July 2013.
+#	25 Apr 2002. Last revised 14 January 2015.
 {
 #	Extract components from y
 	y <- getEAWP(object)
@@ -97,7 +97,7 @@ duplicateCorrelation <- function(object,design=NULL,ndups=2,spacing=1,block=NULL
 		design <- design %x% rep(1,ndups)
 	}
 
-	require( "statmod" ) # need mixedModel2Fit function
+	if(!requireNamespace("statmod",quietly=TRUE)) stop("statmod package required but is not available")
 	rho <- rep(NA,ngenes)
 	nafun <- function(e) NA
 	for (i in 1:ngenes) {
@@ -112,9 +112,9 @@ duplicateCorrelation <- function(object,design=NULL,ndups=2,spacing=1,block=NULL
 			Z <- model.matrix(~0+A)
 			if(!is.null(weights)) {
 				w <- drop(weights[i,])[o]
-				s <- tryCatch(mixedModel2Fit(y,X,Z,w,only.varcomp=TRUE,maxit=20)$varcomp,error=nafun)
+				s <- tryCatch(statmod::mixedModel2Fit(y,X,Z,w,only.varcomp=TRUE,maxit=20)$varcomp,error=nafun)
 			} else
-				s <- tryCatch(mixedModel2Fit(y,X,Z,only.varcomp=TRUE,maxit=20)$varcomp,error=nafun)
+				s <- tryCatch(statmod::mixedModel2Fit(y,X,Z,only.varcomp=TRUE,maxit=20)$varcomp,error=nafun)
 			if(!is.na(s[1])) rho[i] <- s[2]/sum(s)
 		}
 	}
diff --git a/R/fitFDistRobustly.R b/R/fitFDistRobustly.R
index 1280db5..b2d13cf 100644
--- a/R/fitFDistRobustly.R
+++ b/R/fitFDistRobustly.R
@@ -3,7 +3,7 @@ fitFDistRobustly <- function(x,df1,covariate=NULL,winsor.tail.p=c(0.05,0.1),trac
 #	given the first degrees of freedom, using first and second
 #	moments of Winsorized z-values
 #	Gordon Smyth and Belinda Phipson
-#	8 Sept 2002.  Last revised 20 February 2014.
+#	8 Sept 2002.  Last revised 14 January 2015.
 {
 #	Check x
 	n <- length(x)
@@ -110,8 +110,8 @@ fitFDistRobustly <- function(x,df1,covariate=NULL,winsor.tail.p=c(0.05,0.1),trac
 	if(trace) cat("Variance of Winsorized Fisher-z",zwvar,"\n")
 
 #	Theoretical Winsorized moments
-	require("statmod")
-	g <- gauss.quad.prob(128,dist="uniform")
+	if(!requireNamespace("statmod",quietly=TRUE)) stop("statmod package required but is not available")
+	g <- statmod::gauss.quad.prob(128,dist="uniform")
 	linkfun <- function(x) x/(1+x)
 	linkinv <- function(x) x/(1-x)
 	winsorizedMoments <- function(df1=df1,df2=df2,winsor.tail.p=winsor.tail.p) {
diff --git a/R/genas.R b/R/genas.R
index f296f46..ebc634a 100644
--- a/R/genas.R
+++ b/R/genas.R
@@ -3,8 +3,15 @@
 genas <- function(fit,coef=c(1,2),subset="all",plot=FALSE,alpha=0.4)
 #	Genuine association of gene expression profiles
 #	Belinda Phipson and Gordon Smyth
-#	21 September 2009. Last modified 26 July 2013.
+#	21 September 2009. Last modified 11 April 2015.
 {
+	if(is.null(fit$cov.coefficients))
+		if(is.null(fit$qr)) {
+			stop("The fit object appears to have been fitted with observation weights or missing values. genas is not yet implemented for these situations.")
+		} else {
+			fit$cov.coefficients <- chol2inv(fit$qr$qr[,1:fit$qr$rank,drop=FALSE])
+		}
+
 	out <- list(
 		technical.correlation=NA,
 		covariance.matrix=matrix(NA,2,2),
@@ -66,7 +73,7 @@ genas <- function(fit,coef=c(1,2),subset="all",plot=FALSE,alpha=0.4)
 	rhotech <- V[2,1]/sqrt(V[1,1]*V[2,2])
 
 	if(plot) {
-		require(ellipse)
+		if(!requireNamespace("ellipse",quietly=TRUE)) stop("ellipse package required but is not available")
 		lim <- mean(c(sd(fit.plot$coeff[,1]),sd(fit.plot$coeff[,2])))
 		if(nrow(fit)<500) lim <- 1.5*lim else lim <- 2*lim
 		max <- max(c(fit.plot$coeff[,1],fit.plot$coeff[,2]))
@@ -75,16 +82,16 @@ genas <- function(fit,coef=c(1,2),subset="all",plot=FALSE,alpha=0.4)
 		min <- sign(min)*max(abs(min),abs(max))
 		if(abs(rhobiol)>abs(rhotech)){
 			plot(fit.plot$coeff[,1],fit.plot$coeff[,2],pch=16,cex=0.4,ylim=c(min,max),xlim=c(min,max),xlab=colnames(fit.plot$coeff)[1],ylab=colnames(fit.plot$coeff)[2])
-			polygon(ellipse(rhotech,scale=c(lim,lim)),col=rgb(0,0,1,alpha=alpha),border=rgb(0,0,1,alpha=alpha))
-			polygon(ellipse(rhobiol,scale=c(lim,lim)),col=rgb(0,1,0,alpha=alpha),border=rgb(0,1,0,alpha=alpha))
+			polygon(ellipse::ellipse(rhotech,scale=c(lim,lim)),col=rgb(0,0,1,alpha=alpha),border=rgb(0,0,1,alpha=alpha))
+			polygon(ellipse::ellipse(rhobiol,scale=c(lim,lim)),col=rgb(0,1,0,alpha=alpha),border=rgb(0,1,0,alpha=alpha))
 			points(fit.plot$coeff[,1],fit.plot$coeff[,2],pch=16,cex=0.4)
 			abline(h=0,v=0)
 			legend(min,max,legend=bquote(rho[biol]==.(round(rhobiol,3))),col=rgb(0,1,0,alpha=alpha),pch=16,bty="n",cex=0.8)
 			legend(min,max-lim/2,legend=bquote(rho[tech]==.(round(rhotech,3))),col=rgb(0,0,1,alpha=alpha),pch=16,bty="n",cex=0.8)
 		} else {
 			plot(fit.plot$coeff[,1],fit.plot$coeff[,2],pch=16,cex=0.4,ylim=c(min,max),xlim=c(min,max),xlab=colnames(fit.plot$coeff)[1],ylab=colnames(fit.plot$coeff)[2])
-			polygon(ellipse(rhobiol,scale=c(lim,lim)),col=rgb(0,1,0,alpha=alpha),border=rgb(0,1,0,alpha=alpha))
-			polygon(ellipse(rhotech,scale=c(lim,lim)),col=rgb(0,0,1,alpha=alpha),border=rgb(0,0,1,alpha=alpha))
+			polygon(ellipse::ellipse(rhobiol,scale=c(lim,lim)),col=rgb(0,1,0,alpha=alpha),border=rgb(0,1,0,alpha=alpha))
+			polygon(ellipse::ellipse(rhotech,scale=c(lim,lim)),col=rgb(0,0,1,alpha=alpha),border=rgb(0,0,1,alpha=alpha))
 			points(fit.plot$coeff[,1],fit.plot$coeff[,2],pch=16,cex=0.4)
 			abline(h=0,v=0)
 			legend(min,max,legend=bquote(rho[biol]==.(round(rhobiol,3))),col=rgb(0,1,0,alpha=alpha),pch=16,bty="n",cex=0.8)
diff --git a/R/geneset-camera.R b/R/geneset-camera.R
index 5912bb5..7cd0e7d 100644
--- a/R/geneset-camera.R
+++ b/R/geneset-camera.R
@@ -24,8 +24,12 @@ camera <- function(y,...) UseMethod("camera")
 camera.default <- function(y,index,design=NULL,contrast=ncol(design),weights=NULL,use.ranks=FALSE,allow.neg.cor=TRUE,trend.var=FALSE,sort=TRUE,...)
 #	Competitive gene set test allowing for correlation between genes
 #	Gordon Smyth and Di Wu
-#	Created 2007.  Last modified 25 Feb 2014
+#	Created 2007.  Last modified 23 June 2015
 {
+#	Issue warning if extra arguments found
+	dots <- names(list(...))
+	if(length(dots)) warning("Extra arguments disregarded: ",sQuote(dots))
+
 #	Extract components from y
 	y <- getEAWP(y)
 	G <- nrow(y$exprs)
@@ -33,6 +37,8 @@ camera.default <- function(y,index,design=NULL,contrast=ncol(design),weights=NUL
 
 #	Check index
 	if(!is.list(index)) index <- list(set1=index)
+	nsets <- length(index)
+	if(nsets==0) stop("index is empty")
 
 #	Check design
 	if(is.null(design)) design <- y$design
@@ -112,7 +118,7 @@ camera.default <- function(y,index,design=NULL,contrast=ncol(design),weights=NUL
 #	Standardized residuals
 	U <- effects[-(1:p),,drop=FALSE]
 	sigma2 <- colMeans(U^2)
-	U <- t(U) / sqrt(sigma2)
+	U <- t(U) / sqrt(pmax(sigma2,1e-8))
 
 #	Moderated t
 	if(trend.var) A <- rowMeans(y) else A <- NULL
@@ -125,7 +131,6 @@ camera.default <- function(y,index,design=NULL,contrast=ncol(design),weights=NUL
 	meanStat <- mean(Stat)
 	varStat <- var(Stat)
 
-	nsets <- length(index)
 	tab <- matrix(0,nsets,5)
 	rownames(tab) <- names(index)
 	colnames(tab) <- c("NGenes","Correlation","Down","Up","TwoSided")
diff --git a/R/geneset-fry.R b/R/geneset-fry.R
new file mode 100644
index 0000000..4a6eddd
--- /dev/null
+++ b/R/geneset-fry.R
@@ -0,0 +1,138 @@
+fry <- function(y,...) UseMethod("fry")
+
+fry.default <- function(y,index=NULL,design=NULL,contrast=ncol(design),weights=NULL,sort=TRUE,...)
+#	Quick version of roast gene set test assuming equal variances between genes
+#	The up and down p-values are equivalent to those from roast with nrot=Inf
+#	in the special case of prior.df=Inf.
+#	Gordon Smyth and Goknur Giner
+#	Created 30 January 2015.  Last modified 23 June 2015
+{
+#	Issue warning if extra arguments found
+	dots <- names(list(...))
+	if(length(dots)) warning("Extra arguments disregarded: ",sQuote(dots))
+
+#	Extract components from y
+	y <- getEAWP(y)
+	G <- nrow(y$exprs)
+	n <- ncol(y$exprs)
+
+#	Check index
+	if(is.null(index)) index <- list(set1=1L:G)
+	if(!is.list(index)) index <- list(set1=index)
+	nsets <- length(index)
+	if(nsets==0) stop("index is empty")
+
+#	Check design
+	if(is.null(design)) design <- y$design
+	if(is.null(design))
+		design <- matrix(1,n,1)
+	else {
+		design <- as.matrix(design)
+		if(mode(design) != "numeric") stop("design must be a numeric matrix")
+	}
+	if(nrow(design) != n) stop("row dimension of design matrix must match column dimension of data")
+	ne <- nonEstimable(design)
+	if(!is.null(ne)) cat("Coefficients not estimable:",paste(ne,collapse=" "),"\n")
+
+	p <- ncol(design)
+	df.residual <- n-p
+	df.camera <- min(df.residual,G-2)
+
+#	Check weights
+	if(is.null(weights)) weights <- y$weights
+
+#	Reduce to numeric expression matrix
+	y <- y$exprs
+
+#	Check weights
+	if(!is.null(weights)) {
+		if(any(weights<=0)) stop("weights must be positive")
+		if(length(weights)==n) {
+			sw <- sqrt(weights)
+			y <- t(t(y)*sw)
+			design <- design*sw
+			weights <- NULL
+		}
+	}
+	if(!is.null(weights)) {
+		if(length(weights)==G) weights <- matrix(weights,G,n)
+		weights <- as.matrix(weights)
+		if(any( dim(weights) != dim(y) )) stop("weights not conformal with y")
+	}
+
+#	Reform design matrix so that contrast of interest is last column
+	if(is.character(contrast)) {
+		contrast <- which(contrast==colnames(design))
+		if(length(contrast)==0) stop("coef ",contrast," not found")
+	}
+	if(length(contrast)==1) {
+		j <- c((1:p)[-contrast], contrast)
+		if(contrast<p) design <- design[,j]
+	} else {
+		QR <- qr(contrast)
+		design <- t(qr.qty(QR,t(design)))
+		if(sign(QR$qr[1,1]<0)) design[,1] <- -design[,1]
+		design <- design[,c(2:p,1)]
+	}
+
+#	Compute effects matrix
+	if(is.null(weights)) {
+		QR <- qr(design)
+		if(QR$rank<p) stop("design matrix is not of full rank")
+		effects <- qr.qty(QR,t(y))
+		unscaledt <- effects[p,]
+		if(QR$qr[p,p]<0) unscaledt <- -unscaledt
+	} else {
+		effects <- matrix(0,n,G)
+		unscaledt <- rep(0,n)
+		sw <- sqrt(weights)
+		yw <- y*sw
+		for (g in 1:G) {
+			xw <- design*sw[g,]
+			QR <- qr(xw)
+			if(QR$rank<p) stop("weighted design matrix not of full rank for gene ",g)
+			effects[,g] <- qr.qty(QR,yw[g,])
+			unscaledt[g] <- effects[p,g]
+			if(QR$qr[p,p]<0) unscaledt[g] <- -unscaledt[g]
+		}
+	}
+
+#	Standardized residuals
+	U <- effects[-(1:(p-1)),,drop=FALSE]
+
+#	Global statistics
+	nsets <- length(index)
+	NGenes <- rep.int(0L,nsets)
+	Direction <- rep.int("",nsets)
+	PValue.Mixed <- PValue <- rep.int(0,nsets)
+	for (i in 1:nsets) {
+		iset <- index[[i]]
+		USet <- U[,iset,drop=FALSE]
+		NGenes[i] <- ncol(USet)
+		MeanUSet <- rowMeans(USet)
+		t.stat <- MeanUSet[1L] / sqrt(mean(MeanUSet[-1L]^2L))
+		if(t.stat>0) Direction[i] <- "Up" else Direction[i] <- "Down"
+		PValue[i] <- 2*pt(-abs(t.stat),df=df.residual)
+#		MSqUSet <- rowMeans(USet^2)
+#		F.stat <- MSqUSet[1L] / mean(MSqUSet[-1L])
+#		PValue.Mixed[i] <- pf(F.stat,df1=1L,df2=df.residual,lower.tail=FALSE)
+	}
+
+#	Add FDR
+	if(nsets>1) {
+		FDR <- p.adjust(PValue,method="BH")
+#		FDR.Mixed <- p.adjust(PValue.Mixed,method="BH")
+		tab <- data.frame(NGenes=NGenes,Direction=Direction,PValue=PValue,FDR=FDR)
+	} else {
+		tab <- data.frame(NGenes=NGenes,Direction=Direction,PValue=PValue)
+	}
+	rownames(tab) <- names(index)
+
+#	Sort by p-value
+	if(sort && nsets>1) {
+		o <- order(tab$PValue,-tab$NGenes)
+		tab <- tab[o,]
+	}
+
+	tab
+}
diff --git a/R/geneset-ids2indices.R b/R/geneset-ids2indices.R
new file mode 100644
index 0000000..d1c3a89
--- /dev/null
+++ b/R/geneset-ids2indices.R
@@ -0,0 +1,14 @@
+ids2indices <- function(gene.sets, identifiers, remove.empty=TRUE)
+# Make a list of gene identifiers into a list of indices for gene sets
+# Gordon Smyth and Yifang Hu
+# 25 March 2009.  Last modified 6 May 2015.
+{
+	if(!is.list(gene.sets)) gene.sets <- list(Set1=gene.sets)
+	identifiers <- as.character(identifiers)
+	index <- lapply(gene.sets, function(x) which(identifiers %in% as.character(x)))
+	if(remove.empty) {
+		Empty <- which(lengths(index)==0L)
+		if(length(Empty)) for (i in length(Empty):1) index[[Empty[i]]] <- NULL
+	}
+	index
+}
diff --git a/R/geneset-roast.R b/R/geneset-roast.R
index 64383c8..5918a13 100644
--- a/R/geneset-roast.R
+++ b/R/geneset-roast.R
@@ -16,8 +16,12 @@ roast <- function(y,...) UseMethod("roast")
 roast.default <- function(y,index=NULL,design=NULL,contrast=ncol(design),set.statistic="mean",gene.weights=NULL,array.weights=NULL,weights=NULL,block=NULL,correlation,var.prior=NULL,df.prior=NULL,trend.var=FALSE,nrot=999,approx.zscore=TRUE,...)
 # Rotation gene set testing for linear models
 # Gordon Smyth and Di Wu
-# Created 24 Apr 2008.  Last modified 19 Sep 2014.
+# Created 24 Apr 2008.  Last modified 8 April 2015.
 {
+#	Issue warning if extra arguments found
+	dots <- names(list(...))
+	if(length(dots)) warning("Extra arguments disregarded: ",sQuote(dots))
+
 #	Check index
 	if(is.list(index)) return(mroast(y=y,index=index,design=design,contrast=contrast,set.statistic=set.statistic,gene.weights=gene.weights,array.weights=array.weights,weights=weights,block=block,correlation=correlation,var.prior=var.prior,df.prior=df.prior,trend.var=trend.var,nrot=nrot))
 
@@ -351,7 +355,7 @@ mroast <- function(y,...) UseMethod("mroast")
 mroast.default <- function(y,index=NULL,design=NULL,contrast=ncol(design),set.statistic="mean",gene.weights=NULL,array.weights=NULL,weights=NULL,block=NULL,correlation,var.prior=NULL,df.prior=NULL,trend.var=FALSE,nrot=999,approx.zscore=TRUE,adjust.method="BH",midp=TRUE,sort="directional",...)
 #  Rotation gene set testing with multiple sets
 #  Gordon Smyth and Di Wu
-#  Created 28 Jan 2010. Last revised 18 Feb 2014.
+#  Created 28 Jan 2010. Last revised 23 June 2015.
 {
 #	Extract components from y
 	y <- getEAWP(y)
@@ -362,6 +366,7 @@ mroast.default <- function(y,index=NULL,design=NULL,contrast=ncol(design),set.st
 	if(is.null(index)) index <- rep(TRUE,ngenes)
 	if(!is.list(index)) index <- list(set = index)
 	nsets <- length(index)
+	if(nsets==0) stop("index is empty")
 	if(is.null(names(index))) names(index) <- paste("set",1:nsets,sep="")
 
 #	Check design matrix
@@ -479,6 +484,11 @@ mroast.default <- function(y,index=NULL,design=NULL,contrast=ncol(design),set.st
 		stringsAsFactors=FALSE
 	)
 
+	if(midp) {
+		tab$FDR <- pmax(tab$FDR, pv[,"UpOrDown"])
+		tab$FDR.Mixed <- pmax(tab$FDR.Mixed, pv[,"Mixed"])
+	}
+
 #	Sort by p-value
 	sort <- match.arg(sort,c("directional","mixed","none"))
 	if(sort=="none") return(tab)
diff --git a/R/geneset-romer.R b/R/geneset-romer.R
index 8af04bd..093b4b0 100644
--- a/R/geneset-romer.R
+++ b/R/geneset-romer.R
@@ -1,55 +1,44 @@
-##  ROMER.R
+##	ROMER.R
 romer <- function(y,...) UseMethod("romer")
 
-ids2indices <- function(gene.sets, identifiers, remove.empty=TRUE)
-# Make a list of gene identifiers into a list of indices for gene sets
-# Gordon Smyth and Yifang Hu
-# 25 March 2009.  Last modified 19 June 2014.
+romer.default <- function(y,index,design,contrast=ncol(design),array.weights=NULL,block=NULL,correlation=NULL,set.statistic="mean",nrot=9999,shrink.resid=TRUE,...)
+#	rotation mean-rank version of GSEA (gene set enrichment analysis) for linear models
+#	Gordon Smyth and Yifang Hu
+#	27 March 2009.	Last modified 23 June 2015.
 {
-	gene.sets <- as.list(gene.sets)
-	index <- lapply(gene.sets, function(x) which(identifiers %in% x))
-	if(remove.empty)
-		for (i in length(index):1) if(!length(index[[i]])) index[[i]] <- NULL
-	index
-}
+#	Issue warning if extra arguments found
+	dots <- names(list(...))
+	if(length(dots)) warning("Extra arguments disregarded: ",sQuote(dots))
 
-romer.default <- function(y,index,design,contrast=ncol(design),array.weights=NULL,block=NULL,correlation=NULL,set.statistic="mean",nrot=9999,...)
-# rotation mean-rank version of GSEA (gene set enrichment analysis) for linear models
-# Gordon Smyth and Yifang Hu
-# 27 March 2009.  Last modified 20 October 2014.
-{
-	set.statistic <- match.arg(set.statistic,c("mean","floormean","mean50"))
-	if(set.statistic=="mean50") {
-		return(.romer.mean50(y=y,index=index,design=design,contrast=contrast,array.weights=array.weights,block=block,correlation=correlation,nrot=nrot))
-	} else {
-		return(.romer.mean.floormean(y=y,index=index,design=design,contrast=contrast,array.weights=array.weights,block=block,correlation=correlation,floor=(set.statistic=="floormean"),nrot=nrot))
-	}
-}
+#	Check y
+	y <- as.matrix(y)
+	ngenes <- nrow(y)
+	n <- ncol(y)
 
-.romer.mean50 <- function(y,index,design,contrast=ncol(design),array.weights=NULL,block=NULL,correlation,nrot=9999)
-# rotation-mean50-rank version of GSEA (gene set enrichment analysis) for linear models
-# Gordon Smyth and Yifang Hu
-# 27 March 2009.  Last modified 20 October 2014.
-{
-#	Check input arguments
+#	Check index
 	if(!is.list(index)) index <- list(set=index)
-	nset<-length(index)
-	y <- as.matrix(y)
+	nsets <- length(index)
+	if(nsets==0) stop("index is empty")
+	SetSizes <- unlist(lapply(index,length))
+
+#	Check design
 	design <- as.matrix(design)
-	ngenes<-nrow(y)	
 	p <- ncol(design)
-	p0 <- p-1
-	n <- ncol(y)
+	if(p<2L) stop("design needs at least two columns")
+	if(nrow(design) != n) stop("row dimension of design matrix must match column dimension of data")
+	p0 <- p-1L
 	d <- n-p
 
-	if(length(contrast) == 1) {
-		u <- rep.int(0,p)
-		u[contrast] <- 1
-		contrast <- u
+#	Reform design matrix so that contrast of interest is last column
+	if(length(contrast) == 1L) {
+		contrast <- round(contrast)
+		if(contrast < p) {
+			i <- 1L:p
+			design <- design[,c(i[-contrast],contrast)]
+		}
+	} else {
+		design <- contrastAsCoef(design=design, contrast=contrast, first=FALSE)$design
 	}
-	if(length(contrast) != p) stop("length of contrast must match column dimension of design")
-	if(all(contrast==0)) stop("contrast all zero")
-	if(nrow(design) != n) stop("row dimension of design matrix must match column dimension of data")
 
 #	Divide out array weights, if they exist
 	if(!is.null(array.weights)) {
@@ -71,68 +60,40 @@ romer.default <- function(y,index,design,contrast=ncol(design),array.weights=NUL
 		R <- chol(cormatrix)
 		y <- t(backsolve(R, t(y), transpose = TRUE))
 		design <- backsolve(R, design, transpose = TRUE)
- 	}
+	}
 
-#	Reform design matrix so that contrast of interest is last column
-	qr <- qr(contrast)
-	Q <- qr.Q(qr,complete=TRUE)
-	sign1 <- sign(qr$qr[1,1])
-	Q <- cbind(Q[,-1],Q[,1])
-	X <- design %*% Q
-	qr <- qr(X)
-	sign2 <- sign(qr$qr[p,p])
-	signc <- sign1 * sign2
-
-# 	Fit model to all genes
+# 	Fit linear model to all genes
+	qr <- qr(design)
+	signc <- sign(qr$qr[p,p])
 	effects <- qr.qty(qr,t(y))
 
-# 	Estimate global hyper-parameters s0 and d0
+#	Sample variances
 	s2 <- colMeans(effects[-(1:p),,drop=FALSE]^2)
+
+# 	Estimate global hyper-parameters s0 and d0
 	sv <- squeezeVar(s2,df=d)
 	d0 <- sv$df.prior
 	s02 <- sv$var.prior
 	sd.post <- sqrt(sv$var.post)
 
-#	t-statistics and effects
+#	t-statistics and effects (orthogonal residuals)
 	Y <- effects[-(1:p0),,drop=FALSE]
 	YY <- colSums(Y^2)
 	B <- Y[1,]
 	modt <- signc*B/sd.post
-	
-#	Observed rankings for each set
-	s.r <- rank(modt)
-
-	s.rank.mixed<-rep(0,nset)
-	s.rank.up<-rep(0,nset)
-	s.rank.down<-rep(0,nset)
-
-	modt.abs<-abs(modt)
-	s.abs.r <-rank(modt.abs)
-
-	m<-unlist(lapply(index,length))
-	m<-floor((m+1)/2)
 
-	for(i in 1:nset)
-	{	
-		mh<-.meanHalf(s.r[index[[i]]],m[i])
-		s.rank.up[i] <-mh[2]	
-		s.rank.down[i]<-mh[1]
-		s.rank.mixed[i]<-.meanHalf(s.abs.r[index[[i]]],m[i])[2]
-	}	
-
-#	Estimate hyper-parameters p0
-	p.obs <- 2*pt(abs(modt),df=d0+d,lower.tail=FALSE)
-	p0.obs <- 1-propTrueNull(p.obs) # proportion of DE probes
+##	EMP BAYES SHRINK FIRST EFFECT TO REMOVE SYSTEMATIC COMPONENT
+	if(shrink.resid) {
 
-#	Estimate hyper-paremeter v0
-	covmat <- chol2inv(qr$qr, size = qr$rank)
- 	stdev.unscaled <- rep(sqrt(covmat[qr$rank,qr$rank]),ngenes)
+#	Estimate hyperparameter p0 (proportion of DE genes)
+	p.value <- 2*pt(abs(modt),df=d0+d,lower.tail=FALSE)
+	proportion <- 1-propTrueNull(p.value) # proportion of DE probes
 
-	proportion <- p0.obs
+#	Estimate hyperparameter v0 (var.prior, variance of true logFC)
+ 	stdev.unscaled <- rep_len(1/abs(qr$qr[qr$rank,qr$rank]),ngenes)
+ 	var.unscaled <- stdev.unscaled^2
+	df.total <- rep_len(d,ngenes) + sv$df.prior
 	stdev.coef.lim <- c(0.1, 4)
-
-	# get v0
-	df.total <- rep(d,ngenes) + sv$df.prior
 	var.prior.lim <- stdev.coef.lim^2/sv$var.prior
 	var.prior <- tmixture.vector(modt, stdev.unscaled, df.total, proportion, var.prior.lim)
 	if (any(is.na(var.prior))) {
@@ -141,22 +102,38 @@ romer.default <- function(y,index,design,contrast=ncol(design),array.weights=NUL
 	}
 
 #	Estimate posterior probability of DE
-	r <- rep(1, ngenes) %o% var.prior
-	r <- (stdev.unscaled^2 + r)/stdev.unscaled^2
-
+	r <- (var.unscaled + var.prior)/var.unscaled
 	if (sv$df.prior > 10^6)
 		kernel <- modt^2 * (1 - 1/r)/2
 	else
 		kernel <- (1 + df.total)/2 * log((modt^2 + df.total)/(modt^2/r + df.total))
-
 	lods <- log(proportion/(1 - proportion)) - log(r)/2 + kernel
-	pg <- exp(lods)/(1+exp(lods))
+	ProbDE <- exp(lods)/(1+exp(lods))
 
 #	Shrink contrast to be like a residual
-	Y[1,] <- Y[1,]*(sv$var.post/(sv$var.post+var.prior*pg))^(1/2)
+	Y[1,] <- Y[1,]*sqrt(var.unscaled/(var.unscaled+var.prior*ProbDE))
 
-#	Random rotations
-	p.value <- matrix(rep(0,nset*3),nrow=nset,ncol=3)
+	}
+##	END SHRINK
+
+	set.statistic <- match.arg(set.statistic,c("mean","floormean","mean50"))
+
+	if(set.statistic=="mean") {
+
+#	Observed rankings for each set
+	obs.ranks <- matrix(0,ngenes,3)
+	obs.ranks[,1] <- rank(modt)
+	obs.ranks[,2] <- ngenes-obs.ranks[,1]+1
+	obs.ranks[,3] <- rank(abs(modt))
+
+	AllIndices <- unlist(index)
+	Set <- rep(1:nsets,SetSizes)
+	obs.set.ranks <- rowsum(obs.ranks[AllIndices,],group=Set,reorder=FALSE)
+	obs.set.ranks <- obs.set.ranks / SetSizes
+
+#	Random rotations to simulate null hypothesis
+	rot.ranks <- obs.ranks
+	p.value <- matrix(0,nrow=nsets,ncol=3)
 	for(i in 1:nrot)
 	{
 		R <- matrix(rnorm((d+1)),1,d+1)
@@ -170,170 +147,78 @@ romer.default <- function(y,index,design,contrast=ncol(design),array.weights=NUL
 			sdr.post <- sqrt(s02)
 
 		modtr <- signc*Br/sdr.post
-		modtr.abs<-abs(modtr)
-	
-		s.r.2<-rank(modtr)
-		s.abs.r.2<-rank(modtr.abs)
 	
-		for(j in 1:nset)
-		{
-			mh.2<-.meanHalf(s.r.2[index[[j]]],m[j])
-			
-			s.rank.up.2 <-mh.2[2]	
-			s.rank.down.2 <-mh.2[1]
-			s.rank.mixed.2 <-.meanHalf(s.abs.r.2[index[[j]]],m[j])[2]
-		
-			if(s.rank.mixed.2>=s.rank.mixed[j]) p.value[j,1]<-p.value[j,1]+1
-			if(s.rank.up.2>=s.rank.up[j]) p.value[j,2]<-p.value[j,2]+1
-			if(s.rank.down.2<=s.rank.down[j]) p.value[j,3]<-p.value[j,3]+1
-		}
-	}	
-
-	p.value <- (p.value+1)/(nrot+1)
-	colnames(p.value)<-c("Mixed","Up","Down")
-	SetNames <- names(index)
-	if(is.null(SetNames))
-		rownames(p.value) <- 1:nset
-	else
-		rownames(p.value) <- SetNames
-	len.index<-as.numeric(lapply(index,length))
-	cbind(NGenes=len.index,p.value)
-}
+		rot.ranks[,1] <- rank(modtr)
+		rot.ranks[,2] <- ngenes-rot.ranks[,1]+1
+		rot.ranks[,3] <- rank(abs(modtr))
 
-## Return means of top half and bottom half of the ranks for romer2
-.meanHalf<- function(x,n)
-#	Yifang Hu
-{
-	l<-length(x)
-	a<-sort(x,partial=n)
-	top<-mean(a[1:n])
-	if((l%%2)==0) bottom<-mean(a[(n+1):l])
-	if((l%%2)!=0) bottom<-mean(a[n:l])
-	c(top,bottom)
-}
+		rot.set.ranks <- rowsum(rot.ranks[AllIndices,],group=Set,reorder=FALSE)
+		rot.set.ranks <- rot.set.ranks / SetSizes
+		p.value <- p.value + (rot.set.ranks >= obs.set.ranks)
+	}	
+	} # end "mean"
 
-.romer.mean.floormean <- function(y,index,design,contrast=ncol(design),array.weights=NULL,block=NULL,correlation,floor=FALSE,nrot=9999)
-# rotation mean-rank version of GSEA (gene set enrichment analysis) for linear models
-# Gordon Smyth and Yifang Hu
-# 27 March 2009.  Last modified 20 Oct 2014.
-{
-#	Check input arguments
-	if(!is.list(index)) index <- list(set=index)
-	nset<-length(index)
-	y <- as.matrix(y)
-	design <- as.matrix(design)
-	ngenes<-nrow(y)	
-	p <- ncol(design)
-	p0 <- p-1
-	n <- ncol(y)
-	d <- n-p
+	if(set.statistic=="floormean") {
 
-	if(length(contrast) == 1) {
-		u <- rep.int(0,p)
-		u[contrast] <- 1
-		contrast <- u
-	}
-	if(length(contrast) != p) stop("length of contrast must match column dimension of design")
-	if(all(contrast==0)) stop("contrast all zero")
-	if(nrow(design) != n) stop("row dimension of design matrix must match column dimension of data")
+#	Observed rankings for each set
+	obs.ranks <- matrix(0,ngenes,3)
+	obs.ranks[,1] <- rank(pmax(modt,0))
+	obs.ranks[,2] <- rank(pmax(-modt,0))
+	obs.ranks[,3] <- rank(pmax(abs(modt),1))
 
-#	Divide out array weights, it they exist
-	if(!is.null(array.weights)) {
-		if(any(array.weights <= 0)) stop("array.weights must be positive")
-		if(length(array.weights) != n) stop("Length of array.weights doesn't match number of array")
-		design <- design*sqrt(array.weights)
-		y <- t(t(y)*sqrt(array.weights))
-	}
+	AllIndices <- unlist(index)
+	Set <- rep(1:nsets,SetSizes)
+	obs.set.ranks <- rowsum(obs.ranks[AllIndices,],group=Set,reorder=FALSE)
+	obs.set.ranks <- obs.set.ranks / SetSizes
 
-#	Divide out correlation structure, it is exists
-	if(!is.null(block)) {
-		block <- as.vector(block)
-		if (length(block) != n) stop("Length of block does not match number of arrays")
-		ub <- unique(block)
-		nblocks <- length(ub)
-		Z <- matrix(block,n,nblocks) == matrix(ub,n,nblocks,byrow = TRUE)
-		cormatrix <- Z %*% (correlation * t(Z))
-		diag(cormatrix) <- 1
-		R <- chol(cormatrix)
-		y <- t(backsolve(R, t(y), transpose = TRUE))
-		design <- backsolve(R, design, transpose = TRUE)
-	}
+#	Random rotations to simulate null hypothesis
+	rot.ranks <- obs.ranks
+	p.value <- matrix(0,nrow=nsets,ncol=3)
+	for(i in 1:nrot)
+	{
+		R <- matrix(rnorm((d+1)),1,d+1)
+		R <- R/sqrt(rowSums(R^2))
+		Br <- R %*% Y
+		s2r <- (YY-Br^2)/d
 
-#	Reform design matrix so that contrast of interest is last column
-	qr <- qr(contrast)
-	Q <- qr.Q(qr,complete=TRUE)
-	sign1 <- sign(qr$qr[1,1])
-	Q <- cbind(Q[,-1],Q[,1])
-	X <- design %*% Q
-	qr <- qr(X)
-	sign2 <- sign(qr$qr[p,p])
-	signc <- sign1 * sign2
-
-# 	Fit model to all genes
-	effects <- qr.qty(qr,t(y))
+		if(is.finite(d0))
+			sdr.post <- sqrt((d0*s02+d*s2r)/(d0+d))
+		else
+			sdr.post <- sqrt(s02)
 
-#	Sample variances
-	s2 <- colMeans(effects[-(1:p),,drop=FALSE]^2)
+		modtr <- signc*Br/sdr.post
+	
+		rot.ranks[,1] <- rank(pmax(modtr,0))
+		rot.ranks[,2] <- rank(pmax(-modtr,0))
+		rot.ranks[,3] <- rank(pmax(abs(modtr),1))
 
-# 	Estimate global hyper-parameters s0 and d0
-	sv <- squeezeVar(s2,df=d)
-	d0 <- sv$df.prior
-	s02 <- sv$var.prior
-	sd.post <- sqrt(sv$var.post)
+		rot.set.ranks <- rowsum(rot.ranks[AllIndices,],group=Set,reorder=FALSE)
+		rot.set.ranks <- rot.set.ranks / SetSizes
+		p.value <- p.value + (rot.set.ranks >= obs.set.ranks)
+	}	
+	} # end "floormean"
 
-#	t-statistics and effects (orthogonal residuals)
-	Y <- effects[-(1:p0),,drop=FALSE]
-	YY <- colSums(Y^2)
-	B <- Y[1,]
-	modt <- signc*B/sd.post
-	
-#	Estimate hyper-parameter p0
-	p.obs <- 2*pt(abs(modt),df=d0+d,lower.tail=FALSE)
-	p0.obs <- 1-propTrueNull(p.obs) # proportion of DE probes
-	
-#	Estimate hyper-paremeter v0
-	covmat <- chol2inv(qr$qr, size = qr$rank)
- 	stdev.unscaled <- rep(sqrt(covmat[qr$rank,qr$rank]),ngenes)
-	proportion<-p0.obs
-	stdev.coef.lim <- c(0.1, 4)
-	df.total <- rep(d,ngenes) + sv$df.prior
-	var.prior.lim <- stdev.coef.lim^2/sv$var.prior
-	var.prior <- tmixture.vector(modt, stdev.unscaled, df.total,proportion, var.prior.lim)
-	if (any(is.na(var.prior))) {
-		var.prior[is.na(var.prior)] <- 1/sv$var.prior
-		warning("Estimation of var.prior failed - set to default value")
-	}
-	
-#	Estimate posterior probability of DE for each probe
-	r <- rep(1, ngenes) %o% var.prior
-	r <- (stdev.unscaled^2 + r)/stdev.unscaled^2
-	if (sv$df.prior > 10^6)
-		kernel <- modt^2 * (1 - 1/r)/2
-	else
-		kernel <- (1 + df.total)/2 * log((modt^2 + df.total)/(modt^2/r + df.total))
-	lods <- log(proportion/(1 - proportion)) - log(r)/2 + kernel
-	pg <- exp(lods)/(1+exp(lods))
+	if(set.statistic=="mean50") {
 	
 #	Observed rankings for each set
-	obs.ranks <- matrix(0,ngenes,3)
-	if(floor) {
-		obs.ranks[,1] <- rank(pmax(modt,0))
-		obs.ranks[,2] <- rank(pmax(-modt,0))
-		obs.ranks[,3] <- rank(pmax(abs(modt),1))
-	} else {
-		obs.ranks[,1] <- rank(modt)
-		obs.ranks[,2] <- ngenes-obs.ranks[,1]+1
-		obs.ranks[,3] <- rank(abs(modt))
-	}
-	obs.set.ranks <- matrix(0,nset,3)
-	for(i in 1:nset) obs.set.ranks[i,] <- colMeans(obs.ranks[index[[i]],,drop=FALSE])
+	s.r <- rank(modt)
+	s.abs.r <- rank(abs(modt))
 
-#	Shrink contrast to be like a residual
-	Y[1,] <- Y[1,]*(sv$var.post/(sv$var.post+var.prior*pg))^(1/2)
+	s.rank.mixed <- rep(0,nsets)
+	s.rank.up <- rep(0,nsets)
+	s.rank.down <- rep(0,nsets)
 
-#	Random rotations to simulate null hypothesis
-	rot.ranks <- obs.ranks
-	p.value <- matrix(0,nrow=nset,ncol=3)
+	m <- floor((SetSizes+1)/2)
+	for(i in 1:nsets)
+	{
+		mh <- .meanHalf(s.r[index[[i]]],m[i])
+		s.rank.up[i] <- mh[2]	
+		s.rank.down[i] <- mh[1]
+		s.rank.mixed[i] <- .meanHalf(s.abs.r[index[[i]]],m[i])[2]
+	}	
+
+#	Random rotations
+	p.value <- matrix(rep(0,nsets*3),nrow=nsets,ncol=3)
 	for(i in 1:nrot)
 	{
 		R <- matrix(rnorm((d+1)),1,d+1)
@@ -347,48 +232,62 @@ romer.default <- function(y,index,design,contrast=ncol(design),array.weights=NUL
 			sdr.post <- sqrt(s02)
 
 		modtr <- signc*Br/sdr.post
-	
-		if(floor) {
-			rot.ranks[,1] <- rank(pmax(modtr,0))
-			rot.ranks[,2] <- rank(pmax(-modtr,0))
-			rot.ranks[,3] <- rank(pmax(abs(modtr),1))
-		} else {
-			rot.ranks[,1] <- rank(modtr)
-			rot.ranks[,2] <- ngenes-rot.ranks[,1]+1
-			rot.ranks[,3] <- rank(abs(modtr))
-		}
 
-		for(k in 1:nset)
+		s.r.2 <- rank(modtr)
+		s.abs.r.2 <- rank(abs(modtr))
+	
+		for(j in 1:nsets)
 		{
-			rot.set.ranks <- colMeans(rot.ranks[index[[k]],,drop=FALSE])
-			p.value[k,] <- p.value[k,] + (rot.set.ranks >= obs.set.ranks[k,])
+			mh.2 <- .meanHalf(s.r.2[index[[j]]],m[j])
+
+			s.rank.up.2 <- mh.2[2]
+			s.rank.down.2 <- mh.2[1]
+			s.rank.mixed.2 <- .meanHalf(s.abs.r.2[index[[j]]],m[j])[2]
+		
+			if(s.rank.up.2 >= s.rank.up[j]) p.value[j,1] <- p.value[j,1]+1
+			if(s.rank.down.2 <= s.rank.down[j]) p.value[j,2] <- p.value[j,2]+1
+			if(s.rank.mixed.2 >= s.rank.mixed[j]) p.value[j,3] <- p.value[j,3]+1
 		}
 	}	
+	} # end "mean50"
 
 	p.value <- (p.value+1)/(nrot+1)
-	colnames(p.value)<-c("Up","Down","Mixed")
+	colnames(p.value) <- c("Up","Down","Mixed")
 	SetNames <- names(index)
 	if(is.null(SetNames))
-		rownames(p.value) <- 1:nset
+		rownames(p.value) <- 1:nsets
 	else
 		rownames(p.value) <- SetNames
-	set.sizes <- unlist(lapply(index,length))
-	cbind(NGenes=set.sizes,p.value)
+	cbind(NGenes=SetSizes,p.value)
+}
+
+
+.meanHalf <- function(x,n)
+#	Return means of top and bottom halves of a vector of values
+#	Yifang Hu
+{
+	l <- length(x)
+	a <- sort(x,partial=n)
+	top <- mean(a[1:n])
+	if((l%%2)==0) bottom <- mean(a[(n+1):l])
+	if((l%%2)!=0) bottom <- mean(a[n:l])
+	c(top,bottom)
 }
 
+
 topRomer <- function(x,n=10,alternative="up")
-# extracts a number of top gene sets results from the romer output.
-# Gordon Smyth and Yifang Hu.
-# 22 Mar 2010.  Last modified 5 Sep 2011.
+#	Extract top gene sets results from romer output
+#	Gordon Smyth and Yifang Hu.
+#	Created 22 Mar 2010.	Last modified 30 March 2015.
 {
 	n <- min(n,nrow(x))
 	alternative <- match.arg(tolower(alternative),c("up","down","mixed"))
 	alternative <- switch(alternative,"up"="Up","down"="Down","mixed"="Mixed")
 	o <- switch(alternative,
-		"Up"=order(x[,"Up"],x[,"Mixed"],-x[,"NGenes"]),
-		"Down"=order(x[,"Down"],x[,"Mixed"],-x[,"NGenes"]),
-		"Mixed"=order(x[,"Mixed"],x[,"Up"],x[,"Down"],-x[,"NGenes"])
+		"Up" = order(x[,"Up"],x[,"Mixed"],-x[,"NGenes"]),
+		"Down" = order(x[,"Down"],x[,"Mixed"],-x[,"NGenes"]),
+		"Mixed" = order(x[,"Mixed"],pmin(x[,"Up"],x[,"Down"]),-x[,"NGenes"])
 	)
-	x[o,][1:n,,drop=FALSE]
+	x[o[1L:n],,drop=FALSE]
 }
 
diff --git a/R/goana.R b/R/goana.R
index 851d275..9b935ac 100644
--- a/R/goana.R
+++ b/R/goana.R
@@ -1,36 +1,42 @@
 goana <- function(de,...) UseMethod("goana")
 
-goana.MArrayLM <- function(de, coef = ncol(de), geneid = rownames(de), FDR = 0.05, species = "Hs", trend = FALSE, ...)
-#  Gene ontology analysis of DE genes from linear model fit
-#  Gordon Smyth and Yifang Hu
-#  Created 20 June 2014.  Last modified 23 July 2014.
+goana.MArrayLM <- function(de, coef = ncol(de), geneid = rownames(de), FDR = 0.05, trend = FALSE, ...)
+#	Gene ontology analysis of DE genes from linear model fit
+#	Gordon Smyth and Yifang Hu
+#	Created 20 June 2014.  Last modified 1 May 2015.
 {
-	# Check fit
-	if(is.null(de$p.value)) stop("p value not found in fit object (from eBayes).")	
-	if(is.null(de$coefficients)) stop("coefficient not found in fit object.")
-	if(length(coef) != 1) stop("coef length needs to be 1.")
+#	Avoid argument collision with default method
+	dots <- names(list(...))
+	if("universe" %in% dots) stop("goana.MArrayLM defines its own universe",call.=FALSE)
+	if((!is.logical(trend) || trend) && "covariate" %in% dots) stop("goana.MArrayLM defines it own covariate",call.=FALSE)
+
+#	Check fit
+	if(is.null(de$coefficients)) stop("de does not appear to be a valid MArrayLM fit object.")
+	if(is.null(de$p.value)) stop("p.value not found in fit object, perhaps need to run eBayes first.")	
+	if(length(coef) != 1) stop("Only one coef can be specified.")
 	ngenes <- nrow(de)
 
-	# Check geneid
-	# Can be either a vector of IDs or a column name
+#	Check geneid
+#	Can be either a vector of gene IDs or an annotation column name
 	geneid <- as.character(geneid)
 	if(length(geneid) == ngenes) {
 		universe <- geneid
-	} else
+	} else {
 		if(length(geneid) == 1L) {
 			universe <- de$genes[[geneid]]
-			if(is.null(universe)) stop(paste("Column",geneid,"not found in de$genes"))
+			if(is.null(universe)) stop("Column ",geneid," not found in de$genes")
 		} else
-			stop("geneid has incorrect length")
+			stop("geneid of incorrect length")
+	}
 
-	# Check trend
-	# Can be logical, or a numeric vector of covariate values, or the name of the column containing the covariate values
+#	Check trend
+#	Can be logical, or a numeric vector of covariate values, or the name of the column containing the covariate values
 	if(is.logical(trend)) {
 		if(trend) {
 			covariate <- de$Amean
 			if(is.null(covariate)) stop("Amean not found in fit")
 		}
-	} else
+	} else {
 		if(is.numeric(trend)) {
 			if(length(trend) != ngenes) stop("If trend is numeric, then length must equal nrow(de)")
 			covariate <- trend
@@ -39,71 +45,84 @@ goana.MArrayLM <- function(de, coef = ncol(de), geneid = rownames(de), FDR = 0.0
 			if(is.character(trend)) {
 				if(length(trend) != 1L) stop("If trend is character, then length must be 1")
 				covariate <- de$genes[[trend]]
-				if(is.null(covariate)) stop(paste("Column",trend,"not found in de$genes"))
+				if(is.null(covariate)) stop("Column ",trend," not found in de$genes")
 				trend <- TRUE
 			} else
 				stop("trend is neither logical, numeric nor character")
 		}
+	}
 
-	# Check FDR
+#	Check FDR
 	if(!is.numeric(FDR) | length(FDR) != 1) stop("FDR must be numeric and of length 1.")
 	if(FDR < 0 | FDR > 1) stop("FDR should be between 0 and 1.")
 
-	# Get up and down DE genes
+#	Get up and down DE genes
 	fdr.coef <- p.adjust(de$p.value[,coef], method = "BH")
 	EG.DE.UP <- universe[fdr.coef < FDR & de$coef[,coef] > 0]
 	EG.DE.DN <- universe[fdr.coef < FDR & de$coef[,coef] < 0]
-	de.gene <- list(Up=EG.DE.UP, Down=EG.DE.DN)
+	DEGenes <- list(Up=EG.DE.UP, Down=EG.DE.DN)
 
-	# Fit monotonic cubic spline for DE genes vs. gene.weights
-	if(trend) {
-		isDE <- as.numeric(fdr.coef < FDR)
-		o <- order(covariate)
-		PW <- rep(0,nrow(de))
-		PW[o] <- tricubeMovingAverage(isDE[o],span=0.5,full.length=TRUE)
+#	If no DE genes, return data.frame with 0 rows
+	if(length(EG.DE.UP)==0 && length(EG.DE.DN)==0) {
+		message("No DE genes")
+		return(data.frame())
 	}
-	if(!trend) PW <- NULL
 
-	NextMethod(de = de.gene, universe = universe, species = species, prior.prob = PW, ...)
+	if(trend)
+		goana(de=DEGenes, universe = universe, covariate=covariate, ...)
+	else
+		goana(de=DEGenes, universe = universe, ...)
 }
 
-goana.default <- function(de, universe = NULL, species = "Hs", prior.prob = NULL, ...)
-#  Gene ontology analysis of DE genes
-#  Gordon Smyth and Yifang Hu
-#  Created 20 June 2014.  Last modified 28 August 2014.
+goana.default <- function(de, universe = NULL, species = "Hs", prior.prob = NULL, covariate=NULL, plot=FALSE, ...)
+#	Gene ontology analysis of DE genes
+#	Gordon Smyth and Yifang Hu
+#	Created 20 June 2014.  Last modified 27 March 2015.
 {
-	# Ensure de is a list
+#	Ensure de is a list
 	if(!is.list(de)) de <- list(DE = de)
 
-	# Stop if components of de are not vectors
+#	Stop if components of de are not vectors
 	if(!all(vapply(de,is.vector,TRUE))) stop("components of de should be vectors")
 
-	# Ensure gene IDs are of character mode
+#	Ensure gene IDs are of character mode
 	de <- lapply(de, as.character)
+	if(!is.null(universe)) universe <- as.character(universe)
 
-	# Ensure all gene sets have names
+#	Ensure all gene sets have unique names
 	nsets <- length(de)
-
 	names(de) <- trimWhiteSpace(names(de))
 	NAME <- names(de)
-	i <- NAME == "" | is.na(NAME)
-	NAME[i] <- paste0("DE", 1:nsets)[i]
+	i <- which(NAME == "" | is.na(NAME))
+	NAME[i] <- paste0("DE",i)
 	names(de) <- makeUnique(NAME)
 
-	# Select species
+#	Select species
 	species <- match.arg(species, c("Hs", "Mm", "Rn", "Dm"))
 
-	# Load package of GO terms
+#	Fit trend in DE with respect to the covariate, combining all de lists
+	if(!is.null(covariate)) {
+		covariate <- as.numeric(covariate)
+		if(length(covariate) != length(covariate)) stop("universe and covariate must have same length")
+		isDE <- as.numeric(universe %in% unlist(de))
+		o <- order(covariate)
+		prior.prob <- covariate
+		span <- approx(x=c(20,200),y=c(1,0.5),xout=sum(isDE),rule=2)$y
+		prior.prob[o] <- tricubeMovingAverage(isDE[o],span=span,full.length=TRUE)
+		if(plot) barcodeplot(covariate, index=(isDE==1), worm=TRUE, span.worm=span)
+	}
+
+#	Load package of GO terms
 	if(!suppressPackageStartupMessages(require("GO.db", character.only = TRUE))) stop("GO.db package not available")
 
-	# Load species annotation package
+#	Load species annotation package
 	DB <- paste("org", species, "eg", "db", sep = ".")
 	if(!suppressPackageStartupMessages(require(DB, character.only = TRUE))) stop(DB,"package not available")
 
-	# Get gene-GOterm mappings, and remove duplicate entries
+#	Get gene-GOterm mappings, and remove duplicate entries
 	GO2ALLEGS <- paste("org", species, "egGO2ALLEGS", sep = ".")
 	if(is.null(universe)) {
-		EG.GO <- toTable(get(GO2ALLEGS))
+		EG.GO <- AnnotationDbi::toTable(get(GO2ALLEGS))
 		d <- duplicated(EG.GO[,c("gene_id", "go_id", "Ontology")])
 		EG.GO <- EG.GO[!d, ]
 		universe <- unique(EG.GO$gene_id)
@@ -115,17 +134,19 @@ goana.default <- function(de, universe = NULL, species = "Hs", prior.prob = NULL
 		dup <- duplicated(universe)
 		if(!is.null(prior.prob)) {
 			if(length(prior.prob)!=length(universe)) stop("length(prior.prob) must equal length(universe)")
-			prior.prob <- prior.prob[!dup]
+			prior.prob <- rowsum(prior.prob,group=universe,reorder=FALSE)
+			n <- rowsum(rep_len(1L,length(universe)),group=universe,reorder=FALSE)
+			prior.prob <- prior.prob/n
 		}
 		universe <- universe[!dup]
 
 		GO2ALLEGS <- get(GO2ALLEGS)
-		m <- match(Lkeys(GO2ALLEGS),universe,0L)
+		m <- match(AnnotationDbi::Lkeys(GO2ALLEGS),universe,0L)
 		universe <- universe[m]
 		if(!is.null(prior.prob)) prior.prob <- prior.prob[m]
 
-		Lkeys(GO2ALLEGS) <- universe
-		EG.GO <- toTable(GO2ALLEGS)
+		AnnotationDbi::Lkeys(GO2ALLEGS) <- universe
+		EG.GO <- AnnotationDbi::toTable(GO2ALLEGS)
 		d <- duplicated(EG.GO[,c("gene_id", "go_id", "Ontology")])
 		EG.GO <- EG.GO[!d, ]
 	}
@@ -133,18 +154,18 @@ goana.default <- function(de, universe = NULL, species = "Hs", prior.prob = NULL
 	Total <- length(unique(EG.GO$gene_id))
 	if(Total<1L) stop("No genes found in universe")
 
-	# Check prior probabilities
+#	Check prior probabilities
 	if(!is.null(prior.prob)) {
 		if(length(prior.prob)!=length(universe)) stop("length(prior.prob) must equal length(universe)")
 	}
 
-	# Overlap with DE genes
+#	Overlap with DE genes
 	isDE <- lapply(de, function(x) EG.GO$gene_id %in% x)
 	TotalDE <- lapply(isDE, function(x) length(unique(EG.GO$gene_id[x])))
 	nDE <- length(isDE)
 
 	if(length(prior.prob)) {
-		# Probability weight for each gene
+	#	Probability weight for each gene
 		m <- match(EG.GO$gene_id, universe)
 		PW2 <- list(prior.prob[m])
 		X <- do.call(cbind, c(N=1, isDE, PW=PW2))
@@ -158,79 +179,93 @@ goana.default <- function(de, universe = NULL, species = "Hs", prior.prob = NULL
 
 	if(length(prior.prob)) {
 
-		# Calculate weight
-		require("BiasedUrn", character.only = TRUE)
+#		Calculate average prior prob for each set
 		PW.ALL <- sum(prior.prob[universe %in% EG.GO$gene_id])
 		AVE.PW <- S[,"PW"]/S[,"N"]
 		W <- AVE.PW*(Total-S[,"N"])/(PW.ALL-S[,"N"]*AVE.PW)
 
-		# Wallenius' noncentral hypergeometric test
-		for(j in 1:nsets) for(i in 1:nrow(S))
-			P[i,j] <- pWNCHypergeo(S[i,1+j], S[i,"N"], Total-S[i,"N"], TotalDE[[j]], W[i],lower.tail=FALSE) + dWNCHypergeo(S[i,1+j], S[i,"N"], Total-S[i,"N"], TotalDE[[j]], W[i])
-
+#		Wallenius' noncentral hypergeometric test
+		if(!requireNamespace("BiasedUrn",quietly=TRUE)) stop("BiasedUrn package required but is not available")
+		for(j in 1:nsets) for(i in 1:nrow(S)) 
+			P[i,j] <- BiasedUrn::pWNCHypergeo(S[i,1+j], S[i,"N"], Total-S[i,"N"], TotalDE[[j]], W[i],lower.tail=FALSE) + BiasedUrn::dWNCHypergeo(S[i,1+j], S[i,"N"], Total-S[i,"N"], TotalDE[[j]], W[i])
 		S <- S[,-ncol(S)]
 
 	} else {
 
-		# Fisher's exact test
+	#	Fisher's exact test
 		for(j in 1:nsets)
 			P[,j] <- phyper(q=S[,1+j]-0.5,m=TotalDE[[j]],n=Total-TotalDE[[j]], k=S[,"N"],lower.tail=FALSE)
 
 	}
 
-	# Assemble output
+#	Assemble output
 	g <- strsplit2(rownames(S),split="\\.")
-	TERM <- select(GO.db,keys=g[,1],columns="TERM")
+	TERM <- AnnotationDbi::select(GO.db::GO.db,keys=g[,1],columns="TERM")
 	Results <- data.frame(Term = TERM[[2]], Ont = g[,2], S, P, stringsAsFactors=FALSE)
 	rownames(Results) <- g[,1]
 
-	# Name p-value columns
+#	Name p-value columns
 	colnames(Results)[3+nsets+(1L:nsets)] <- paste0("P.", names(de))
 
 	Results
 }
 
-topGO <- function(results, ontology = c("BP", "CC", "MF"), sort = NULL, number = 20L)
-#  Extract sorted results from goana output 
-#  Gordon Smyth and Yifang Hu
-#  Created 20 June 2014. Last modified 29 August 2014.
+topGO <- function(results, ontology = c("BP", "CC", "MF"), sort = NULL, number = 20L, truncate.term=NULL)
+#	Extract top GO terms from goana output 
+#	Gordon Smyth and Yifang Hu
+#	Created 20 June 2014. Last modified 22 April 2015.
 {
-	# Check results
+#	Check results
 	if(!is.data.frame(results)) stop("results should be a data.frame.")
 
-	# Number of gene sets
-	nsets <- (ncol(results)-3L) %/% 2L
-	setnames <- colnames(results)[4L:(3L+nsets)]
-
-	# Check ontology
+#	Check ontology
 	ontology <- match.arg(unique(ontology), c("BP", "CC", "MF"), several.ok = TRUE)
 
-	# Check sort and find p-value column
-	if(is.null(sort)) {
-		P.col <- 4L+nsets
-	} else {
-		sort <- as.character(sort[1])
-		if(sort=="up") sort="Up"
-		if(sort=="down") sort="Down"
-		sort <- paste0("^",sort,"$")
-		P.col <- grep(sort, setnames)
-		if(!length(P.col)) stop("sort column not found")
-		P.col <- 3L+nsets+P.col
-	}
-
-	# Check number
-	if(!is.numeric(number)) stop("Need to input number.")
-	if(number < 1L) return(data.frame())
-
-	# Limit results to specified ontologies
+#	Limit results to specified ontologies
 	if(length(ontology) < 3L) {
 		sel <- results$Ont %in% ontology
 		results <- results[sel,]
 	}
+	dimres <- dim(results)
+
+#	Check number
+	if(!is.numeric(number)) stop("number should be a positive integer")
+	if(number > dimres[1L]) number <- dimres[1]
+	if(number < 1L) return(results[integer(0),])
+
+#	Number of gene lists for which results are reported
+#	Lists are either called "Up" and "Down" or have user-supplied names
+	nsets <- (dimres[2L]-3L) %/% 2L
+	if(nsets < 1L) stop("results has wrong number of columns")
+	setnames <- colnames(results)[4L:(3L+nsets)]
+
+#	Check sort. Defaults to all gene lists.
+	if(is.null(sort)) {
+		isort <- 1L:nsets
+	} else {
+		sort <- as.character(sort)
+		isort <- which(tolower(setnames) %in% tolower(sort))
+		if(!length(isort)) stop("sort column not found in results")
+	}
 
-	# Sort by p-value
-	o <- order(results[,P.col], rownames(results))
-	if(number < length(o)) o <- o[1:number]
+#	Sort by minimum p-value for specified gene lists
+	P.col <- 3L+nsets+isort
+	if(length(P.col)==1L) {
+		o <- order(results[,P.col])
+	} else {
+		o <- order(do.call("pmin",as.data.frame(results[,P.col,drop=FALSE])))
+	}
+	tab <- results[o[1L:number],,drop=FALSE]
+
+#	Truncate Term column for readability
+	if(!is.null(truncate.term)) {
+		truncate.term <- as.integer(truncate.term[1])
+		truncate.term <- max(truncate.term,5L)
+		truncate.term <- min(truncate.term,1000L)
+		tm2 <- truncate.term-3L
+		i <- (nchar(tab$Term) > tm2)
+		tab$Term[i] <- paste0(substring(tab$Term[i],1L,tm2),"...")
+	}
 
-	results[o,,drop=FALSE]
+	tab
 }
diff --git a/R/kegga.R b/R/kegga.R
new file mode 100644
index 0000000..bdfb813
--- /dev/null
+++ b/R/kegga.R
@@ -0,0 +1,277 @@
+kegga <- function(de,...) UseMethod("kegga")
+
+kegga.MArrayLM <- function(de, coef = ncol(de), geneid = rownames(de), FDR = 0.05, trend = FALSE, ...)
+#	KEGG (Kyoto Encyclopedia of Genes and Genomes) pathway analysis of DE genes from linear model fit
+#	Gordon Smyth and Yifang Hu
+#	Created 15 May 2015. Last modified 3 June 2015.
+{
+#	Avoid argument collision with default method
+	dots <- names(list(...))
+	if("universe" %in% dots) stop("kegga.MArrayLM defines its own universe",call.=FALSE)
+	if((!is.logical(trend) || trend) && "covariate" %in% dots) stop("kegga.MArrayLM defines it own covariate",call.=FALSE)
+
+#	Check fit
+	if(is.null(de$coefficients)) stop("de does not appear to be a valid MArrayLM fit object.")
+	if(is.null(de$p.value)) stop("p.value not found in fit object, perhaps need to run eBayes first.")	
+	if(length(coef) != 1) stop("Only one coef can be specified.")
+	ngenes <- nrow(de)
+
+#	Check geneid
+#	Can be either a vector of gene IDs or an annotation column name
+	geneid <- as.character(geneid)
+	if(length(geneid) == ngenes) {
+		universe <- geneid
+	} else {
+		if(length(geneid) == 1L) {
+			universe <- de$genes[[geneid]]
+			if(is.null(universe)) stop("Column ",geneid," not found in de$genes")
+		} else
+			stop("geneid of incorrect length")
+	}
+
+#	Check trend
+#	Can be logical, or a numeric vector of covariate values, or the name of the column containing the covariate values
+	if(is.logical(trend)) {
+		if(trend) {
+			covariate <- de$Amean
+			if(is.null(covariate)) stop("Amean not found in fit")
+		}
+	} else {
+		if(is.numeric(trend)) {
+			if(length(trend) != ngenes) stop("If trend is numeric, then length must equal nrow(de)")
+			covariate <- trend
+			trend <- TRUE
+		} else {
+			if(is.character(trend)) {
+				if(length(trend) != 1L) stop("If trend is character, then length must be 1")
+				covariate <- de$genes[[trend]]
+				if(is.null(covariate)) stop("Column ",trend," not found in de$genes")
+				trend <- TRUE
+			} else
+				stop("trend is neither logical, numeric nor character")
+		}
+	}
+
+#	Check FDR
+	if(!is.numeric(FDR) | length(FDR) != 1) stop("FDR must be numeric and of length 1.")
+	if(FDR < 0 | FDR > 1) stop("FDR should be between 0 and 1.")
+
+#	Get up and down DE genes
+	fdr.coef <- p.adjust(de$p.value[,coef], method = "BH")
+	EG.DE.UP <- universe[fdr.coef < FDR & de$coef[,coef] > 0]
+	EG.DE.DN <- universe[fdr.coef < FDR & de$coef[,coef] < 0]
+	DEGenes <- list(Up=EG.DE.UP, Down=EG.DE.DN)
+
+#	If no DE genes, return data.frame with 0 rows
+	if(length(EG.DE.UP)==0 && length(EG.DE.DN)==0) {
+		message("No DE genes")
+		return(data.frame())
+	}
+
+	if(trend)
+		kegga(de=DEGenes, universe = universe, covariate=covariate, ...)
+	else
+		kegga(de=DEGenes, universe = universe, ...)
+}
+
+kegga.default <- function(de, universe = NULL, species = "Hs", prior.prob = NULL, covariate=NULL, plot=FALSE, ...)
+#	KEGG (Kyoto Encyclopedia of Genes and Genomes) pathway analysis of DE genes
+#	Gordon Smyth and Yifang Hu
+#	Created 18 May 2015.  Modified 3 June 2015.
+{
+#	Ensure de is a list
+	if(!is.list(de)) de <- list(DE = de)
+
+#	Stop if components of de are not vectors
+	if(!all(vapply(de,is.vector,TRUE))) stop("components of de should be vectors")
+
+#	Ensure gene IDs are of character mode
+	de <- lapply(de, as.character)
+	if(!is.null(universe)) universe <- as.character(universe)
+
+#	Ensure all gene sets have unique names
+	nsets <- length(de)
+	names(de) <- trimWhiteSpace(names(de))
+	NAME <- names(de)
+	i <- which(NAME == "" | is.na(NAME))
+	NAME[i] <- paste0("DE",i)
+	names(de) <- makeUnique(NAME)
+
+#	Select species
+	species <- match.arg(species, c("Hs", "Mm", "Rn", "Dm"))
+
+#	Fit trend in DE with respect to the covariate, combining all de lists
+	if(!is.null(covariate)) {
+		covariate <- as.numeric(covariate)
+		if(length(covariate) != length(covariate)) stop("universe and covariate must have same length")
+		isDE <- as.numeric(universe %in% unlist(de))
+		o <- order(covariate)
+		prior.prob <- covariate
+		span <- approx(x=c(20,200),y=c(1,0.5),xout=sum(isDE),rule=2)$y
+		prior.prob[o] <- tricubeMovingAverage(isDE[o],span=span,full.length=TRUE)
+		if(plot) barcodeplot(covariate, index=(isDE==1), worm=TRUE, span.worm=span)
+	}
+
+#	Enable REST-style online access to KEGG pathways
+	if(!requireNamespace("KEGGREST",quietly=TRUE)) stop("KEGGREST required but is not available")
+
+#	Convert to KEGG organism/species codes
+	organism <- switch(species, "Hs"="hsa", "Dm"="dme", "Mm"="mmu", "Rn"="rno")
+
+#	Get gene-KEGG mappings, and remove duplicate entries
+	if(is.null(universe)) {
+
+		path <- KEGGREST::keggLink("pathway", organism)
+		path <- data.frame(kegg_id = names(path), path_id = path, stringsAsFactors = FALSE)
+		if(organism == "dme") {
+			EG <- KEGGREST::keggConv("dme", "ncbi-geneid")
+			geneid <- names(EG)[match(path$kegg_id, EG)]
+			geneid <- gsub("ncbi-geneid:", "", geneid)
+		} else {
+			geneid <- gsub(paste0(organism, ":"), "", path$kegg_id)
+		}
+		EG.KEGG <- data.frame(gene_id = geneid, path, stringsAsFactors = FALSE)
+
+		universe <- unique(EG.KEGG$gene_id)
+		universe <- as.character(universe)
+	} else {
+
+		universe <- as.character(universe)
+
+		dup <- duplicated(universe)
+		if(!is.null(prior.prob)) {
+			if(length(prior.prob)!=length(universe)) stop("length(prior.prob) must equal length(universe)")
+			prior.prob <- rowsum(prior.prob,group=universe,reorder=FALSE)
+			n <- rowsum(rep_len(1L,length(universe)),group=universe,reorder=FALSE)
+			prior.prob <- prior.prob/n
+		}
+		universe <- universe[!dup]
+
+		path <- KEGGREST::keggLink("pathway", organism)
+		path <- data.frame(kegg_id = names(path), path_id = path, stringsAsFactors = FALSE)
+		if(organism == "dme") {
+			EG <- KEGGREST::keggConv("dme", "ncbi-geneid")
+			geneid <- names(EG)[match(path$kegg_id, EG)]
+			geneid <- gsub("ncbi-geneid:", "", geneid)
+		} else {
+			geneid <- gsub(paste0(organism, ":"), "", path$kegg_id)
+		}
+		EG.KEGG <- data.frame(gene_id = geneid, path, stringsAsFactors = FALSE)
+
+		m <- match(EG.KEGG$gene_id, universe)
+		universe <- universe[m]
+		if(!is.null(prior.prob)) prior.prob <- prior.prob[m]
+		EG.KEGG <- EG.KEGG[EG.KEGG$gene_id %in% universe,]
+	}
+
+	Total <- length(unique(EG.KEGG$gene_id))
+	if(Total<1L) stop("No genes found in universe")
+
+#	Check prior probabilities
+	if(!is.null(prior.prob)) {
+		if(length(prior.prob)!=length(universe)) stop("length(prior.prob) must equal length(universe)")
+	}
+
+#	Overlap with DE genes
+	isDE <- lapply(de, function(x) EG.KEGG$gene_id %in% x)
+	TotalDE <- lapply(isDE, function(x) length(unique(EG.KEGG$gene_id[x])))
+	nDE <- length(isDE)
+
+	if(length(prior.prob)) {
+	#	Probability weight for each gene
+		m <- match(EG.KEGG$gene_id, universe)
+		PW2 <- list(prior.prob[m])
+		X <- do.call(cbind, c(N=1, isDE, PW=PW2))
+	} else
+		X <- do.call(cbind, c(N=1, isDE))
+
+	group <- EG.KEGG$path_id
+	S <- rowsum(X, group=group, reorder=FALSE)
+
+	P <- matrix(0, nrow = nrow(S), ncol = nsets)
+
+	if(length(prior.prob)) {
+
+#		Calculate average prior prob for each set
+		PW.ALL <- sum(prior.prob[universe %in% EG.KEGG$gene_id])
+		AVE.PW <- S[,"PW"]/S[,"N"]
+		W <- AVE.PW*(Total-S[,"N"])/(PW.ALL-S[,"N"]*AVE.PW)
+
+#		Wallenius' noncentral hypergeometric test
+		if(!requireNamespace("BiasedUrn",quietly=TRUE)) stop("BiasedUrn package required but is not available")
+		for(j in 1:nsets) for(i in 1:nrow(S)) 
+			P[i,j] <- BiasedUrn::pWNCHypergeo(S[i,1+j], S[i,"N"], Total-S[i,"N"], TotalDE[[j]], W[i],lower.tail=FALSE) + BiasedUrn::dWNCHypergeo(S[i,1+j], S[i,"N"], Total-S[i,"N"], TotalDE[[j]], W[i])
+		S <- S[,-ncol(S)]
+
+	} else {
+
+#		Fisher's exact test
+		for(j in 1:nsets)
+			P[,j] <- phyper(q=S[,1+j]-0.5,m=TotalDE[[j]],n=Total-TotalDE[[j]], k=S[,"N"],lower.tail=FALSE)
+
+	}
+
+#	Assemble output
+	g <- rownames(S)
+	pathname <- KEGGREST::keggList("pathway")
+	names(pathname) <- gsub("map", organism, names(pathname))
+	m <- match(g, names(pathname))
+	Results <- data.frame(Path = pathname[m], S, P, stringsAsFactors=FALSE)
+	rownames(Results) <- g
+
+#	Name p-value columns
+	colnames(Results)[2+nsets+(1L:nsets)] <- paste0("P.", names(de))
+
+	Results
+}
+
+topKEGG <- function(results, sort = NULL, number = 20L, truncate.term=NULL)
+#	Extract top KEGG pathways from kegga output 
+#	Gordon Smyth and Yifang Hu
+#	Created 15 May 2015.
+{
+#	Check results
+	if(!is.data.frame(results)) stop("results should be a data.frame.")
+	dimres <- dim(results)
+
+#	Check number
+	if(!is.numeric(number)) stop("number should be a positive integer")
+	if(number > dimres[1L]) number <- dimres[1]
+	if(number < 1L) return(results[integer(0),])
+
+#	Number of gene lists for which results are reported
+#	Lists are either called "Up" and "Down" or have user-supplied names
+	nsets <- (dimres[2L]-2L) %/% 2L
+	if(nsets < 1L) stop("results has wrong number of columns")
+	setnames <- colnames(results)[3L:(2L+nsets)]
+
+#	Check sort. Defaults to all gene lists.
+	if(is.null(sort)) {
+		isort <- 1L:nsets
+	} else {
+		sort <- as.character(sort)
+		isort <- which(tolower(setnames) %in% tolower(sort))
+		if(!length(isort)) stop("sort column not found in results")
+	}
+
+#	Sort by minimum p-value for specified gene lists
+	P.col <- 2L+nsets+isort
+	if(length(P.col)==1L) {
+		o <- order(results[,P.col])
+	} else {
+		o <- order(do.call("pmin",as.data.frame(results[,P.col,drop=FALSE])))
+	}
+	tab <- results[o[1L:number],,drop=FALSE]
+
+#	Truncate Term column for readability
+	if(!is.null(truncate.term)) {
+		truncate.term <- as.integer(truncate.term[1])
+		truncate.term <- max(truncate.term,5L)
+		truncate.term <- min(truncate.term,1000L)
+		tm2 <- truncate.term-3L
+		i <- (nchar(tab$Term) > tm2)
+		tab$Term[i] <- paste0(substring(tab$Term[i],1L,tm2),"...")
+	}
+
+	tab
+}
diff --git a/R/lmfit.R b/R/lmfit.R
index 4908841..03a712e 100644
--- a/R/lmfit.R
+++ b/R/lmfit.R
@@ -3,7 +3,7 @@
 lmFit <- function(object,design=NULL,ndups=1,spacing=1,block=NULL,correlation,weights=NULL,method="ls",...)
 #	Fit genewise linear models
 #	Gordon Smyth
-#	30 June 2003.  Last modified 28 July 2013.
+#	30 June 2003.  Last modified 7 July 2015.
 {
 #	Extract components from y
 	y <- getEAWP(object)
@@ -15,6 +15,7 @@ lmFit <- function(object,design=NULL,ndups=1,spacing=1,block=NULL,correlation,we
 	else {
 		design <- as.matrix(design)
 		if(mode(design) != "numeric") stop("design must be a numeric matrix")
+		if(nrow(design) != ncol(y$exprs)) stop("row dimension of design doesn't match column dimension of data object")
 	}
 	ne <- nonEstimable(design)
 	if(!is.null(ne)) cat("Coefficients not estimable:",paste(ne,collapse=" "),"\n")
@@ -67,7 +68,7 @@ lmFit <- function(object,design=NULL,ndups=1,spacing=1,block=NULL,correlation,we
 lm.series <- function(M,design=NULL,ndups=1,spacing=1,weights=NULL)
 #	Fit linear model for each gene to a series of arrays
 #	Gordon Smyth
-#	18 Apr 2002. Revised 16 Apr 2013.
+#	18 Apr 2002. Revised 26 June 2015.
 {
 #	Check expression matrix
 	M <- as.matrix(M)
@@ -130,7 +131,7 @@ lm.series <- function(M,design=NULL,ndups=1,spacing=1,weights=NULL)
 		return(fit)
 	}
 
-#	Genewise QR-decompositions are required, so iteration through genes
+#	Genewise QR-decompositions are required, so iterate through genes
 	beta <- stdev.unscaled
 	sigma <- rep(NA,ngenes)
 	df.residual <- rep(0,ngenes)
@@ -160,15 +161,15 @@ lm.series <- function(M,design=NULL,ndups=1,spacing=1,weights=NULL)
 	est <- QR$pivot[1:QR$rank]
 	dimnames(cov.coef) <- list(coef.names[est],coef.names[est])
 
-	list(coefficients=beta,stdev.unscaled=stdev.unscaled,sigma=sigma,df.residual=df.residual,cov.coefficients=cov.coef,pivot=QR$pivot)
+	list(coefficients=beta,stdev.unscaled=stdev.unscaled,sigma=sigma,df.residual=df.residual,cov.coefficients=cov.coef,pivot=QR$pivot,rank=QR$rank)
 }
 
 mrlm <- function(M,design=NULL,ndups=1,spacing=1,weights=NULL,...)
 #	Robustly fit linear model for each gene to a series of arrays
 #	Gordon Smyth
-#	20 Mar 2002.  Last revised 22 Feb 2007.
+#	20 Mar 2002.  Last revised 26 June 2015.
 {
-	require(MASS) # need rlm.default
+	if(!requireNamespace("MASS",quietly=TRUE)) stop("MASS package required but is not available")
 	M <- as.matrix(M)
 	narrays <- ncol(M)
 	if(is.null(design)) design <- matrix(1,narrays,1)
@@ -199,7 +200,7 @@ mrlm <- function(M,design=NULL,ndups=1,spacing=1,weights=NULL,...)
 		else
 			w <- as.vector(weights[i,obs])
 		if(length(y) > nbeta) {
-			out <- rlm(x=X,y=y,weights=w,...)
+			out <- MASS::rlm(x=X,y=y,weights=w,...)
 			beta[i,] <- coef(out)
 			stdev.unscaled[i,] <- sqrt(diag(chol2inv(out$qr$qr)))
 			df.residual[i] <- length(y) - out$rank
@@ -210,14 +211,14 @@ mrlm <- function(M,design=NULL,ndups=1,spacing=1,weights=NULL,...)
 	cov.coef <- chol2inv(QR$qr,size=QR$rank)
 	est <- QR$pivot[1:QR$rank]
 	dimnames(cov.coef) <- list(coef.names[est],coef.names[est])
-	list(coefficients=beta,stdev.unscaled=stdev.unscaled,sigma=sigma,df.residual=df.residual,cov.coefficients=cov.coef,pivot=QR$pivot)
+	list(coefficients=beta,stdev.unscaled=stdev.unscaled,sigma=sigma,df.residual=df.residual,cov.coefficients=cov.coef,pivot=QR$pivot,rank=QR$rank)
 }
 
 gls.series <- function(M,design=NULL,ndups=2,spacing=1,block=NULL,correlation=NULL,weights=NULL,...)
 #	Fit linear model for each gene to a series of microarrays.
 #	Fit is by generalized least squares allowing for correlation between duplicate spots.
 #	Gordon Smyth
-#	11 May 2002.  Last revised 12 Dec 2010.
+#	11 May 2002.  Last revised 26 June 2015.
 {
 	M <- as.matrix(M)
 	narrays <- ncol(M)
@@ -336,7 +337,7 @@ gls.series <- function(M,design=NULL,ndups=2,spacing=1,block=NULL,correlation=NU
 	cov.coef <- chol2inv(QR$qr,size=QR$rank)
 	est <- QR$pivot[1:QR$rank]
 	dimnames(cov.coef) <- list(coef.names[est],coef.names[est])
-	list(coefficients=beta,stdev.unscaled=stdev.unscaled,sigma=sigma,df.residual=df.residual,ndups=ndups,spacing=spacing,block=block,correlation=correlation,cov.coefficients=cov.coef,pivot=QR$pivot)
+	list(coefficients=beta,stdev.unscaled=stdev.unscaled,sigma=sigma,df.residual=df.residual,ndups=ndups,spacing=spacing,block=block,correlation=correlation,cov.coefficients=cov.coef,pivot=QR$pivot,rank=QR$rank)
 }
 
 is.fullrank <- function(x)
@@ -390,7 +391,7 @@ getEAWP <- function(object)
 #	Given any microarray data object, extract basic information needed
 #	for linear modelling.
 #	Gordon Smyth
-#	9 March 2008. Last modified 19 Sep 2014.
+#	9 March 2008. Last modified 7 July 2015.
 {
 	y <- list()
 	
@@ -409,10 +410,11 @@ getEAWP <- function(object)
 		y$design <- object$design
 	} else {
 	if(is(object,"ExpressionSet")) {
-		y$exprs <- exprs(object)
+		if(!requireNamespace("Biobase",quietly=TRUE)) stop("Biobase package required but is not available")
+		y$exprs <- Biobase::exprs(object)
 		if(length(object at featureData@data)) y$probes <- object at featureData@data
 		y$Amean <- rowMeans(y$exprs,na.rm=TRUE)
-		if("weights" %in% assayDataElementNames(object)) y$weights <- assayDataElement(object,"weights")
+		if("weights" %in% Biobase::assayDataElementNames(object)) y$weights <- Biobase::assayDataElement(object,"weights")
 	} else {
 	if(is(object,"PLMset")) {
 		y$exprs <- object at chip.coefs
@@ -430,9 +432,10 @@ getEAWP <- function(object)
 		if(length(object at maA)) y$Amean <- rowMeans(object at maA,na.rm=TRUE)
 	} else {
 #		Default method for matrices, data.frames, vsn objects etc.
-		y$exprs <- as.matrix(object)
-#		If exprs are positive, assume they are log-intensities rather than log-ratios
-#		if(all(y$exprs>=0,na.rm=TRUE)) y$Amean <- rowMeans(y$exprs,na.rm=TRUE)
+		if(is.vector(object))
+			y$exprs <- matrix(object,nrow=1)
+		else
+			y$exprs <- as.matrix(object)
 		y$Amean <- rowMeans(y$exprs,na.rm=TRUE)
 	}}}}
 
diff --git a/R/loessFit.R b/R/loessFit.R
index cb50521..3d18152 100644
--- a/R/loessFit.R
+++ b/R/loessFit.R
@@ -4,7 +4,7 @@ loessFit <- function(y, x, weights=NULL, span=0.3, iterations=4L, min.weight=1e-
 #	Fast lowess fit for univariate x and y allowing for weights
 #	Uses lowess() if weights=NULL and weightedLowess(), locfit.raw() or loess() otherwise
 #	Gordon Smyth
-#	28 June 2003.  Last revised 17 Apr 2014.
+#	28 June 2003.  Last revised 14 January 2015.
 {
 #	Check x and y
 	n <- length(y)
@@ -81,15 +81,11 @@ loessFit <- function(y, x, weights=NULL, span=0.3, iterations=4L, min.weight=1e-
 		},
 		"locfit" = {
 #			Check for locfit package
-			loaded <- ( "package:locfit" %in% search() )
-			if(!loaded) {
-				loadresult <- tryCatch(suppressPackageStartupMessages(library("locfit",character.only=TRUE,quietly=TRUE)),error=function(e) e)
-				if(inherits(loadresult,"error")) stop("locfit package not available",call.=FALSE)
-			}
+			if(!requireNamespace("locfit",quietly=TRUE)) stop("locfit required but is not available")
 #			Weighted lowess with robustifying iterations
 		    biweights <- rep(1,nobs)
  			for (i in 1:iterations) {
-       			fit <- locfit.raw(x=xobs,y=yobs,weights=wobs*biweights,alpha=span,deg=1)
+       			fit <- locfit::locfit(yobs~xobs,weights=wobs*biweights,alpha=span,deg=1)
 		        res <- residuals(fit,type="raw")
 		        s <- median(abs(res))
 		        biweights <- pmax(1-(res/(6*s))^2,0)^2
diff --git a/R/neqc.R b/R/neqc.R
index bd94749..fb7a4e6 100644
--- a/R/neqc.R
+++ b/R/neqc.R
@@ -56,7 +56,7 @@ normexp.fit.detection.p <- function(x,detection.p="Detection")
 normexp.fit.control <- function(x,status=NULL,negctrl="negative",regular="regular",robust=FALSE)
 #  Estimate normexp parameters using negative control probes
 #  Wei Shi and Gordon Smyth
-#  Created 17 April 2009. Last modified 19 Dec 2011.
+#  Created 17 April 2009. Last modified 14 January 2015.
 {
 	if(is(x, "EListRaw")) {
 		if(is.null(status)) status <- x$genes$Status
@@ -71,12 +71,12 @@ normexp.fit.control <- function(x,status=NULL,negctrl="negative",regular="regula
 	if(nrow(xn)<2) stop("Fewer than two negative control probes found")
 
 	if(robust) {
-		require(MASS)
+		if(!requireNamespace("MASS",quietly=TRUE)) stop("MASS package required but is not available")
 		narrays <- ncol(xn)
 		m <- s <- rep(0,narrays)
 	#	Robustness is judged on the log-scale, assumed normal
 		for (j in 1:ncol(xn)) {
-			h <- huber(log(xn[,j]))
+			h <- MASS::huber(log(xn[,j]))
 			m[j] <- h$mu
 			s[j] <- h$s
 		}
@@ -95,11 +95,13 @@ normexp.fit.control <- function(x,status=NULL,negctrl="negative",regular="regula
 nec <- function(x,status=NULL,negctrl="negative",regular="regular",offset=16,robust=FALSE,detection.p="Detection")
 #	Normexp background correction aided by negative controls.
 #	Wei Shi and Gordon Smyth
-#	Created 27 September 2010. Last modified 31 March 2011.
+#	Created 27 September 2010. Last modified 21 Oct 2014.
 {
-	if(is(x,"EListRaw") && !is.null(x$Eb)) x$E <- x$E-x$Eb
-		
 	if(is(x, "EListRaw")) {
+		if(!is.null(x$Eb)) {
+			x$E <- x$E-x$Eb
+			x$Eb <- NULL
+		}
 		if(is.null(status)) status <- x$genes$Status
 		if(any(tolower(status) %in% tolower(negctrl))) {
 			normexp.par <- normexp.fit.control(x,status,negctrl,regular,robust)
@@ -107,9 +109,7 @@ nec <- function(x,status=NULL,negctrl="negative",regular="regular",offset=16,rob
 			normexp.par <- normexp.fit.detection.p(x,detection.p)
 			message("Inferred negative control probe intensities were used in background correction.")
 		}
-
-		for(i in 1:ncol(x))
-			x$E[, i] <- normexp.signal(normexp.par[i, ], x$E[, i])
+		for(i in 1:ncol(x)) x$E[,i] <- normexp.signal(normexp.par[i,], x$E[,i])
 		x$E <- x$E + offset
 	} else {
 		x <- as.matrix(x)
@@ -118,9 +118,7 @@ nec <- function(x,status=NULL,negctrl="negative",regular="regular",offset=16,rob
 		} else {
 			normexp.par <- normexp.fit.detection.p(x,detection.p)
 		}
-
-		for(i in 1:ncol(x))
-			x[, i] <- normexp.signal(normexp.par[i, ], x[, i])
+		for(i in 1:ncol(x)) x[,i] <- normexp.signal(normexp.par[i,], x[,i])
 		x <- x + offset
 	}
 	x
diff --git a/R/norm.R b/R/norm.R
index 1e81cd6..5c2f660 100755
--- a/R/norm.R
+++ b/R/norm.R
@@ -146,10 +146,10 @@ normalizeWithinArrays <- function(object,layout=object$printer,method="printtipl
 normalizeRobustSpline <- function(M,A,layout=NULL,df=5,method="M") {
 #	Robust spline normalization
 #	Gordon Smyth
-#	27 April 2003.  Last revised 29 Nov 2012.
+#	27 April 2003.  Last revised 14 January 2015.
 
-	require(MASS)
-	require(splines)
+	if(!requireNamespace("MASS",quietly=TRUE)) stop("MASS package required but is not available")
+	if(!requireNamespace("splines",quietly=TRUE)) stop("splines package required but is not available")
 	if(is.null(layout)) {
 		ngrids <- 1
 		nspots <- length(M)
@@ -163,11 +163,11 @@ normalizeRobustSpline <- function(M,A,layout=NULL,df=5,method="M") {
 #	Global splines
 	O <- is.finite(M) & is.finite(A)
 	X <- matrix(NA,ngrids*nspots,df)
-	X[O,] <- ns(A[O],df=df,intercept=TRUE)
+	X[O,] <- splines::ns(A[O],df=df,intercept=TRUE)
 	x <- X[O,,drop=FALSE]
 	y <- M[O]
 	w <- rep(1,length(y))
-	s0 <- summary(rlm(x,y,weights=w,method=method),method="XtWX",correlation=FALSE)
+	s0 <- summary(MASS::rlm(x,y,weights=w,method=method),method="XtWX",correlation=FALSE)
 	beta0 <- s0$coefficients[,1]
 	covbeta0 <- s0$cov * s0$stddev^2
 
@@ -190,7 +190,7 @@ normalizeRobustSpline <- function(M,A,layout=NULL,df=5,method="M") {
 			r <- qr(x)$rank
 			if(r<df) x <- x[,1:r,drop=FALSE]
 			w <- rep(1,length(y))
-			s <- summary(rlm(x,y,weights=w,method=method),method="XtWX",correlation=FALSE)
+			s <- summary(MASS::rlm(x,y,weights=w,method=method),method="XtWX",correlation=FALSE)
 			beta[i,1:r] <- s$coefficients[,1]
 			covbeta[i,1:r,1:r] <- s$cov * s$stddev^2
 		}
@@ -257,7 +257,8 @@ normalizeForPrintorder.rg <- function(R,G,printorder,method="loess",separate.cha
 	if(method=="plate") {
 		# Correct for plate pack (usually four 384-well plates)
 		plate <- 1 + (printorder-0.5) %/% plate.size
-		hubermu <- function(...) huber(...)$mu
+		if(!requireNamespace("MASS",quietly=TRUE)) stop("MASS package required but is not available")
+		hubermu <- function(...) MASS::huber(...)$mu
 		if(separate.channels) {
 			plate.mR <- tapply(Rf,plate,hubermu)
 			plate.mG <- tapply(Gf,plate,hubermu)
@@ -418,7 +419,8 @@ normalizeBetweenArrays <- function(object, method=NULL, targets=NULL, cyclic.met
 
 normalizeVSN <- function(x,...)
 {
-	require("vsn")
+	if(!requireNamespace("Biobase",quietly=TRUE)) stop("Biobase package required but is not available")
+	if(!requireNamespace("vsn",quietly=TRUE)) stop("vsn package required but is not available")
 	UseMethod("normalizeVSN")
 }
 
@@ -430,7 +432,7 @@ normalizeVSN.RGList <- function(x,...)
 	x <- backgroundCorrect(x,method="subtract")
 	y <- cbind(x$G,x$R)
 	x$G <- x$R <- NULL
-	y <- exprs(vsnMatrix(x=y,...))
+	y <- Biobase::exprs(vsn::vsnMatrix(x=y,...))
 	n2 <- ncol(y)/2
 	G <- y[,1:n2]
 	R <- y[,n2+(1:n2)]
@@ -445,7 +447,7 @@ normalizeVSN.EListRaw <- function(x,...)
 #	9 Sep 2010.
 {
 	x <- backgroundCorrect(x,method="subtract")
-	x$E <- exprs(vsnMatrix(x=x$E,...))
+	x$E <- Biobase::exprs(vsn::vsnMatrix(x=x$E,...))
 	new("EList",unclass(x))
 }
 
@@ -454,7 +456,7 @@ normalizeVSN.default <- function(x,...)
 #	Gordon Smyth
 #	9 Sep 2010.
 {
-	exprs(vsnMatrix(x=as.matrix(x),...))
+	Biobase::exprs(vsn::vsnMatrix(x=as.matrix(x),...))
 }
 
 
diff --git a/R/plot.R b/R/plot.R
deleted file mode 100644
index 904f8ec..0000000
--- a/R/plot.R
+++ /dev/null
@@ -1,64 +0,0 @@
-##  PLOT.R
-##  plot() produces MA plots (aka mean difference plots) on expression objects
-
-plot.RGList <- function(x, y, array=1, xlab="A", ylab="M", main=colnames(x)[array], status=x$genes$Status, zero.weights=FALSE, ...)
-#	MA-plot with color coding for controls
-#	Gordon Smyth
-#	Created 21 March 2014. Last modified 18 Sep 2014.
-{
-	MA <- MA.RG(x[,array])
-	plot.MAList(x=MA,array=1,xlab=xlab,ylab=ylab,main=main,status=status,zero.weights=zero.weights,...)
-}
-
-plot.MAList <- function(x, y, array=1, xlab="A", ylab="M", main=colnames(x)[array], status=x$genes$Status, zero.weights=FALSE, ...)
-#	MA-plot with color coding for controls
-#	Gordon Smyth
-#	Created 21 March 2014. Last modified 18 Sep 2014.
-{
-	A <- as.matrix(x$A)[,array]
-	M <- as.matrix(x$M)[,array]
-	if(!zero.weights && !is.null(x$weights)) {
-		w <- as.matrix(x$weights)[,array]
-		M[ is.na(w) | (w <= 0) ] <- NA
-	}
-	plotWithHighlights(x=A,y=M,xlab=xlab,ylab=ylab,main=main,status=status,...)
-}
-
-plot.MArrayLM <- function(x, y, coef=ncol(x), xlab="Average log-expression", ylab="log-fold-change", main=colnames(x)[coef], status=x$genes$Status, zero.weights=FALSE, ...)
-#	MA-plot with color coding for controls
-#	Gordon Smyth
-#	Created 21 March 2014.  Last modified 18 Sep 2014.
-{
-	if(is.null(x$Amean)) stop("Amean component is absent.")
-	logFC <- as.matrix(x$coef)[,coef]
-	if(!zero.weights && !is.null(x$weights)) {
-		w <- as.matrix(x$weights)[,coef]
-		logFC[ is.na(w) | (w <= 0) ] <- NA
-	}
-	plotWithHighlights(x=x$Amean,y=logFC,xlab=xlab,ylab=ylab,main=main,status=status,...)
-}
-
-plot.EList <- function(x, y, array=1, xlab="Average log-expression", ylab="Expression log-ratio (this sample vs others)", main=colnames(x)[array], status=x$genes$Status, zero.weights=FALSE, ...)
-#	MA-plot with color coding for controls
-#	Gordon Smyth
-#	Created 21 March 2014. Last modified 18 Sep 2014.
-{
-	E <- as.matrix(E$E)
-	if(ncol(E) < 2) stop("Need at least two arrays")
-
-#	Convert array to integer if not already
-	j <- 1L:ncol(E)
-	names(j) <- colnames(E)
-	array <- j[array[1]]
-
-	AveOfOthers <- rowMeans(E[,-array,drop=FALSE],na.rm=TRUE)
-	Diff <- E[,array]-AveOfOthers
-	Mean <- (E[,array]+AveOfOthers)/2
-
-	if(!zero.weights && !is.null(x$weights)) {
-		w <- as.matrix(x$weights)[,array]
-		Diff[ is.na(w) | (w <= 0) ] <- NA
-	}
-
-	plotWithHighlights(x=Mean,y=Diff,xlab=xlab,ylab=ylab,main=main,status=status,...)
-}
diff --git a/R/plotMD.R b/R/plotMD.R
new file mode 100644
index 0000000..57dec0d
--- /dev/null
+++ b/R/plotMD.R
@@ -0,0 +1,116 @@
+##  plotMD.R
+
+plotMD <- function(object,...) UseMethod("plotMD")
+
+plotMD.RGList <- function(object, column=1, array=NULL, xlab="A", ylab="M", main=colnames(object)[column], status=object$genes$Status, zero.weights=FALSE, ...)
+#	Mean-difference plot with color coding for controls
+#	Created by Gordon Smyth 7 April 2003 and James Wettenhall 27 June 2003.
+#	Last modified 7 June 2015.
+{
+	if(!is.null(array)) column <- array
+	object <- MA.RG(object[,column])
+	plotMD.MAList(object=object,column=1,xlab=xlab,ylab=ylab,main=main,status=status,zero.weights=zero.weights,...)
+}
+
+plotMD.MAList <- function(object, column=1, array=NULL, xlab="A", ylab="M", main=colnames(object)[column], status=object$genes$Status, zero.weights=FALSE, ...)
+#	Mean-difference plot with color coding for controls
+#	Gordon Smyth 7 April 2003, James Wettenhall 27 June 2003.
+#	Last modified 7 June 2015.
+{
+	if(!is.null(array)) column <- array
+	A <- as.matrix(object$A)[,column]
+	M <- as.matrix(object$M)[,column]
+	if(!zero.weights && !is.null(object$weights)) {
+		w <- as.matrix(object$weights)[,column]
+		M[ is.na(w) | (w <= 0) ] <- NA
+	}
+	plotWithHighlights(x=A,y=M,xlab=xlab,ylab=ylab,main=main,status=status,...)
+}
+
+plotMD.MArrayLM <- function(object, column=ncol(object), coef=NULL, xlab="Average log-expression", ylab="log-fold-change", main=colnames(object)[column], status=object$genes$Status, zero.weights=FALSE, ...)
+#	Mean-difference plot with color coding for controls
+#	Gordon Smyth 7 April 2003, James Wettenhall 27 June 2003.
+#	Last modified 24 June 2015.
+{
+	if(!is.null(coef)) column <- coef
+	if(is.null(object$Amean)) stop("Amean component is absent.")
+	logFC <- as.matrix(object$coefficients)[,column]
+	if(!zero.weights && !is.null(object$weights)) {
+		w <- as.matrix(object$weights)[,column]
+		logFC[ is.na(w) | (w <= 0) ] <- NA
+	}
+	plotWithHighlights(x=object$Amean,y=logFC,xlab=xlab,ylab=ylab,main=main,status=status,...)
+}
+
+plotMD.EListRaw <- function(object, column=1, array=NULL, xlab="Average log-expression", ylab="Expression log-ratio (this sample vs others)", main=colnames(object)[column], status=object$genes$Status, zero.weights=FALSE, ...)
+#	Mean-difference plot with color coding for controls
+#	Gordon Smyth
+#	Created 22 Oct 2014. Last modified 7 June 2015.
+{
+	if(!is.null(array)) column <- array
+	if(!is.null(object$Eb)) object$E <- object$E-object$Eb
+	object$E <- log2(object$E)
+	object <- new("EList",unclass(object))
+	plotMD(object, column=column, xlab=xlab, ylab=ylab, main=main, status=status, zero.weights=zero.weights, ...)
+}
+
+plotMD.EList <- function(object, column=1, array=NULL, xlab="Average log-expression", ylab="Expression log-ratio (this sample vs others)", main=colnames(object)[column], status=object$genes$Status, zero.weights=FALSE, ...)
+#	Mean-difference plot with color coding for controls
+#	Gordon Smyth 7 April 2003, James Wettenhall 27 June 2003.
+#	Last modified 14 April 2015.
+{
+	if(!is.null(array)) column <- array
+	E <- as.matrix(object$E)
+	if(ncol(E) < 2L) stop("Need at least two columns")
+
+#	Convert column to integer if not already
+	j <- 1:ncol(E)
+	names(j) <- colnames(E)
+	column <- j[column[1]]
+
+	AveOfOthers <- rowMeans(E[,-column,drop=FALSE],na.rm=TRUE)
+	Diff <- E[,column]-AveOfOthers
+	Mean <- (E[,column]+AveOfOthers)/2
+
+	if(!zero.weights && !is.null(object$weights)) {
+		w <- as.matrix(object$weights)[,column]
+		Diff[ is.na(w) | (w <= 0) ] <- NA
+	}
+
+	plotWithHighlights(x=Mean,y=Diff,xlab=xlab,ylab=ylab,main=main,status=status,...)
+}
+
+plotMD.default <- function(object, column=1, xlab="Average log-expression", ylab="Expression log-ratio (this sample vs others)", main=colnames(object)[column], status=NULL, ...)
+#	Mean-difference plot with color coding for controls
+#	Gordon Smyth 7 April 2003, James Wettenhall 27 June 2003.
+#	Last modified 14 April 2015.
+{
+#	Data is assumed to be single-channel
+	object <- as.matrix(object)
+	ncolumns <- ncol(object)
+	if(ncolumns<2) stop("Need at least two columns")
+	column <- as.integer(column[1L])
+	Ave <- rowMeans(object[,-column,drop=FALSE],na.rm=TRUE)
+	y <- object[,column]-Ave
+	x <- (object[,column]+Ave)/2
+
+	plotWithHighlights(x,y,xlab=xlab,ylab=ylab,main=main,status=status, ...)
+}
+
+
+mdplot <- function(x,columns=c(1,2),xlab="Mean",ylab="Difference",main=NULL,...)
+#	Mean-difference plot of two columns of a matrix
+#	Gordon Smyth
+#	16 March 2005. Last modified 13 April 2015.
+{
+	x <- as.matrix(x)
+	columns <- as.integer(columns)[1:2]
+	d <- x[,columns[2]]-x[,columns[1]]
+	m <- (x[,columns[1]]+x[,columns[2]])/2
+	if(is.null(main)) {
+		cn <- colnames(x)[columns]
+		if(is.null(cn)) cn <- paste("Column",columns)
+		main <- paste(cn[2],"vs",cn[1])
+	}
+	plotWithHighlights(x=m,y=d,xlab=xlab,ylab=ylab,main=main,...)
+}
diff --git a/R/plotMDS.R b/R/plotMDS.R
index 9790bad..be94e7d 100644
--- a/R/plotMDS.R
+++ b/R/plotMDS.R
@@ -10,11 +10,11 @@ setMethod("show","MDS",function(object) {
 
 plotMDS <- function(x,...) UseMethod("plotMDS")
 
-plotMDS.MDS <- function(x,labels=NULL,pch=NULL,cex=1,dim.plot=x$dim.plot,xlab=paste("Dimension",dim.plot[1]),ylab=paste("Dimension",dim.plot[2]),...)
+plotMDS.MDS <- function(x,labels=NULL,pch=NULL,cex=1,dim.plot=NULL,xlab=NULL,ylab=NULL,...)
 #	Method for MDS objects
 #	Create a new plot using MDS coordinates or distances previously created
 #	Gordon Smyth and Yifang Hu
-#	21 May 2011.  Last modified 26 June 2014
+#	21 May 2011.  Last modified 29 December 2014
 {
 #	Check labels
 	if(is.null(labels) & is.null(pch)) {
@@ -23,21 +23,31 @@ plotMDS.MDS <- function(x,labels=NULL,pch=NULL,cex=1,dim.plot=x$dim.plot,xlab=pa
 	}
 
 #	Are new dimensions requested?
-	if(!all(dim.plot==x$dim.plot)) {
-		ndim <- max(dim.plot)
-		if(ndim > ncol(x$cmdscale.out)) x$cmdscale.out <- cmdscale(as.dist(x$distance.matrix),k=ndim)
-		x$x <- x$cmdscale.out[,dim.plot[1]]
-		x$y <- x$cmdscale.out[,dim.plot[2]]
+	if(is.null(dim.plot)) {
+		dim.plot <- x$dim.plot
+	} else {
+		if(any(dim.plot != x$dim.plot)) {
+			ndim <- max(dim.plot)
+			if(ndim > ncol(x$cmdscale.out)) x$cmdscale.out <- cmdscale(as.dist(x$distance.matrix),k=ndim)
+			x$x <- x$cmdscale.out[,dim.plot[1]]
+			x$y <- x$cmdscale.out[,dim.plot[2]]
+		}
 	}
 
+#	Axis labels
+	if(is.null(x$axislabel)) x$axislabel <- "Principal Coordinate"
+	if(is.null(xlab)) xlab <- paste(x$axislabel,dim.plot[1])
+	if(is.null(ylab)) ylab <- paste(x$axislabel,dim.plot[2])
+
 #	Make the plot
 	if(is.null(labels)){
 #		Plot symbols instead of text
 		plot(x$x, x$y, pch = pch, xlab = xlab, ylab = ylab, cex = cex, ...)
 	} else {
-#		Plot text.  Need to estimate width of labels in plot coordinates.
-#		Estimate will be ok for default plot width, but maybe too small for smaller plots.
+#		Plot text.
 		labels <- as.character(labels)
+#		Need to estimate width of labels in plot coordinates.
+#		Estimate will be ok for default plot width, but maybe too small for smaller plots.
 		StringRadius <- 0.01*cex*nchar(labels)
 		left.x <- x$x-StringRadius
 		right.x <- x$x+StringRadius
@@ -48,15 +58,15 @@ plotMDS.MDS <- function(x,labels=NULL,pch=NULL,cex=1,dim.plot=x$dim.plot,xlab=pa
 	return(invisible(x))
 }
 
-plotMDS.default <- function(x,top=500,labels=NULL,pch=NULL,cex=1,dim.plot=c(1,2),ndim=max(dim.plot),gene.selection="pairwise",xlab=paste("Dimension",dim.plot[1]),ylab=paste("Dimension",dim.plot[2]),...)
+plotMDS.default <- function(x,top=500,labels=NULL,pch=NULL,cex=1,dim.plot=c(1,2),ndim=max(dim.plot),gene.selection="pairwise",xlab=NULL,ylab=NULL,...)
 #	Multi-dimensional scaling with top-distance
 #	Di Wu and Gordon Smyth
-#	19 March 2009.  Last modified 26 June 2014
+#	19 March 2009.  Last modified 14 Jan 2015
 {
 #	Check x
 	x <- as.matrix(x)
 	nsamples <- ncol(x)
-	if(nsamples < 3) stop("Need at least 3 columns")
+	if(nsamples < 3) stop(paste("Only",nsamples,"columns of data: need at least 3"))
 	cn <- colnames(x)
 #	Remove rows with missing or Inf values
 	bad <- rowSums(is.finite(x)) < nsamples
@@ -73,37 +83,55 @@ plotMDS.default <- function(x,top=500,labels=NULL,pch=NULL,cex=1,dim.plot=c(1,2)
 	}
 	if(!is.null(labels)) labels <- as.character(labels)
 
+#	Check dim.plot
+	dim.plot <- unique(as.integer(dim.plot))
+	if(length(dim.plot) != 2L) stop("dim.plot must specify two dimensions to plot")
+
 #	Check dim
-	if(ndim < 2) stop("Need at least two dim.plot")
-	if(nsamples < ndim) stop("Too few samples")
-	if(nprobes < ndim) stop("Too few rows")
+	if(ndim < 2L) stop("Need at least two dim.plot")
+	if(nsamples < ndim) stop("ndim is greater than number of samples")
+	if(nprobes < ndim) stop("ndim is greater than number of rows of data")
 
 #	Check gene.selection
 	gene.selection <- match.arg(gene.selection,c("pairwise","common"))
 
 #	Distance matrix from pairwise leading fold changes
 	dd <- matrix(0,nrow=nsamples,ncol=nsamples,dimnames=list(cn,cn))
-	topindex <- nprobes-top+1
 	if(gene.selection=="pairwise") {
 #		Distance measure is mean of top squared deviations for each pair of arrays
-		for (i in 2:(nsamples))
-		for (j in 1:(i-1))
+		topindex <- nprobes-top+1L
+		for (i in 2L:(nsamples))
+		for (j in 1L:(i-1L))
 			dd[i,j]=sqrt(mean(sort.int((x[,i]-x[,j])^2,partial=topindex)[topindex:nprobes]))
+		axislabel <- "Leading logFC dim"
 	} else {
 #		Same genes used for all comparisons
-		s <- rowMeans((x-rowMeans(x))^2)
-		q <- quantile(s,p=(topindex-1.5)/(nprobes-1))
-		x <- x[s>=q,]
-		for (i in 2:(nsamples))
-			dd[i,1:(i-1)]=sqrt(colMeans((x[,i]-x[,1:(i-1),drop=FALSE])^2))
+		if(nprobes > top) {
+			s <- rowMeans((x-rowMeans(x))^2)
+			o <- order(s,decreasing=TRUE)
+			x <- x[o[1L:top],,drop=FALSE]
+		}
+		for (i in 2L:(nsamples))
+			dd[i,1L:(i-1L)]=sqrt(colMeans((x[,i]-x[,1:(i-1),drop=FALSE])^2))
+		axislabel <- "Principal Component"
 	}
 
 #	Multi-dimensional scaling
-	a1 <- cmdscale(as.dist(dd),k=ndim)
+	a1 <- suppressWarnings(cmdscale(as.dist(dd),k=ndim))
 
 #	Make MDS object and call plotMDS method
 	mds <- new("MDS",list(dim.plot=dim.plot,distance.matrix=dd,cmdscale.out=a1,top=top,gene.selection=gene.selection))
-	mds$x <- a1[,dim.plot[1]]
-	mds$y <- a1[,dim.plot[2]]
+	if(dim.plot[1] > ncol(a1)) {
+		mds$x <- rep.int(0,nsamples)
+		warning(paste("dimension",dim.plot[1],"is degenerate or all zero"))
+	} else
+		mds$x <- a1[,dim.plot[1]]
+	if(dim.plot[2] > ncol(a1)) {
+		mds$y <- rep.int(0,nsamples)
+		warning(paste("dimension",dim.plot[2],"is degenerate or all zero"))
+	} else
+		mds$y <- a1[,dim.plot[2]]
+	mds$top <- top
+	mds$axislabel <- axislabel
 	plotMDS(mds,labels=labels,pch=pch,cex=cex,xlab=xlab,ylab=ylab,...)
 }
diff --git a/R/plotWithHighlights.R b/R/plotWithHighlights.R
index fa4691c..9ad8a96 100644
--- a/R/plotWithHighlights.R
+++ b/R/plotWithHighlights.R
@@ -1,46 +1,48 @@
-plotWithHighlights <- function(x, y, status=NULL, values=NULL, pch=16, col=NULL, cex=1, legend="topleft", pch.bg=16, col.bg="black", cex.bg=0.3, ...)
+plotWithHighlights <- function(x, y, status=NULL, values=NULL, hl.pch=16, hl.col=NULL, hl.cex=1, legend="topleft", bg.pch=16, bg.col="black", bg.cex=0.3, pch=NULL, col=NULL, cex=NULL, ...)
 #	Scatterplot with color coding for special points
 
-#	Replaces the earlier function .plotMAxy, which in turn was based the original plotMA
+#	Replaces the earlier function .plotMAxy, which in turn was based on the original plotMA
 #	created by Gordon Smyth 7 April 2003 and modified by James Wettenhall 27 June 2003.
 
 #	Gordon Smyth
-#	Last modified 17 April 2014.
+#	Last modified 20 May 2015.
 {
 #	If no status information, just plot all points normally
 	if(is.null(status) || all(is.na(status))) {
-		plot(x,y,pch=pch.bg,col=col.bg,cex=cex.bg,...)
+		plot(x,y,pch=bg.pch,col=bg.col,cex=bg.cex,...)
 		return(invisible())
 	}
 #	From here, status is not NULL and not all NA
 
 #	Check values
 	if(is.null(values)) {
-
-#		Check for values and graphics parameters set as attributes by controlStatus()
-		if(!is.null(attr(status,"values"))) {
-			values <- attr(status,"values")
-			if(!is.null(attr(status,"pch"))) pch <- attr(status,"pch")
-			if(!is.null(attr(status,"col"))) col <- attr(status,"col")
-			if(!is.null(attr(status,"cex"))) cex <- attr(status,"cex")
-		}
-
-#		Default is to set the most frequent status value as background, and to highlight other status values in decreasing order of frequency
-		if(is.null(values)) {
+		if(is.null(attr(status,"values"))) {
+#			Default is to set the most frequent status value as background, and to highlight other status values in decreasing order of frequency
 			status.values <- names(sort(table(status),decreasing=TRUE))
 			status <- as.character(status)
 			values <- status.values[-1]
+		} else {
+#			Use values and graphics parameters set as attributes by controlStatus()
+			values <- attr(status,"values")
+			if(!is.null(attr(status,"pch"))) hl.pch <- attr(status,"pch")
+			if(!is.null(attr(status,"col"))) hl.col <- attr(status,"col")
+			if(!is.null(attr(status,"cex"))) hl.cex <- attr(status,"cex")
 		}
 	}
 
 #	If no values, then just plot all points normally
 	nvalues <- length(values)
 	if(nvalues==0L) {
-		plot(x,y,pch=pch.bg,col=col.bg,cex=cex.bg,...)
+		plot(x,y,pch=bg.pch,col=bg.col,cex=bg.cex,...)
 		return(invisible())
 	}
 #	From here, values has positive length
 
+#	Allow legacy names 'pch', 'col' and 'cex' as alternatives to 'hl.pch', 'hl.col' and 'hl.cex'
+	if(missing(hl.pch) && !is.null(pch)) hl.pch <- pch
+	if(is.null(hl.col) && !is.null(col)) hl.col <- col
+	if(missing(hl.cex) && !is.null(cex)) hl.cex <- cex
+
 #	Setup plot axes
 	plot(x,y,type="n",...)
 
@@ -48,18 +50,18 @@ plotWithHighlights <- function(x, y, status=NULL, values=NULL, pch=16, col=NULL,
 	bg <- !(status %in% values)
 	bg[is.na(bg)] <- TRUE
 	nonhi <- any(bg)
-	if(nonhi) points(x[bg],y[bg],pch=pch.bg[1],col=col.bg[1],cex=cex.bg[1])
+	if(nonhi) points(x[bg],y[bg],pch=bg.pch[1],col=bg.col[1],cex=bg.cex[1])
 
 #	Check graphical parameters for highlighted points
-	pch <- rep_len(unlist(pch),length.out=nvalues)
-	cex <- rep_len(unlist(cex),length.out=nvalues)
-	if(is.null(col)) col <- nonhi + 1L:nvalues
-	col <- rep_len(unlist(col),length.out=nvalues)
+	hl.pch <- rep_len(unlist(hl.pch),length.out=nvalues)
+	hl.cex <- rep_len(unlist(hl.cex),length.out=nvalues)
+	if(is.null(hl.col)) hl.col <- nonhi + 1L:nvalues
+	hl.col <- rep_len(unlist(hl.col),length.out=nvalues)
 
 #	Plot highlighted points
 	for (i in 1:nvalues) {
 		sel <- status==values[i]
-		points(x[sel],y[sel],pch=pch[i],cex=cex[i],col=col[i])
+		points(x[sel],y[sel],pch=hl.pch[i],cex=hl.cex[i],col=hl.col[i])
 	}
 
 #	Check legend
@@ -78,9 +80,13 @@ plotWithHighlights <- function(x, y, status=NULL, values=NULL, pch=16, col=NULL,
 			bg.value <- unique(status[bg])
 			if(length(bg.value) > 1) bg.value <- "Other"
 			values <- c(bg.value,values)
-			pch <- c(pch.bg,pch)
-			col <- c(col.bg,col)
-			cex <- c(cex.bg,cex)
+			pch <- c(bg.pch,hl.pch)
+			col <- c(bg.col,hl.col)
+			cex <- c(bg.cex,hl.cex)
+		} else {
+			pch <- hl.pch
+			col <- hl.col
+			cex <- hl.cex
 		}
 		h <- cex>0.5
 		cex[h] <- 0.5+0.8*(cex[h]-0.5)
diff --git a/R/plotdensities.R b/R/plotdensities.R
index 97bf294..a2ae8ac 100755
--- a/R/plotdensities.R
+++ b/R/plotdensities.R
@@ -6,12 +6,15 @@ UseMethod("plotDensities")
 plotDensities.RGList <- function(object,log=TRUE,group=NULL,col=NULL,main="RG Densities",bc.method="subtract",...)
 #	Plot empirical single-channel densities
 #	Original version by Natalie Thorne, 9 September 2003
-#	Modified by Gordon Smyth.  Last modified 10 Sep 2014.
+#	Modified by Gordon Smyth.  Last modified 13 March 2015.
 {
 	object <- backgroundCorrect(object,method=bc.method)
 	narray <- ncol(object)
 	E <- cbind(object$R,object$G)
 
+#	Add one to prevent taking logs of zero
+#	However this means that plotDensities.RGList and plotDensities.MAList will give slightly
+#	different plots on the same data even when the RG and MA objects represent the same data
 	if(log) E <- log2(E+1)
 
 	col2 <- col
@@ -23,13 +26,13 @@ plotDensities.RGList <- function(object,log=TRUE,group=NULL,col=NULL,main="RG De
 		group2 <- c(group,group)
 	}
 
-	NextMethod(object=E,group=group2,col=col2,main=main,...)
+	plotDensities(object=E,group=group2,col=col2,main=main,...)
 }
 
 plotDensities.MAList <- function(object,log=TRUE,group=NULL,col=NULL,main="RG Densities",...)
 #	Plot empirical single-channel densities
 #	Original version by Natalie Thorne, 9 September 2003
-#	Modified by Gordon Smyth.  Last modified 10 Sep 2014.
+#	Modified by Gordon Smyth.  Last modified 1 March 2015.
 {
 	narray <- ncol(object)
 	E <- cbind(object$A+object$M/2, object$A-object$M/2)
@@ -43,33 +46,33 @@ plotDensities.MAList <- function(object,log=TRUE,group=NULL,col=NULL,main="RG De
 		group <- rep(group,narray)
 		group2 <- c(group,group)
 	}
-
-	NextMethod(object=E,group=group2,col=col2,main=main,...)
+	
+	plotDensities(object=E,group=group2,col=col2,main=main,...)
 }
 
-plotDensities.EListRaw <- function(object,log=TRUE,group=NULL,col=NULL,main=NULL,bc.method="subtract",...)
+plotDensities.EListRaw <- function(object,log=TRUE,bc.method="subtract",...)
 #	Gordon Smyth.
-#	Created 23 March 2009.  Last modified 10 Sep 2014.
+#	Created 23 March 2009.  Last modified 13 March 2015.
 {
 	object <- backgroundCorrect(object,method=bc.method)
 	E <- object$E
 	if(log) E <- log2(E+1)
-	NextMethod(object=E,group=group,col=col,main=main,...)
+	plotDensities(object=E,...)
 }
 
-plotDensities.EList <- function(object,log=TRUE,group=NULL,col=NULL,main=NULL,...)
+plotDensities.EList <- function(object,log=TRUE,...)
 #	Gordon Smyth.
-#	Created 23 March 2009.  Last modified 10 Sep 2014.
+#	Created 23 March 2009.  Last modified 13 March 2015.
 {
 	E <- object$E
 	if(!log) E <- 2^E
-	NextMethod(object=E,group=group,col=col,main=main,...)
+	plotDensities(object=E,...)
 }
 
-plotDensities.default <- function(object,group=NULL,col=NULL,main=NULL,...)
+plotDensities.default <- function(object,group=NULL,col=NULL,main=NULL,legend="topleft",...)
 #	Plot empirical single-channel densities
 #	Gordon Smyth
-#	18 Nov 2013.  Last modified 10 Sep 2014.
+#	18 Nov 2013.  Last modified 13 March 2015.
 {
 #	Coerce object to matrix
 	E <- as.matrix(object)
@@ -85,6 +88,15 @@ plotDensities.default <- function(object,group=NULL,col=NULL,main=NULL,...)
 	if(is.null(col)) col <- 1:ngroup
 	col <- rep(col,length=ngroup)
 
+#	Check legend
+	if(is.logical(legend)) {
+		legend.position <- "topleft"
+	} else {
+		legend.position <- as.character(legend)
+		legend <- TRUE
+	}
+	legend.position <- match.arg(legend.position,c("bottomright","bottom","bottomleft","left","topleft","top","topright","right","center"))
+
 #	Expand cols to number of arrays
 	arraycol <- group
 	levels(arraycol) <- col
@@ -98,6 +110,6 @@ plotDensities.default <- function(object,group=NULL,col=NULL,main=NULL,...)
 		Y[,a] <- d$y
 	}
 	matplot(X,Y,xlab="Intensity",ylab="Density",main=main,type="l",col=arraycol,lwd=2,lty=1)
-	if(ngroup>1) legend("topleft",lwd=2,legend=levels(group),col=col)
+	if(legend && ngroup>1) legend(legend.position,lwd=2,legend=levels(group),col=col)
 	invisible(list(X=X,Y=Y))
 }
diff --git a/R/plots-ma.R b/R/plots-ma.R
index 1ce2b44..02fc6e2 100755
--- a/R/plots-ma.R
+++ b/R/plots-ma.R
@@ -40,6 +40,14 @@ plotMA.MArrayLM <- function(object, coef=ncol(object), xlab="Average log-express
 	plotWithHighlights(x=object$Amean,y=logFC,xlab=xlab,ylab=ylab,main=main,status=status,...)
 }
 
+plotMA.EListRaw <- function(object, array=1, xlab="Average log-expression", ylab="Expression log-ratio (this sample vs others)", main=colnames(object)[array], status=object$genes$Status, zero.weights=FALSE, ...)
+{
+	if(!is.null(object$Eb)) object$E <- object$E-object$Eb
+	object$E <- log2(object$E)
+	object <- new("EList",unclass(object))
+	plotMA(object, array=array, xlab=xlab, ylab=ylab, main=main, status=status, zero.weights=zero.weights, ...)
+}
+
 plotMA.EList <- function(object, array=1, xlab="Average log-expression", ylab="Expression log-ratio (this sample vs others)", main=colnames(object)[array], status=object$genes$Status, zero.weights=FALSE, ...)
 #	MA-plot with color coding for controls
 #	Gordon Smyth 7 April 2003, James Wettenhall 27 June 2003.
@@ -155,13 +163,3 @@ plotPrintTipLoess <- function(object,layout,array=1,span=0.4,...) {
 	df <- data.frame(y=object$M[,array],x=object$A[,array],gr=factor(gridc(layout)),gc=factor(layout$ngrid.r-gridr(layout)+1))
 	coplot(y~x|gr*gc,data=na.omit(df),xlab=c("A","Tip Column"),ylab=c("M","Tip Row"),pch=".",span=span,show.given=FALSE,panel=panel.smooth)
 }
-
-mdplot <- function(x,xlab="Mean",ylab="Difference",...)
-#	Mean-difference plot
-#	Gordon Smyth
-#	16 March 2005. Last modified 30 Sep 2014.
-{
-	d <- x[,1]-x[,2]
-	m <- (x[,1]+x[,2])/2
-	plotWithHighlights(x=m,y=d,xlab=xlab,ylab=ylab,...)
-}
diff --git a/R/predFCm.R b/R/predFCm.R
index e2fe0c1..ab45444 100644
--- a/R/predFCm.R
+++ b/R/predFCm.R
@@ -1,43 +1,51 @@
-predFCm <- function(fit,coef=2,prob=TRUE,VarRel=NULL)
-# Belinda Phipson 29 May 2012. Updated 8 January 2013.
+predFCm <- function(fit,coef=2, var.indep.of.fc=TRUE, all.de=TRUE, prop.true.null.method="lfdr")
+#	Predictive (empirical Bayes shrunk) fold changes
+#	Belinda Phipson and Gordon Smyth
+#	Created 29 May 2012. Last modified 1 December 2014.
 {
- p <- 1-propTrueNull(fit$p.value[,coef],method="lfdr")
- if(p==0) p<-1e-8
- if(length(fit$s2.prior)==1) trend<-FALSE else trend<-TRUE
- fit <- eBayes(fit,proportion = p,trend=trend)
- v <- fit$cov.coefficients[coef,coef]
+#	Check fit
+	if(!is(fit,"MArrayLM")) stop("fit must be a MArrayLM fit object")
+	if(is.null(fit$p.value)) fit <- eBayes(fit)
 
- if(is.null(VarRel)) VarRel <- "Independent"
+#	Check coef
+	coef <- coef[1]
 
- if(VarRel=="Independent"){
-	v0 <- fitGammaIntercept(fit$coeff[,coef]^2,offset=v*fit$s2.post)
-	if(v0<0) v0<-1e-8
-	pfc <- fit$coeff[,coef]*v0/(v0+v*fit$s2.post)
-	if(prob){
-		A <- p/(1-p)
-		B <- (v*fit$s2.post/(v*fit$s2.post+v0))^0.5
-		C <- exp(fit$coeff[,coef]^2*v0/(2*v^2*fit$s2.post^2+2*v*v0*fit$s2.post))
-		lods <- log(A*B*C)
-		probDE <- exp(lods)/(1+exp(lods))
-		probDE[lods>700] <- 1
-		pfc <- pfc*probDE
+#	Estimate proportion of true nulls and re-run eBayes
+	p <- 1-propTrueNull(fit$p.value[,coef], method=prop.true.null.method)
+	if(p==0) p <- 1e-8
+	if(length(fit$s2.prior)==1L) trend <- FALSE else trend <- TRUE
+	if(length(fit$df.prior)==1L) robust <- FALSE else robust <- TRUE
+	fit <- eBayes(fit,proportion=p,trend=trend,robust=robust)
+	v <- fit$cov.coefficients[coef,coef]
+
+	if(var.indep.of.fc){
+		v0 <- fitGammaIntercept(fit$coeff[,coef]^2, offset=v*fit$s2.post)
+		if(v0<0) v0<-1e-8
+		pfc <- fit$coeff[,coef]*v0/(v0+v*fit$s2.post)
+		if(!all.de) {
+			A <- p/(1-p)
+			B <- (v*fit$s2.post/(v*fit$s2.post+v0))^0.5
+			C <- exp(fit$coeff[,coef]^2*v0/(2*v^2*fit$s2.post^2+2*v*v0*fit$s2.post))
+			lods <- log(A*B*C)
+			probDE <- exp(lods)/(1+exp(lods))
+			probDE[lods>700] <- 1
+			pfc <- pfc*probDE
 		}
-	}
- else if(VarRel=="Increasing"){
-	b2 <- fit$coeff[,coef]^2/fit$s2.post
-        v0 <- fitGammaIntercept(b2,offset=v)
-	if(v0<0) v0<-1e-8
-	pfc <- fit$coeff[,coef]*v0/(v0+v)
-	if(prob){
-		A <- p/(1-p)
-		B <- (v/(v+v0))^0.5
-		C <- exp(fit$coeff[,coef]^2*v0/(2*v^2*fit$s2.post+2*v*v0*fit$s2.post))
-		lods <- log(A*B*C)
-		probDE <- exp(lods)/(1+exp(lods))
-		probDE[lods>700] <- 1
-		pfc <- pfc*probDE
+	} else {
+		if(is.null(fit$s2.post)) fit <- eBayes(fit)
+		b2 <- fit$coeff[,coef]^2 / fit$s2.post
+		v0 <- fitGammaIntercept(b2, offset=v)
+		v0 <- pmin(v0, 1e-8)
+		pfc <- fit$coeff[,coef] * v0/(v0+v)
+		if(!all.de) {
+			A <- p/(1-p)
+			B <- (v/(v+v0))^0.5
+			C <- exp(fit$coeff[,coef]^2*v0/(2*v^2*fit$s2.post+2*v*v0*fit$s2.post))
+			lods <- log(A*B*C)
+			probDE <- exp(lods)/(1+exp(lods))
+			probDE[lods>700] <- 1
+			pfc <- pfc*probDE
 		}
 	}
- else stop("Invalid VarRel, please select either Independent or Increasing")
- pfc
+	pfc
 }
diff --git a/R/read.idat.R b/R/read.idat.R
index 9145b21..8e040b5 100644
--- a/R/read.idat.R
+++ b/R/read.idat.R
@@ -1,10 +1,11 @@
-read.idat <- function(idatfiles, bgxfile, dateinfo=FALSE)
-# Function to read idat data from gene expression BeadArrays
-# Matt Ritchie, 30 September 2013
+read.idat <- function(idatfiles, bgxfile, dateinfo=FALSE, tolerance=0)
+# Read idat data from gene expression BeadChips
+# Matt Ritchie
+# Created 30 September 2013. Modified on 14 January 2015 and 26 June 2015.
 {
-  require(illuminaio)
+  if(!requireNamespace("illuminaio",quietly=TRUE)) stop("illuminaio package required but is not available")
   cat("Reading manifest file", bgxfile, "... ")
-  bgx <- readBGX(bgxfile)
+  bgx <- illuminaio::readBGX(bgxfile)
   cat("Done\n")
   nregprobes <-nrow(bgx$probes)
   nctrlprobes <-nrow(bgx$control)
@@ -23,14 +24,15 @@ read.idat <- function(idatfiles, bgxfile, dateinfo=FALSE)
   rm(tmp)
   for(i in 1:nsamples) {
     cat("\t", idatfiles[i], "... ")
-    tmp <- readIDAT(idatfiles[i])
+    tmp <- illuminaio::readIDAT(idatfiles[i])
     cat("Done\n")
     ind <- match(elist$genes[,"Array_Address_Id"], tmp$Quants[,'IllumicodeBinData'])
-    if(sum(is.na(ind))>0)
-      stop("Can't match ids in manifest with those in idat file", idatfiles[i], "- please check that you have the right files\n")
-    elist$E[,i] <- round(tmp$Quants[ind,'MeanBinData'],1) # intensity data
-    elist$other$STDEV[,i] <- tmp$Quants[ind,'DevBinData'] # Bead STDEV
-    elist$other$NumBeads[,i] <- tmp$Quants[ind,'NumGoodBeadsBinData'] # NumBeads
+    if(sum(is.na(ind))>tolerance)
+      stop("Can't match all ids in manifest with those in idat file ", idatfiles[i], "\n", sum(is.na(ind)), 
+            " missing - please check that you have the right files, or consider setting \'tolerance\'=", sum(is.na(ind)))
+    elist$E[!is.na(ind),i] <- round(tmp$Quants[ind[!is.na(ind)],'MeanBinData'],1) # intensity data
+    elist$other$STDEV[!is.na(ind),i] <- tmp$Quants[ind[!is.na(ind)],'DevBinData'] # Bead STDEV
+    elist$other$NumBeads[!is.na(ind),i] <- tmp$Quants[ind[!is.na(ind)],'NumGoodBeadsBinData'] # NumBeads
     if(dateinfo) {
       elist$targets[i,"DecodeInfo"] = paste(tmp$RunInfo[1,], sep="", collapse=" ")
       elist$targets[i,"ScanInfo"] = paste(tmp$RunInfo[2,], sep="", collapse=" ")
diff --git a/R/roc.R b/R/roc.R
deleted file mode 100755
index 0cee6d8..0000000
--- a/R/roc.R
+++ /dev/null
@@ -1,20 +0,0 @@
-#  ROC.R
-
-auROC <- function(truth, stat=NULL) {
-#	Area under Receiver Operating Curve for empirical data
-#	Gordon Smyth
-#	21 Dec 2003. Last modified 4 Dec 2009.
-
-	if(!length(truth)) return(NULL)
-	truth <- as.numeric(as.logical(truth))
-	if(!is.null(stat)) {
-		if(length(stat) != length(truth)) stop("lengths differ")
-		truth[is.na(stat)] <- NA
-		truth <- truth[order(stat,decreasing=TRUE)]
-	}
-	isna <- is.na(truth)
-	if(any(isna)) truth <- truth[!isna]
-	sens <- cumsum(truth)/sum(truth)
-	mean(sens[truth==0])
-}
-
diff --git a/R/sepchannel.R b/R/sepchannel.R
index bf3f27a..30fc95d 100755
--- a/R/sepchannel.R
+++ b/R/sepchannel.R
@@ -56,7 +56,7 @@ lmscFit <- function(object,design,correlation)
 intraspotCorrelation <- function(object,design,trim=0.15)
 #	Estimate intra-spot correlation between channels for two channel data
 #	Gordon Smyth
-#	19 April 2004.  Last modified 13 Nov 2005.
+#	19 April 2004.  Last modified 14 Dec 2015.
 {
 #	Check input
 	M <- as.matrix(object$M)
@@ -79,12 +79,12 @@ intraspotCorrelation <- function(object,design,trim=0.15)
 	designA <- (Ident %x% matrix(c(0.5,0.5),1,2)) %*% design
 	X <- rbind(designM, designA)
 	Z <- diag(2) %x% rep(1,narrays)
-	if(!require(statmod)) stop("statmod package required but is not available")
+	if(!requireNamespace("statmod",quietly=TRUE)) stop("statmod package required but is not available")
 	arho <- rep(NA,ngenes)
 	degfre <- matrix(0,ngenes,2,dimnames=list(rownames(M),c("df.M","df.A")))
 	for (i in 1:ngenes) {
 		y <- c(M[i,],A[i,])
-		fit <- try(remlscore(y,X,Z),silent=TRUE)
+		fit <- try(statmod::remlscore(y,X,Z),silent=TRUE)
 		if(is.list(fit)) {
 			arho[i] <- 0.5*(fit$gamma[2]-fit$gamma[1])
 			degfre[i,] <- crossprod(Z,1-fit$h)
diff --git a/R/squeezeVar.R b/R/squeezeVar.R
index fc76f41..387d962 100644
--- a/R/squeezeVar.R
+++ b/R/squeezeVar.R
@@ -107,8 +107,8 @@ fitFDist <- function(x,df1,covariate=NULL)
 		emean <- mean(e)
 		evar <- sum((e-emean)^2)/(n-1)
 	} else {
-		require(splines)
-		design <- try(ns(covariate,df=splinedf,intercept=TRUE),silent=TRUE)
+		if(!requireNamespace("splines",quietly=TRUE)) stop("splines package required but is not available")
+		design <- try(splines::ns(covariate,df=splinedf,intercept=TRUE),silent=TRUE)
 		if(is(design,"try-error")) stop("Problem with covariate")
 		fit <- lm.fit(design,e)
 		if(notallok) {
diff --git a/R/toptable.R b/R/toptable.R
index b87e637..611c58b 100644
--- a/R/toptable.R
+++ b/R/toptable.R
@@ -3,10 +3,11 @@
 topTable <- function(fit,coef=NULL,number=10,genelist=fit$genes,adjust.method="BH",sort.by="B",resort.by=NULL,p.value=1,lfc=0,confint=FALSE)
 #	Summary table of top genes, object-orientated version
 #	Gordon Smyth
-#	4 August 2003.  Last modified 27 February 2014.
+#	4 August 2003.  Last modified 10 April 2015.
 {
 #	Check fit
 	if(!is(fit,"MArrayLM")) stop("fit must be an MArrayLM object")
+	if(is.null(fit$t) && is.null(fit$F)) stop("Need to run eBayes or treat first")
 	if(is.null(fit$coefficients)) stop("coefficients not found in fit object")
 	if(confint && is.null(fit$stdev.unscaled)) stop("stdev.unscaled not found in fit object")
 
diff --git a/R/venn.R b/R/venn.R
index d8c42d9..c57ce36 100755
--- a/R/venn.R
+++ b/R/venn.R
@@ -32,7 +32,7 @@ vennDiagram <- function(object,include="both",names=NULL,mar=rep(1,4),cex=c(1.5,
 #	Plot Venn diagram
 #	Gordon Smyth, James Wettenhall, Yifang Hu.
 #	Capabilities for multiple counts and colors uses code by Francois Pepin.
-#	4 July 2003.  Last modified 31 January 2014.
+#	4 July 2003.  Last modified 31 October 2014.
 {
 #	Check include
 	include <- as.character(include)
@@ -60,7 +60,11 @@ vennDiagram <- function(object,include="both",names=NULL,mar=rep(1,4),cex=c(1.5,
 	if(is.null(names)) names <- colnames(object)[1:nsets]
 
 #	Set colors
-	if(is.null(circle.col)) circle.col <- par('col')
+	FILL.COL <- TRUE
+	if(is.null(circle.col)) { 
+		circle.col <- par('col')
+		FILL.COL <- FALSE
+	}
 	if(length(circle.col)<nsets) circle.col <- rep(circle.col,length.out=nsets)
 	if(is.null(counts.col)) counts.col <- par('col')
 	if(length(counts.col)<LenInc) counts.col <- rep(counts.col,length.out=LenInc)
@@ -91,8 +95,17 @@ vennDiagram <- function(object,include="both",names=NULL,mar=rep(1,4),cex=c(1.5,
 	ytext <- switch(nsets, 1.8, c(1.8,1.8), c(2.4,2.4,-3) )
 #	Note that lines() better than symbols() to make circles follow aspect ratio of plot
 	for(circle in 1:nsets) {
-		lines(xcentres[circle]+r*cos(theta),ycentres[circle]+r*sin(theta),lwd=lwd,col=circle.col[circle])
+
+		if(!FILL.COL) lines(xcentres[circle]+r*cos(theta),ycentres[circle]+r*sin(theta),lwd=lwd,col=circle.col[circle])
+		if(FILL.COL) {
+			RGB <- col2rgb(circle.col[circle])/255
+			ALPHA <- 0.06
+			RGB.ALP <- rgb(RGB[1, 1], RGB[2, 1], RGB[3, 1], alpha = ALPHA)
+			polygon(xcentres[circle]+r*cos(theta),ycentres[circle]+r*sin(theta),border=circle.col[circle],lwd=lwd,col=RGB.ALP)
+		}
+
 		text(xtext[circle],ytext[circle],names[circle],cex=cex)
+
 	}
 
 #	Plot rectangles
@@ -160,10 +173,25 @@ vennDiagram <- function(object,include="both",names=NULL,mar=rep(1,4),cex=c(1.5,
    if (4 == nsets) {
 		rect(-20, -20, 420, 400)
 		elps <- cbind(162*cos(seq(0,2*pi,len=1000)), 108*sin(seq(0,2*pi,len=1000)))
-		polygon(relocate_elp(elps,  45, 130, 170),border=circle.col[1],lwd=lwd)
-		polygon(relocate_elp(elps,  45, 200, 200),border=circle.col[2],lwd=lwd)
-		polygon(relocate_elp(elps, 135, 200, 200),border=circle.col[3],lwd=lwd)
-		polygon(relocate_elp(elps, 135, 270, 170),border=circle.col[4],lwd=lwd)
+
+		if(!FILL.COL){
+			polygon(relocate_elp(elps,  45, 130, 170),border=circle.col[1],lwd=lwd)
+			polygon(relocate_elp(elps,  45, 200, 200),border=circle.col[2],lwd=lwd)
+			polygon(relocate_elp(elps, 135, 200, 200),border=circle.col[3],lwd=lwd)
+			polygon(relocate_elp(elps, 135, 270, 170),border=circle.col[4],lwd=lwd)
+		}
+		if(FILL.COL){
+			RGB <- col2rgb(circle.col)/255
+			ALPHA <- 0.06
+			RGB.ALP1 <- rgb(RGB[1, 1], RGB[2, 1], RGB[3, 1], alpha = ALPHA)
+			RGB.ALP2 <- rgb(RGB[1, 2], RGB[2, 2], RGB[3, 2], alpha = ALPHA)
+			RGB.ALP3 <- rgb(RGB[1, 3], RGB[2, 3], RGB[3, 3], alpha = ALPHA)
+			RGB.ALP4 <- rgb(RGB[1, 4], RGB[2, 4], RGB[3, 4], alpha = ALPHA)
+			polygon(relocate_elp(elps,  45, 130, 170),border=circle.col[1],lwd=lwd,col=RGB.ALP1)
+			polygon(relocate_elp(elps,  45, 200, 200),border=circle.col[2],lwd=lwd,col=RGB.ALP2)
+			polygon(relocate_elp(elps, 135, 200, 200),border=circle.col[3],lwd=lwd,col=RGB.ALP3)
+			polygon(relocate_elp(elps, 135, 270, 170),border=circle.col[4],lwd=lwd,col=RGB.ALP4)
+		}
 
 		text( 35, 315, names[1], cex=cex[1])
 		text(138, 350, names[2], cex=cex[1])
@@ -220,11 +248,28 @@ vennDiagram <- function(object,include="both",names=NULL,mar=rep(1,4),cex=c(1.5,
 	rect(-20, -30, 430, 430)
 
 	elps <- cbind(150*cos(seq(0,2*pi,len=1000)), 60*sin(seq(0,2*pi,len=1000)))
-	polygon(relocate_elp(elps,  90,200, 250),border=circle.col[1],lwd=lwd)
-	polygon(relocate_elp(elps, 162,250, 220),border=circle.col[2],lwd=lwd)
-	polygon(relocate_elp(elps, 234,250, 150),border=circle.col[3],lwd=lwd)
-	polygon(relocate_elp(elps, 306,180, 125),border=circle.col[4],lwd=lwd)
-	polygon(relocate_elp(elps, 378,145, 200),border=circle.col[5],lwd=lwd)
+
+	if(!FILL.COL){
+		polygon(relocate_elp(elps,  90,200, 250),border=circle.col[1],lwd=lwd)
+		polygon(relocate_elp(elps, 162,250, 220),border=circle.col[2],lwd=lwd)
+		polygon(relocate_elp(elps, 234,250, 150),border=circle.col[3],lwd=lwd)
+		polygon(relocate_elp(elps, 306,180, 125),border=circle.col[4],lwd=lwd)
+		polygon(relocate_elp(elps, 378,145, 200),border=circle.col[5],lwd=lwd)
+	}
+	if(FILL.COL){
+		RGB <- col2rgb(circle.col)/255
+		ALPHA <- 0.06
+		RGB.ALP1 <- rgb(RGB[1, 1], RGB[2, 1], RGB[3, 1], alpha = ALPHA)
+		RGB.ALP2 <- rgb(RGB[1, 2], RGB[2, 2], RGB[3, 2], alpha = ALPHA)
+		RGB.ALP3 <- rgb(RGB[1, 3], RGB[2, 3], RGB[3, 3], alpha = ALPHA)
+		RGB.ALP4 <- rgb(RGB[1, 4], RGB[2, 4], RGB[3, 4], alpha = ALPHA)
+		RGB.ALP5 <- rgb(RGB[1, 5], RGB[2, 5], RGB[3, 5], alpha = ALPHA)
+		polygon(relocate_elp(elps,  90,200, 250),border=circle.col[1],lwd=lwd,col=RGB.ALP1)
+		polygon(relocate_elp(elps, 162,250, 220),border=circle.col[2],lwd=lwd,col=RGB.ALP2)
+		polygon(relocate_elp(elps, 234,250, 150),border=circle.col[3],lwd=lwd,col=RGB.ALP3)
+		polygon(relocate_elp(elps, 306,180, 125),border=circle.col[4],lwd=lwd,col=RGB.ALP4)
+		polygon(relocate_elp(elps, 378,145, 200),border=circle.col[5],lwd=lwd,col=RGB.ALP5)
+	}
 
 	text( 50, 285, names[1],cex=cex[1])
 	text(200, 415, names[2],cex=cex[1])
@@ -233,7 +278,7 @@ vennDiagram <- function(object,include="both",names=NULL,mar=rep(1,4),cex=c(1.5,
 	text(100, -10, names[5],cex=cex[1])
 
 	text( 61, 231, z["10000"], cex=cex[2], col=counts.col[1])
-	text(194, 332, z["01000"], cex=cex[2], col=counts.col[1])
+	text(200, 332, z["01000"], cex=cex[2], col=counts.col[1])
 	text(321, 248, z["00100"], cex=cex[2], col=counts.col[1])
 	text(290,  84, z["00010"], cex=cex[2], col=counts.col[1])
 	text(132,  72, z["00001"], cex=cex[2], col=counts.col[1])
@@ -267,7 +312,7 @@ vennDiagram <- function(object,include="both",names=NULL,mar=rep(1,4),cex=c(1.5,
 
 	if(length(include)==2) {
 		text( 61, 220, z2["10000"], cex=cex[2], col=counts.col[2])
-		text(194, 321, z2["01000"], cex=cex[2], col=counts.col[2])
+		text(200, 321, z2["01000"], cex=cex[2], col=counts.col[2])
 		text(321, 237, z2["00100"], cex=cex[2], col=counts.col[2])
 		text(290,  73, z2["00010"], cex=cex[2], col=counts.col[2])
 		text(132,  61, z2["00001"], cex=cex[2], col=counts.col[2])
diff --git a/R/voom.R b/R/voom.R
index 9cf34cc..fd2674b 100644
--- a/R/voom.R
+++ b/R/voom.R
@@ -16,9 +16,9 @@ voom <- function(counts,design=NULL,lib.size=NULL,normalize.method="none",plot=F
 	} else {
 		isExpressionSet <- suppressPackageStartupMessages(is(counts,"ExpressionSet"))
 		if(isExpressionSet) {
-			if(length(fData(counts))) out$genes <- fData(counts)
-			if(length(pData(counts))) out$targets <- pData(counts)
-			counts <- exprs(counts)
+			if(length(Biobase::fData(counts))) out$genes <- Biobase::fData(counts)
+			if(length(Biobase::pData(counts))) out$targets <- Biobase::pData(counts)
+			counts <- Biobase::exprs(counts)
 		} else {
 			counts <- as.matrix(counts)
 		}
diff --git a/R/write.R b/R/write.R
index 4404339..671cdcc 100755
--- a/R/write.R
+++ b/R/write.R
@@ -3,7 +3,7 @@
 write.fit <- function(fit, results=NULL, file, digits=3, adjust="none", method="separate", F.adjust="none", sep="\t", ...) {
 #	Write an MArrayLM fit to a file
 #	Gordon Smyth
-#	14 Nov 2003.  Last modified 16 June 2008.
+#	14 Nov 2003.  Last modified 9 June 2015.
 
 	if(!is(fit, "MArrayLM")) stop("fit should be an MArrayLM object")
 	if(!is.null(results) && !is(results,"TestResults")) stop("results should be a TestResults object")
@@ -16,19 +16,20 @@ write.fit <- function(fit, results=NULL, file, digits=3, adjust="none", method="
 	} else {
 		p.value.adj <- p.value
 		if(method=="separate") for (j in 1:ncol(p.value)) p.value.adj[,j] <- p.adjust(p.value[,j],method=adjust)
-		if(method=="global") p.value.adj <- p.adjust(p.value,method=adjust)
+		if(method=="global") p.value.adj[] <- p.adjust(p.value,method=adjust)
 	}
 	if(F.adjust=="none" || is.null(fit$F.p.value))
 		F.p.value.adj <- NULL
 	else
 		F.p.value.adj <- p.adjust(fit$F.p.value,method=F.adjust)
 
-	rn <- function(x,digits=digits) if(is.null(x))
-		NULL
-	else {
-		if(is.matrix(x) && ncol(x)==1) x <- x[,1]
-		round(x,digits=digits)
-	}
+	rn <- function(x,digits=digits)
+			if(is.null(x))
+				NULL
+			else {
+				if(is.matrix(x) && ncol(x)==1) x <- x[,1]
+				round(x,digits=digits)
+			}
 	tab <- list()
 	tab$A <- rn(fit$Amean,digits=digits-1)
 	tab$Coef <- rn(fit$coef,digits=digits)
diff --git a/build/vignette.rds b/build/vignette.rds
index ed236c7..fe28f8c 100644
Binary files a/build/vignette.rds and b/build/vignette.rds differ
diff --git a/inst/CITATION b/inst/CITATION
index 807b436..5b522a0 100755
--- a/inst/CITATION
+++ b/inst/CITATION
@@ -1,15 +1,20 @@
 citHeader("Please cite the paper below for the limma software itself.  Please also try to cite the appropriate methodology articles that describe the statistical methods implemented in limma, depending on which limma functions you are using.  The methodology articles are listed in Section 2.1 of the limma User's Guide.")
 
-citEntry(entry="incollection",
-	title = "Limma: linear models for microarray data",
-	author = "Gordon K Smyth",
-	booktitle="Bioinformatics and Computational Biology Solutions Using {R} and Bioconductor",
-	editor="R. Gentleman and V. Carey and S. Dudoit and R. Irizarry, W. Huber",
-	publisher="Springer",
-	address="New York",
-	year = 2005,
-	pages = "397--420",
+citEntry(entry="article",
+	author = c(person(c("Matthew","E"),"Ritchie"),
+	           person("Belinda","Phipson"),
+	           person("Di","Wu"),
+	           person("Yifang","Hu"),
+	           person(c("Charity","W"),"Law"),
+	           person("Wei","Shi"),
+	           person(c("Gordon","K"),"Smyth")),
+	title = "{limma} powers differential expression analyses for {RNA}-sequencing and microarray studies",
+	journal = "Nucleic Acids Research",
+	year = 2015,
+	volume = 43,
+	number = 7,
+	pages = "e47",
 
 	textVersion = 
-	"Smyth, GK (2005). Limma: linear models for microarray data. In: 'Bioinformatics and Computational Biology Solutions using R and Bioconductor'. R. Gentleman, V. Carey, S. Dudoit, R. Irizarry, W. Huber (eds), Springer, New York, pages 397-420."
+	"Ritchie, M.E., Phipson, B., Wu, D., Hu, Y., Law, C.W., Shi, W., and Smyth, G.K. (2015). limma powers differential expression analyses for RNA-sequencing and microarray studies. Nucleic Acids Research 43(7), e47."
 )
diff --git a/inst/NEWS.Rd b/inst/NEWS.Rd
index d352e7c..01e131c 100644
--- a/inst/NEWS.Rd
+++ b/inst/NEWS.Rd
@@ -2,6 +2,119 @@
 \title{limma News}
 \encoding{UTF-8}
 
+\section{Version 3.24.0}{\itemize{
+\item
+Limma review article (Ritchie et al, Nucleic Acids Research, 2015) is now published, and becomes the primary citation for limma.
+References in User's Guide, help files and CITATION have been updated to refer to this article.
+
+\item
+New function plotMD() for mean-difference plots.  This will take
+  over the functionality of the plotMA() function.
+
+\item
+mdplot() has new arguments 'columns' and 'main'.
+
+\item
+Arguments 'pch', 'cex' and 'col' of plotWithHighlights() renamed to
+  'hi.pch', 'hi.cex' and 'hi.col'.  Improved help page for
+  plotWithHighlights().
+
+\item
+plot() methods removed for EList, MAList and MArrayLM objects.  Use plotMD() instead.
+
+\item
+New function fry() provides a fast version of mroast()
+  when there is little heteroscedasticity between genes.
+
+\item 
+Minor change to mroast() output so that FDR values are never
+  smaller than p-values, even when mid-p-values are used.
+ 
+\item
+camera(), roast(), mroast() and romer() now give a warning if
+  any arguments found in ... are not used.
+
+\item
+romer() is now an S3 generic function.
+Speed improvements for romer() when the "mean" or "floormean" set
+  statistics are used.
+
+\item
+topGO() can now sort gene ontology results by several p-value
+  columns at once, using the minimum of the columns.  The default is
+  now to sort results using all the p-value columns found in the
+  results instead of just by the first column.
+
+\item
+goana() has new arguments 'plot' and 'covariate'.
+The plot argument allows users to view any estimated trend in the genewise significance values.
+The help files goana.Rd and goana.MArrayLM.Rd are consolidated into one file.
+
+\item
+plotDensities() has a new argument 'legend', allowing user to
+  reposition the legend.
+
+\item
+voomWithQualityWeights() has a new argument 'col', allowing the barplot of 
+  sample weights to be colour-coded.
+
+\item
+Improvements and bug fixes to plotMDS().
+plotMDS now stores 'axislabel', depending on the method used to
+  compute distances, and uses this to make more informative axis labels.
+plotMDS now traps problems when the distances are all zero or if
+  one or more of the dimensions are degenerate.
+Also, a bug when gene.selection="common" and top=nrow(x) has been fixed.
+
+\item
+The arguments for predFCm() have been renamed.  Old argument
+  'VarRel' replaced by logical argument 'var.indep.of.fc'.  Old
+  argument 'prop' replaced by 'all.de'.  New argument
+  'prop.true.null.method' passes through method to propTrueNull().
+
+\item
+vennDiagram() now fills circles with specified colors.
+
+\item
+plotMA() now has a method for EListRaw objects.
+
+\item
+voomWithQualityWeights() now stores the sample weights in the output EList object.
+  The values stored in $weights are unchanged, they are still the combined 
+  observation and sample weights.
+
+\item
+nec() and neqc() now remove the background Eb values if they exist in the
+  EListRaw object.
+
+\item
+Acknowledgements edited in User's Guide.
+
+\item
+fix URLs for a number of references in help pages.
+
+\item
+Improvements to lowess C code.
+
+\item
+When loading suggested packages within function calls, usages of
+  require() have been converted to requireNamespace() wherever
+  possible.  Functions from suggested packages are called using `::'.
+
+\item
+topTable() now gives an information error message if eBayes() or
+  treat() have not already been run on the fitted model object.
+
+\item
+genas() now gives an error message when applied to fitted model for
+  which the coefficient correlations are gene-specific.
+
+\item
+Fix a bug in the MAList method for plotDensities that was introduced with
+  the use of NextMethod() in version 3.21.16.
+}}
+
+
 \section{Version 3.22.0}{\itemize{
 \item
 New functions goana() and topGO() provide gene ontology analyses of differentially genes from a linear model fit.
diff --git a/inst/doc/changelog.txt b/inst/doc/changelog.txt
index 7de2b0c..9ff73af 100755
--- a/inst/doc/changelog.txt
+++ b/inst/doc/changelog.txt
@@ -1,13 +1,254 @@
-20 Oct 2014: limma 3.22.1
+ 7 July 2015: limma 3.24.13
+
+- New 'tolerance' argument for read.idat() to allow manifest and idat
+  to differ by a certain number of probes
+
+- A minor change for when lmFit() is run on a single gene: a simple
+  vector data 'object' is now coerced to a matrix with one row
+  instead of one column  
+
+26 June 2015: limma 3.24.12
+
+- lmFit() and friends now always produce an output component 'rank'
+  that returns the column rank of the design matrix.  Previously it
+  depended on the options used whether this component was given.
+
+23 June 2015: limma 3.24.11
+
+- camera(), fry(), mroast() and romer() now give a more informative
+  error message when the index list is empty.
+
+- camera() no longer gives NA results when a gene has a residual
+  variance exactly zero.
+
+ 9 June 2015: limma 3.24.10
+
+- bug fix to write.fit() when method="global" and fit contains more
+  than one column.
+
+ 8 June 2015: limma 3.24.9
+
+- plotMD() can now accept arguments 'array' or 'coef' as appropriate
+  as synonyms for 'column'.  This may help users transitioning from
+  plotMA ot plotMD.
+
+ 7 June 2015: limma 3.24.8
+
+- Improved power for the romer() function.  The empirical Bayes
+  shrinkage of the residuals, removed on 4 April, has been
+  re-instated in a corrected form.  It can optionally be turned off
+  using the 'shrink.resid' argument.
+
+ 5 June 2015: limma 3.24.7
+
+- The dimnames<- method for EListRaw objects now sets rownames for
+  the background matrix Eb as well as for the foreground matrix E.
+
+ 3 June 2015: limma 3.24.6
+
+- new function kegga() to conduct KEGG pathway over-representation
+  analyses.  kegga() is an S3 generic function with a method for
+  MArrayLM fitted model objects.
+
+20 May 2015: limma 3.24.5
+
+- bug fix for plotWithHighlights(). Legend was not displaying
+  correctly when there were no background points.
+
+13 May 2015: limma 3.24.4
+
+- goana() with trend now chooses the span of the tricube smoother
+  based on the number of differentially expressed genes.  Larger
+  spans give smoother trends and are used for smaller numbers of
+  genes.  Arguments 'species' and 'plot' are no longer part of
+  goana.MArrayLM() and are instead passed to goana.default().
+
+- speedup for ids2indices().
+
+- bug fix to plotMD.RGList.
+
+28 April 2015: limma 3.24.3
+
+- arguments hi.pch, hi.col and hi.cex of plotWithHighlights() renamed
+  to hl.pch, hl.col and hl.cex.  ('hl' is short for 'highlight'.)
+
+- fix bug in auROC() introduced in 3.25.2.
+
+25 April 2015: limma 3.24.2
+
+- auROC() now allows for tied stat values.
+
+22 April 2015: limma 3.24.1
+
+- Update citation for the limma review article (Ritchie et al,
+  NAR 2015).
+
+- Update Liu et al reference for voomWithQualityWeights().
+
+- topGO() has a new argument 'truncate.term' to limit number of
+  characters appearing in a column.
+
+17 April 2015: limma 3.24.0 (Bioconductor 3.1 Release Branch)
+
+14 April 2015: limma 3.23.17
+
+- adding back legacy arguments 'pch', 'col' and 'cex' as alternative
+  arguments for plotWithHighlights() to ensure background
+  compatibility.
+
+- edit help pages for plotMD, plotMA and plotWithHighlights.
+
+13 April 2015: limma 3.23.16
+
+- add note to help page for genas() explaining it is not yet
+  implemented for use with observation weights.
+
+13 April 2015: limma 3.23.15
+
+- update User's Guide.
+
+- fix bug in plotWithHighlights() introduced in previous version.
+
+13 April 2015: limma 3.23.14
+
+- new function plotMD() for mean-difference plots.  This will take
+  over functionality of plotMA() function.
+
+- mdplot() has new arguments 'columns' and 'main'.
+
+- arguments 'pch', 'col' and 'cex' of plotWithHighlights() renamed to
+  'hi.pch', 'hi.col' and 'hi.cex'.  Improved help page for
+  plotWithHighlights().
+
+- plot() methods removed for EList, MAList and MArrayLM objects.
+  Use plotMD() instead.
+
+- genas() now gives an error message when applied to fitted model for
+  which the coefficient correlations are gene-specific.
+
+- topTable() now gives an information error message if eBayes() or
+  treat() have not already been run on the fitted model object.
+
+- NEWS.Rd updated for imminent Bioconductor 3.1 release.
+
+8 April 2015: limma 3.23.13
+
+- new function fry(), which provides a fast version of mroast()
+  when there is little heteroscedasticity between genes.
+ 
+- minor change to mroast() output so that FDR values are never
+  smaller than p-values when midp=TRUE.
+ 
+ 4 April 2015: limma 3.23.12
+
+- camera(), roast(), mroast() and romer() now give a warning if
+  any arguments found in ... are not used.
+
+- In the romer() function, the empirical Bayes shrinkage of the
+  residuals, introduced 5 October 2009, has been removed.  The
+  results will revert to being somewhat more conservative.
+
+- speed improvement for romer() when the "mean" or "floormean" set
+  statistics are used.
+
+- topGO() can now sort gene ontology results by several p-value
+  columns at once, using the minimum of the columns.  The default is
+  now to sort results using all the p-value columns found in the
+  results instead of just by the first column.
+
+- new arguments 'plot' and 'covariate' for goana().  The help files
+  goana.Rd and goana.MArrayLM.Rd are consolidated into one file.
+
+13 March 2015: limma 3.23.11
+
+- new argument 'legend' for plotDensities, allowing user to
+  reposition the legend.
+
+1 March 2015: limma 3.23.10
+
+- fix a bug in the MAList method for plotDensities that was
+  introduced with the use of NextMethod() in version 3.21.16.
+
+24 Feb 2015: limma 3.23.9
+
+- Update citation to the recent limma review article, which is now in
+  advance access publication.
+
+16 Jan 2015: limma 3.23.8
+
+- When loading suggested packages within function calls, usages of
+  require() have been converted to requireNamespace() wherever
+  possible.  Functions from suggested packages are called using ::.
+
+- Acknowledgements edited in User's Guide.
+
+12 Jan 2015: limma 3.23.7
+
+- fix URLs for a number of references in help pages.
+
+- fix bug in plotMDS.default introduced with limma 3.23.5
+
+8 Jan 2015: limma 3.23.6
+
+- Limma review article (Ritchie et al, NAR, 2015) now accepted for
+  publication.  Updating references in User's Guide, help
+  files and CITATION to refer to this article.
+
+29 Dec 2014: limma 3.23.5
+
+- bug fix to plotMDS when gene.selection="common" and top=nrow(x).
+
+- plotMDS() now traps problems when the distances are all zero or if
+  one or more of the dimensions are degenerate.
+
+- CITATION file now refers to Ritchie et al (NAR, 2015).
+
+27 Dec 2014: limma 3.23.4
+
+- new 'col' argument for voomWithQualityWeights() so that barplot of 
+  sample weights can be colour-coded by the user.
+
+13 Dec 2014: limma 3.23.3
+
+- improvements to lowess C code.
+
+- the argument names predFCm() changed slightly.  Old argument
+  'VarRel' replaced by logical argument 'var.indep.of.fc'.  Old
+  argument 'prop' replaced by 'all.de'.  New argument
+  'prop.true.null.method' passes through method to propTrueNull.
+
+25 Nov 2014: limma 3.23.2
+
+- plotMDS() now stores 'axislabel', depending on the method used to
+  compute distances, and using this for axis labels.
+
+- vennDiagram now fills circles with specified colors.
+
+- voomWithQualityWeights() now stores the sample weights in the
+  sample.weights component output EList objects.  The values stored
+  in $weights are unchanged, they are still the combined 
+  observation and sample weights.
+
+- plotMA method for EListRaw objects.
+
+- nec() and neqc() now remove the Eb component if it exists in an
+  EListRaw object.
+
+20 Oct 2014: limma 3.23.1
 
 - romer() is now an S3 generic function.
 
+14 Oct 2014: limma 3.23.0 (Bioconductor 3.1 Developmental Branch)
 14 Oct 2014: limma 3.22.0 (Bioconductor 3.0 Release Branch)
 
 10 Oct 2014: limma 3.21.21
 
-- arrayWeights() with plot=TRUE now resets graphics parameters to
-  original settings on exit.
+- arrayWeights() has a new argument var.design, allowing the array
+  weights to be a function of covariates.  When plot=TRUE, the
+  graphics parameters are now reset to original values on exit.
+
+- new function voomWithQualityWeights(), combining capabilities of
+  voom() and arrayWeights().
 
 10 Oct 2014: limma 3.21.20
 
@@ -53,6 +294,8 @@
 
 - Updates to the two RNA-seq case studies in the User's Guide.
 
+- plotDensities S3 methods now use NextMethod().
+
  8 Sep 2014: limma 3.21.15
 
 - speed improvement for goana().
@@ -1457,8 +1700,10 @@
 15 July 2010: limma 3.5.13
 
 - marray no longer a suggested package
+
 - read.ilmn() now uses readGenericHeader() to skip over
   header information in BeadStudio files.
+
 - read.ilmn() no longer issues warning if control probe
   files are not provided.
 
@@ -1478,14 +1723,15 @@
 
 3 June 2010: limma 3.5.9
 
-- new argument 'set.statistic' for romer() to control the
-  sensitivity of the tests to sets with only a subset of genes
-  differentially expressed.  The old function romer2() and the
-  old argument 'floor' are now retired.
 - romer() now longer outputs p-values for the "either"
   alternative hypothesis.  P-values are output for "Up", "Down"
   or "Mixed".
 
+- romer() and romer2() consolidated into one function romer(). There
+  is now a new argument 'set.statistic' to choose the set summary
+  statistic, and the old argument 'floor' is removed as no longer
+  needed.
+
 2 June 2010: limma 3.5.8
 
 - more complete documentation for roast().
@@ -1701,11 +1947,15 @@
 - New function genas() which tests for associations between
   contrasts in a linear model.
 
-- New options and improved power for the romer() function.
-  There are now two versions, romer() and romer2(), which use
-  different test statistics.  Both new versions should give
-  better statistical power than the old version.  The new
-  romer() is also computationally quicker.
+- New options and improved power for the romer() function.  Empirical
+  Bayes shrinkage of the residuals is now used to improve statistical
+  power.  There are also two new options for the set summary
+  statistic.  The original mean50 statistic is now provided in a new
+  function romer2().  The new romer() function now uses an ordinary
+  mean set statistics by default, and a floor-mean set statistic as
+  an option.  Both romer() and romer2() give better statistical power
+  than than the previous version.  The new romer() is also
+  computationally quicker.
 
 - new functions read.ilmn() and read.ilmn.targets() for reading in
   Illumina Whole Genome Expression BeadChip data.
@@ -3062,27 +3312,36 @@ This version was the first posted to CRAN as well as to Bioconductor
 28 June 2004: limma 1.7.1
 
 - cex=16,pch=0.2 now default in plotMA()
-- cex=16,pch=0.1 changed to cex=16,pch=0.2 throughout User's Guide
+
 - calls in normalizeRobustSpline() to rlm() now explicitly set prior weights
 
 28 June 2004: limma 1.7.0
 
-	All the linear modelling functions now pass the covariance matrix
-	Of the estimated coefficients.	This improves support for models
-	with covariance structures: random effects models for technical
-	replicates, mixed models for log-intensity analysis of two color
-	data, duplicate spots etc.  Lots of updates to help files.  pdf of
-	User's Guide updated.  Reading of GPR headers now supported.
+- All the linear modelling functions now pass the covariance matrix
+  Of the estimated coefficients.	This improves support for models
+  with covariance structures: random effects models for technical
+  replicates, mixed models for log-intensity analysis of two color
+  data, duplicate spots etc.  Lots of updates to help files.  pdf of
+  User's Guide updated.  Reading of GPR headers now supported.
 
 - pdf version of User's Guide updated
+
 - estrogen case study re-done for User's Guide
+
 - many .Rd files revised
+
 - instances of missing() changed to is.null() is modelMatrix()
+
 - lm.series(), rlm.series(), gls.series() and lmscFit() now save cov matrix of coefficients
+
 - contrasts.fit() and classifyTestF() now use cov matrix of coefficients in data object
+
 - changed many external links in .Rd files to reflect movement of functions from base to stats and graphics in R 1.9.0
+
 - readGPRHeader() no longer assumes any known fields
+
 - lmFit() now accepts PLMset objects
+
 - changelog.txt moved to /inst/doc
 
 21 June 2004: limma 1.6.14
diff --git a/inst/doc/intro.pdf b/inst/doc/intro.pdf
index c19625c..4bd9f8e 100644
Binary files a/inst/doc/intro.pdf and b/inst/doc/intro.pdf differ
diff --git a/man/01Introduction.Rd b/man/01Introduction.Rd
index d008fc5..0a6823e 100644
--- a/man/01Introduction.Rd
+++ b/man/01Introduction.Rd
@@ -8,8 +8,7 @@
 LIMMA is a library for the analysis of gene expression microarray data, especially the use of linear models for analysing designed experiments and the assessment of differential expression.
 LIMMA provides the ability to analyse comparisons between many RNA targets simultaneously in arbitrary complicated designed experiments.
 Empirical Bayesian methods are used to provide stable results even when the number of arrays is small.
-The normalization and data analysis functions are for two-colour spotted microarrays.
-The linear model and differential expression functions apply to all microarrays including Affymetrix and other multi-array oligonucleotide experiments.
+The linear model and differential expression functions apply to all gene expression technologies, including microarrays, RNA-seq and quantitative PCR.
 }
 
 \details{
@@ -35,16 +34,19 @@ The function \code{\link{changeLog}} displays the record of changes to the packa
 \author{Gordon Smyth, with contributions from many colleagues}
 
 \references{
-Smyth, G. K., Yang, Y.-H., Speed, T. P. (2003). Statistical issues in microarray data analysis.
-\emph{Methods in Molecular Biology} 224, 111-136.
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
+
+Law, CW, Chen, Y, Shi, W, and Smyth, GK (2014).
+Voom: precision weights unlock linear model analysis tools for RNA-seq read counts.
+\emph{Genome Biology} 15, R29.
+\url{http://genomebiology.com/2014/15/2/R29}
 
 Smyth, G. K. (2004). Linear models and empirical Bayes methods for assessing differential expression in microarray experiments.
-\emph{Statistical Applications in Genetics and Molecular Biology}, Volume \bold{3}, Article 3.
+\emph{Statistical Applications in Genetics and Molecular Biology}, Volume 3, Article 3.
 \url{http://www.statsci.org/smyth/pubs/ebayes.pdf}
-
-Smyth, G. K. (2005). Limma: linear models for microarray data.
-In: \emph{Bioinformatics and Computational Biology Solutions using R and Bioconductor}.
-R. Gentleman, V. Carey, S. Dudoit, R. Irizarry, W. Huber (eds), Springer, New York, 2005.
 }
 
 \seealso{
diff --git a/man/02classes.Rd b/man/02classes.Rd
index 5c308f2..2ebdd92 100644
--- a/man/02classes.Rd
+++ b/man/02classes.Rd
@@ -51,4 +51,19 @@ A \code{show} method is defined for \code{LargeDataOject}s which uses the utilit
 }
 
 \author{Gordon Smyth}
+
+\seealso{
+\link{01.Introduction},
+\link{02.Classes},
+\link{03.ReadingData},
+\link{04.Background},
+\link{05.Normalization},
+\link{06.LinearModels},
+\link{07.SingleChannel},
+\link{08.Tests},
+\link{09.Diagnostics},
+\link{10.GeneSetTests},
+\link{11.RNAseq}
+}
+
 \keyword{documentation}
diff --git a/man/03reading.Rd b/man/03reading.Rd
index 46c9961..1eb4283 100644
--- a/man/03reading.Rd
+++ b/man/03reading.Rd
@@ -62,4 +62,18 @@ The functions \code{\link{readSpotTypes}} and \code{\link{controlStatus}} assist
 }
 
 \author{Gordon Smyth}
+
+\seealso{
+\link{01.Introduction},
+\link{02.Classes},
+\link{03.ReadingData},
+\link{04.Background},
+\link{05.Normalization},
+\link{06.LinearModels},
+\link{07.SingleChannel},
+\link{08.Tests},
+\link{09.Diagnostics},
+\link{10.GeneSetTests},
+\link{11.RNAseq}
+}
 \keyword{documentation}
diff --git a/man/04Background.Rd b/man/04Background.Rd
index 3979a48..405cb54 100644
--- a/man/04Background.Rd
+++ b/man/04Background.Rd
@@ -23,4 +23,19 @@ If \code{robust=TRUE}, then \code{normexp.fit.control} uses the function \code{h
 }
 
 \author{Gordon Smyth}
+
+\seealso{
+\link{01.Introduction},
+\link{02.Classes},
+\link{03.ReadingData},
+\link{04.Background},
+\link{05.Normalization},
+\link{06.LinearModels},
+\link{07.SingleChannel},
+\link{08.Tests},
+\link{09.Diagnostics},
+\link{10.GeneSetTests},
+\link{11.RNAseq}
+}
+
 \keyword{documentation}
diff --git a/man/05Normalization.Rd b/man/05Normalization.Rd
index b715086..c57e16c 100644
--- a/man/05Normalization.Rd
+++ b/man/05Normalization.Rd
@@ -38,4 +38,19 @@ Smyth, G. K., and Speed, T. P. (2003). Normalization of cDNA microarray data.
 \emph{Methods} 31, 265-273.
 \url{http://www.statsci.org/smyth/pubs/normalize.pdf}
 }
+
+\seealso{
+\link{01.Introduction},
+\link{02.Classes},
+\link{03.ReadingData},
+\link{04.Background},
+\link{05.Normalization},
+\link{06.LinearModels},
+\link{07.SingleChannel},
+\link{08.Tests},
+\link{09.Diagnostics},
+\link{10.GeneSetTests},
+\link{11.RNAseq}
+}
+
 \keyword{documentation}
diff --git a/man/06linearmodels.Rd b/man/06linearmodels.Rd
index 8992d56..467649d 100644
--- a/man/06linearmodels.Rd
+++ b/man/06linearmodels.Rd
@@ -82,6 +82,9 @@ After the above steps the results may be displayed or further processed using:
 \item{ \code{\link{plotlines}}}{
 	Plots fitted coefficients or log-intensity values for time-course data.}
 
+\item{ \code{\link{genas}}}{
+	Estimates and plots biological correlation between two coefficients.}
+
 \item{ \code{\link{write.fit}} }{
 	Writes an \code{MarrayLM} object to a file.
 	Note that if \code{fit} is an \code{MArrayLM} object, either \code{write.fit} or \code{write.table} can be used to write the results to a delimited text file.}
@@ -101,4 +104,19 @@ Smyth, G. K. (2004). Linear models and empirical Bayes methods for assessing dif
 
 Smyth, G. K., Michaud, J., and Scott, H. (2005). The use of within-array replicate spots for assessing differential expression in microarray experiments. Bioinformatics 21(9), 2067-2075.
 }
+
+\seealso{
+\link{01.Introduction},
+\link{02.Classes},
+\link{03.ReadingData},
+\link{04.Background},
+\link{05.Normalization},
+\link{06.LinearModels},
+\link{07.SingleChannel},
+\link{08.Tests},
+\link{09.Diagnostics},
+\link{10.GeneSetTests},
+\link{11.RNAseq}
+}
+
 \keyword{documentation}
diff --git a/man/07SingleChannel.Rd b/man/07SingleChannel.Rd
index 0a0da0e..39ab49f 100644
--- a/man/07SingleChannel.Rd
+++ b/man/07SingleChannel.Rd
@@ -14,4 +14,19 @@ The function \code{\link{targetsA2C}} converts two-color format target data fram
 }
 
 \author{Gordon Smyth}
+
+\seealso{
+\link{01.Introduction},
+\link{02.Classes},
+\link{03.ReadingData},
+\link{04.Background},
+\link{05.Normalization},
+\link{06.LinearModels},
+\link{07.SingleChannel},
+\link{08.Tests},
+\link{09.Diagnostics},
+\link{10.GeneSetTests},
+\link{11.RNAseq}
+}
+
 \keyword{documentation}
diff --git a/man/08Tests.Rd b/man/08Tests.Rd
index fcde541..5d1d38e 100644
--- a/man/08Tests.Rd
+++ b/man/08Tests.Rd
@@ -50,4 +50,18 @@ When evaluating test procedures with simulated or known results, the utility fun
 }
 
 \author{Gordon Smyth}
+
+\seealso{
+\link{01.Introduction},
+\link{02.Classes},
+\link{03.ReadingData},
+\link{04.Background},
+\link{05.Normalization},
+\link{06.LinearModels},
+\link{07.SingleChannel},
+\link{08.Tests},
+\link{09.Diagnostics},
+\link{10.GeneSetTests},
+\link{11.RNAseq}
+}
 \keyword{documentation}
diff --git a/man/09Diagnostics.Rd b/man/09Diagnostics.Rd
index 97754b9..6491ad0 100644
--- a/man/09Diagnostics.Rd
+++ b/man/09Diagnostics.Rd
@@ -22,11 +22,24 @@ Produces a spatial picture of any spot-specific measure from an array image. If
 \item{ \code{\link{plotFB}} }{
 Plots foreground versus background log-intensies.}
 
-\item{ \code{\link{plotMA}} or \code{\link{plot.MAList}} }{
-MA-plots.
-One of the most useful plots of a two-color array.
+\item{ \code{\link{plotMD}} }{
+Mean-difference plots.
+Very versatile plot.
+For two color arrays, this plots the M-values vs A-values.
+For single channel technologies, this plots one column of log-expression values vs the average of the other columns.
+For fitted model objects, this plots a log-fold-change versus average log-expression.
+\code{\link{mdplot}} can also be useful for comparing two one-channel microarrays.
+}
+
+\item{ \code{\link{plotMA}} }{
+MA-plots, essentially the same as mean-difference plots.
 \code{\link{plotMA3by2}} will write MA-plots to files, six plots to a page.
-\code{\link{mdplot}} can also be useful for comparing two one-channel microarrays.}
+}
+
+\item{ \code{\link{plotWithHighlights}} }{
+Scatterplots with highlights.
+This is the underlying engine for \code{plotMD} and \code{plotMA}.
+}
 
 \item{ \code{\link{plotPrintTipLoess}} }{
 Produces a grid of MA-plots, one for each print-tip group on an array, together with the corresponding lowess curve.
@@ -53,4 +66,19 @@ After a linear model is fitted, this checks constancy of the variance with respe
 }
 
 \author{Gordon Smyth}
+
+\seealso{
+\link{01.Introduction},
+\link{02.Classes},
+\link{03.ReadingData},
+\link{04.Background},
+\link{05.Normalization},
+\link{06.LinearModels},
+\link{07.SingleChannel},
+\link{08.Tests},
+\link{09.Diagnostics},
+\link{10.GeneSetTests},
+\link{11.RNAseq}
+}
+
 \keyword{documentation}
diff --git a/man/10GeneSetTests.Rd b/man/10GeneSetTests.Rd
index 03557d0..33e793f 100644
--- a/man/10GeneSetTests.Rd
+++ b/man/10GeneSetTests.Rd
@@ -12,10 +12,13 @@ This page gives an overview of the LIMMA functions for gene set testing and path
 \item{ \code{\link{mroast}} }{
 	Self-contained gene set testing for many sets.}
 
+\item{ \code{\link{fry}} }{
+	Fast version of \code{mroast} when heteroscedasticity of genes can be ignored.}
+
 \item{ \code{\link{camera}} }{
 	Competitive gene set testing.}
 
-\item{ \code{\link{romer}} }{
+\item{ \code{\link{romer}} and \code{\link{topRomer}} }{
 	Gene set enrichment analysis.}
 
 \item{ \code{\link{ids2indices}} }{
@@ -24,13 +27,36 @@ This page gives an overview of the LIMMA functions for gene set testing and path
 \item{ \code{\link{alias2Symbol}} and \code{\link{alias2SymbolTable}} }{
 	Convert gene symbols or aliases to current official symbols.}
 
-\item{ \code{\link{topRomer}} }{
-	Display results from romer tests as a top-table.}
-
 \item{ \code{\link{geneSetTest}} or \code{\link{wilcoxGST}} }{
 	Simple gene set testing based on gene or probe permutation.}
 
 \item{ \code{\link{barcodeplot}} }{
 	Enrichment plot of a gene set.}
+
+\item{ \code{\link{goana}} and \code{\link{topGO}}}{
+	Gene ontology over-representation analysis of gene lists using Entrez Gene IDs.
+	\code{goana} can work directly on a fitted model object or on one or more lists of genes.}
+
+\item{ \code{\link{kegga}} and \code{\link{topKEGG}}}{
+	KEGG pathway over-representation analysis of gene lists using Entrez Gene IDs.
+	\code{goana} can work directly on a fitted model object or on one or more lists of genes.}
 }
 }
+
+\author{Gordon Smyth}
+
+\seealso{
+\link{01.Introduction},
+\link{02.Classes},
+\link{03.ReadingData},
+\link{04.Background},
+\link{05.Normalization},
+\link{06.LinearModels},
+\link{07.SingleChannel},
+\link{08.Tests},
+\link{09.Diagnostics},
+\link{10.GeneSetTests},
+\link{11.RNAseq}
+}
+
+\keyword{documentation}
diff --git a/man/11RNAseq.Rd b/man/11RNAseq.Rd
index d66e456..2c34ead 100644
--- a/man/11RNAseq.Rd
+++ b/man/11RNAseq.Rd
@@ -3,21 +3,27 @@
 \title{Topic: Analysis of RNA-seq Data}
 
 \description{
-This page gives an overview of the LIMMA functions available to analyze RNA-seq data.
+This page gives an overview of LIMMA functions to analyze RNA-seq data.
 
 \describe{
 \item{ \code{\link{voom}} }{
 	Transform RNA-seq or ChIP-seq counts to log counts per million (log-cpm) with associated precision weights.
 	After this tranformation, RNA-seq or ChIP-seq data can be analyzed using the same functions as would be used for microarray data.}
 
+\item{ \code{\link{voomWithQualityWeights}} }{
+	Combines the functionality of \code{voom} and \code{arrayWeights}.}
+
 \item{ \code{\link{diffSplice}} }{
-	Test for differential splicing of exons between experimental conditions.}
+	Test for differential exon usage between experimental conditions.}
 
 \item{ \code{\link{topSplice}} }{
 	Show a data.frame of top results from \code{diffSplice}.}
 
 \item{ \code{\link{plotSplice}} }{
 	Plot results from \code{diffSplice}.}
+
+\item{ \code{\link{plotExons}} }{
+	Plot logFC for individual exons for a given gene.}
 }
 }
 
@@ -26,6 +32,28 @@ Law, CW, Chen, Y, Shi, W, Smyth, GK (2014).
 Voom: precision weights unlock linear model analysis tools for RNA-seq read counts.
 \emph{Genome Biology} 15, R29.
 \url{http://genomebiology.com/2014/15/2/R29}
+
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
+}
+
+\seealso{
+See also the edgeR package for normalization and data summaries of RNA-seq data, as well as for alternative differential expression methods based on the negative binomial distribution.
+\code{voom} accepts DGEList objects and normalization factors from edgeR.
+
+\link{01.Introduction},
+\link{02.Classes},
+\link{03.ReadingData},
+\link{04.Background},
+\link{05.Normalization},
+\link{06.LinearModels},
+\link{07.SingleChannel},
+\link{08.Tests},
+\link{09.Diagnostics},
+\link{10.GeneSetTests},
+\link{11.RNAseq}
 }
 
 \keyword{documentation}
diff --git a/man/EList.Rd b/man/EList.Rd
index e1af7d6..6c48e00 100644
--- a/man/EList.Rd
+++ b/man/EList.Rd
@@ -26,6 +26,7 @@ These classes contains no slots (other than \code{.Data}), but objects should co
 \section{Optional Components}{
 Optional components include:
 \describe{
+  \item{\code{Eb}}{numeric matrix containing unlogged background expression values, of same dimensions as \code{E}. For an \code{EListRaw} object only.}
   \item{\code{weights}}{numeric matrix of same dimensions as \code{E} containing relative spot quality weights.  Elements should be non-negative.}
   \item{\code{other}}{list containing other matrices, all of the same dimensions as \code{E}.}
   \item{\code{genes}}{data.frame containing probe information. Should have one row for each probe. May have any number of columns.}
diff --git a/man/arrayWeights.Rd b/man/arrayWeights.Rd
index 5f2ce5c..5786f8e 100644
--- a/man/arrayWeights.Rd
+++ b/man/arrayWeights.Rd
@@ -59,7 +59,7 @@ the slots or components in the data \code{object}.
 Ritchie, M. E., Diyagama, D., Neilson, van Laar, R., J., Dobrovic, A., Holloway, A., and Smyth, G. K. (2006).
 Empirical array quality weights in the analysis of microarray data.
 BMC Bioinformatics 7, 261.
-\url{http://www.biomedcentral.com/1471-2105/7/261/abstract}
+\url{http://www.biomedcentral.com/1471-2105/7/261}
 }
 \seealso{
 \code{\link{voomWithQualityWeights}}
diff --git a/man/arrayWeightsQuick.Rd b/man/arrayWeightsQuick.Rd
index 4328877..45a0e7b 100644
--- a/man/arrayWeightsQuick.Rd
+++ b/man/arrayWeightsQuick.Rd
@@ -24,7 +24,7 @@ Numeric vector of weights of length \code{ncol(fit)}.
 Ritchie, M. E., Diyagama, D., Neilson, van Laar, R., J., Dobrovic, A., Holloway, A., and Smyth, G. K. (2006).
 Empirical array quality weights in the analysis of microarray data.
 BMC Bioinformatics 7, 261.
-\url{http://www.biomedcentral.com/1471-2105/7/261/abstract}
+\url{http://www.biomedcentral.com/1471-2105/7/261}
 }
 \author{Gordon Smyth}
 \seealso{
diff --git a/man/asmalist.Rd b/man/asmalist.Rd
index 284621f..cded54e 100755
--- a/man/asmalist.Rd
+++ b/man/asmalist.Rd
@@ -11,7 +11,7 @@ as.MAList(object)
 }
 
 \arguments{
-\item{object}{an \code{\link[marray:marrayNorm-class]{marrayNorm}} object}
+\item{object}{an \code{marrayNorm} object}
 }
 
 \value{
@@ -29,6 +29,8 @@ Note that such conversion is not necessary to access the limma linear modelling
 
 \seealso{
   \link{02.Classes} gives an overview of all the classes defined by this package.
+
+  The marrayNorm class is defined in the marray package.
 }
 
 \keyword{classes}
diff --git a/man/auROC.Rd b/man/auROC.Rd
index e2e8a5a..c017a1f 100755
--- a/man/auROC.Rd
+++ b/man/auROC.Rd
@@ -13,19 +13,21 @@ auROC(truth, stat=NULL)
   If \code{NULL}, then \code{truth} is assumed to be already sorted in decreasing test statistic order.}
 }
 \details{
-A receiver operating curve (ROC) is a plot of sensitivity (true positive rate) versus error (false positive rate) for a statistical test or binary classifier.
+A receiver operating curve (ROC) is a plot of sensitivity (true positive rate) versus 1-specificity (false positive rate) for a statistical test or binary classifier.
 The area under the ROC is a well accepted measure of test performance.
 It is equivalent to the probability that a randomly chosen pair of cases is corrected ranked.
 
-Here we consider a test statistic \code{stat}, with larger values being more significant, and a vector \code{truth} indicating whether the null hypothesis is in fact true.
+Here we consider a test statistic \code{stat}, with larger values being more significant, and a vector \code{truth} indicating whether the alternative hypothesis is in fact true.
+\code{truth==TRUE} or \code{truth==1} indicates a true discovery and \code{truth=FALSE} or \code{truth=0} indicates a false discovery.
 Correct ranking here means that \code{truth[i]} is greater than or equal to \code{truth[j]} when \code{stat[i]} is greater than \code{stat[j]}. 
 The function computes the exact area under the empirical ROC curve defined by \code{truth} when ordered by \code{stat}.
+
+If \code{stat} contains ties, then \code{auROC} returns the average area under the ROC for all possible orderings of \code{truth} for tied \code{stat} values.
+
+The area under the curve is undefined if \code{truth} is all \code{TRUE} or all \code{FALSE} or if \code{truth} or \code{stat} contain missing values.
 }
 \value{
-Numeric vector giving area under the curve, 1 being perfect and 0 being the minimum, or \code{NULL} if \code{truth} has zero length.
-}
-\seealso{
-See \link{08.Tests} for other functions for testing and processing p-values.
+Numeric value between 0 and 1 giving area under the curve, 1 being perfect and 0 being the minimum.
 }
 \examples{
 auROC(c(1,1,0,0,0))
diff --git a/man/backgroundcorrect.Rd b/man/backgroundcorrect.Rd
index 172cd36..59af249 100755
--- a/man/backgroundcorrect.Rd
+++ b/man/backgroundcorrect.Rd
@@ -67,12 +67,12 @@ Parameter estimation for the exponential-normal convolution model for background
 Ritchie, M. E., Silver, J., Oshlack, A., Silver, J., Holmes, M., Diyagama, D., Holloway, A., and Smyth, G. K. (2007).
 A comparison of background correction methods for two-colour microarrays.
 \emph{Bioinformatics} 23, 2700-2707.
-\url{http://bioinformatics.oxfordjournals.org/cgi/content/abstract/btm412}
+\url{http://bioinformatics.oxfordjournals.org/content/23/20/2700}
 
 Silver, J., Ritchie, M. E., and Smyth, G. K. (2009).
 Microarray background correction: maximum likelihood estimation for the normal-exponential convolution model.
 \emph{Biostatistics} 10, 352-363.
-\url{http://biostatistics.oxfordjournals.org/cgi/content/abstract/kxn042}
+\url{http://biostatistics.oxfordjournals.org/content/10/2/352}
 }
 \author{Gordon Smyth}
 \examples{
diff --git a/man/barcodeplot.Rd b/man/barcodeplot.Rd
index d64126b..8c9174b 100644
--- a/man/barcodeplot.Rd
+++ b/man/barcodeplot.Rd
@@ -48,7 +48,7 @@ An enrichment worm optionally shows the relative enrichment of the vertical bars
 Barcode plots are often used in conjunction with gene set tests, and show the enrichment of gene sets amongst high or low ranked genes.
 They were inspired by the set location plot of Subramanian et al (2005), with a number of enhancements, especially the ability to plot positive and negative sets simultaneously.
 Barcode plots first appeared in the literature in Lim et al (2009).
-More recent examples can be seen in Liu et al (2014).
+More recent examples can be seen in Liu et al (2014), Sheikh et al (2015), Witkowski et al (2015) and Ng et al (2015).
 
 The function can be used with any of four different calling sequences:
   \itemize{
@@ -60,13 +60,20 @@ The function can be used with any of four different calling sequences:
 }
 
 \seealso{
-\code{\link{tricubeMovingAverage}}, \code{\link{roast}}, \code{\link{camera}}, \code{\link{wilcox.test}}
+\code{\link{tricubeMovingAverage}}, \code{\link{roast}}, \code{\link{camera}}, \code{\link{romer}}, \code{\link{geneSetTest}}
+
+There is a topic page on \link{10.GeneSetTests}.
 }
 
 \author{Gordon Smyth, Di Wu and Yifang Hu}
 
 \references{
-Lim E, Vaillant F, Wu D, Forrest NC, Pal B, Hart AH, Asselin-Labat ML, Gyorki DE, Ward T, Partanen A, Feleppa F, Huschtscha LI, Thorne HJ; kConFab; Fox SB, Yan M, French JD, Brown MA, Smyth GK, Visvader JE, Lindeman GJ (2009).
+Ng, AP, Hu, Y, Metcalf, D, Hyland, CD, Ierino, H, Phipson, B, Wu, D, Baldwin, TM, Kauppi, M, Kiu, H, Di, Rago, L, Hilton, DJ, Smyth, GK, Alexander, WS (2015).
+Early lineage priming by trisomy of Erg leads to myeloproliferation in a down syndrome model.
+\emph{PLOS Genetics} 11, e1005211. 
+\url{http://www.ncbi.nlm.nih.gov/pubmed/25973911}
+
+Lim E, Vaillant F, Wu D, Forrest NC, Pal B, Hart AH, Asselin-Labat ML, Gyorki DE, Ward T, Partanen A, Feleppa F, Huschtscha LI, Thorne HJ; kConFab; Fox SB, Yan M, French JD, Brown MA, Smyth GK, Visvader JE, and Lindeman GJ (2009).
 Aberrant luminal progenitors as the candidate target population for basal tumor development in BRCA1 mutation carriers.
 \emph{Nat Med}, 15, 907-913.
 
@@ -75,9 +82,19 @@ Pax5 loss imposes a reversible differentiation block in B progenitor acute lymph
 \emph{Genes & Development} 28, 1337-1350. 
 \url{http://www.ncbi.nlm.nih.gov/pubmed/24939936}
 
-Subramanian A, Tamayo P, Mootha VK, Mukherjee S, Ebert BL, Gillette MA, Paulovich A, Pomeroy SL, Golub TR, Lander ES, Mesirov JP (2005).
+Sheikh, B, Lee, S, El-saafin, F, Vanyai, H, Hu, Y, Pang, SHM, Grabow, S, Strasser, A, Nutt, SL, Alexander, WS, Smyth, GK, Voss, AK, and Thomas, T (2015). 
+MOZ regulates B cell progenitors in mice, consequently, Moz haploinsufficiency dramatically retards MYC-induced lymphoma development. 
+\emph{Blood}, 125, 1910-1921.
+\url{http://www.ncbi.nlm.nih.gov/pubmed/25605372}
+
+Subramanian A, Tamayo P, Mootha VK, Mukherjee S, Ebert BL, Gillette MA, Paulovich A, Pomeroy SL, Golub TR, Lander ES, and Mesirov JP (2005).
 Gene set enrichment analysis: a knowledge-based approach for interpreting genome-wide expression profiles.
 \emph{Proc Natl Acad Sci USA}, 102, 15545-15550.
+
+Witkowski, MT, Cimmino, L, Hu, Y, Trimarchi, T, Tagoh, H, McKenzie, MD, Best, SA, Tuohey, L, Willson, TA, Nutt, SL, Meinrad Busslinger, M, Aifantis, I, Smyth, GK, and Dickins, RA (2015). 
+Activated Notch counteracts Ikaros tumor suppression in mouse and human T cell acute lymphoblastic leukemia.
+\emph{Leukemia}.
+\url{http://www.ncbi.nlm.nih.gov/pubmed/25655195}
 }
 
 \examples{
diff --git a/man/decideTests.Rd b/man/decideTests.Rd
index 157d4de..c260fb0 100755
--- a/man/decideTests.Rd
+++ b/man/decideTests.Rd
@@ -9,7 +9,7 @@ A number of different multiple testing schemes are offered which adjust for mult
 decideTests(object,method="separate",adjust.method="BH",p.value=0.05,lfc=0)
 }
 \arguments{
-  \item{object}{\code{MArrayLM} object output from \code{eBayes} from which the t-statistics may be extracted.}
+  \item{object}{\code{MArrayLM} object output from \code{eBayes} or \code{treat} from which the t-statistics may be extracted.}
   \item{method}{character string specify how probes and contrasts are to be combined in the multiple testing strategy.  Choices are \code{"separate"}, \code{"global"}, \code{"hierarchical"}, \code{"nestedF"} or any partial string.}
   \item{adjust.method}{character string specifying p-value adjustment method.  Possible values are \code{"none"}, \code{"BH"}, \code{"fdr"} (equivalent to \code{"BH"}), \code{"BY"} and \code{"holm"}. See \code{\link[stats]{p.adjust}} for details.}
   \item{p.value}{numeric value between 0 and 1 giving the desired size of the test}
@@ -33,6 +33,11 @@ The setting \code{method="separate"} is equivalent to using \code{topTable} sepa
 \code{method="nestedF"} adjusts down genes and then uses \code{classifyTestsF} to classify contrasts as significant or not for the selected genes.
 Please see the limma User's Guide for a discussion of the statistical properties of these methods.
 }
+\note{
+Although this function enables users to set p-value and lfc cutoffs simultaneously, this is not generally recommended.
+If the fold changes and p-values are not highly correlated, then the use of a fold change cutoff can increase the false discovery rate above the nominal level.
+Users wanting to use fold change thresholding are recommended to use \code{treat} instead of \code{eBayes}, and to leave \code{lfc} at the default value when using \code{decideTests}.
+}
 \seealso{
 An overview of multiple testing functions is given in \link{08.Tests}.
 }
diff --git a/man/diffSplice.Rd b/man/diffSplice.Rd
index bf684c4..9e33177 100644
--- a/man/diffSplice.Rd
+++ b/man/diffSplice.Rd
@@ -38,7 +38,9 @@ The minimum adjusted p-value is then used for each gene.
 This function can be used on data from an exon microarray or can be used in conjunction with voom for exon-level RNA-seq counts.
 }
 \seealso{
-\code{\link{voom}}
+\code{\link{topSplice}}, \code{\link{plotSplice}}
+
+A summary of functions available in LIMMA for RNA-seq analysis is given in \link{11.RNAseq}.
 }
 \author{Gordon Smyth and Charity Law}
 
diff --git a/man/ebayes.Rd b/man/ebayes.Rd
index 17a3e16..2eca21d 100755
--- a/man/ebayes.Rd
+++ b/man/ebayes.Rd
@@ -80,9 +80,12 @@ See \code{\link{squeezeVar}} for more details.
 An overview of linear model functions in limma is given by \link{06.LinearModels}.
 }
 \author{Gordon Smyth and Davis McCarthy}
+
 \references{
-McCarthy, D. J., and Smyth, G. K. (2009). Testing significance relative to a fold-change threshold is a TREAT. \emph{Bioinformatics}.
-\url{http://bioinformatics.oxfordjournals.org/cgi/content/abstract/btp053}
+McCarthy, D. J., and Smyth, G. K. (2009).
+Testing significance relative to a fold-change threshold is a TREAT.
+\emph{Bioinformatics} 25, 765-771.
+\url{http://bioinformatics.oxfordjournals.org/content/25/6/765}
 
 Loennstedt, I., and Speed, T. P. (2002). Replicated microarray data. \emph{Statistica Sinica} \bold{12}, 31-46.
 
@@ -95,6 +98,7 @@ Smyth, G. K. (2004). Linear models and empirical Bayes methods for assessing dif
 \emph{Statistical Applications in Genetics and Molecular Biology}, Volume \bold{3}, Article 3.
 \url{http://www.statsci.org/smyth/pubs/ebayes.pdf}
 }
+
 \examples{
 #  See also lmFit examples
 
diff --git a/man/genas.Rd b/man/genas.Rd
index ea5d08b..abc02f8 100644
--- a/man/genas.Rd
+++ b/man/genas.Rd
@@ -42,6 +42,11 @@ The biological and technical correlations are overlaid on the scatterplot using
 \code{library(ellipse)} is required to enable the plotting of ellipses.
 }
 
+\note{
+As present, \code{genas} assumes that technical correlations between coefficients are the same for all genes, and hence it only works with fit objects that were created without observation weights or missing values.
+It does not work with \code{voom} pipelines, because these involve observation weights.
+}
+
 \value{
 	\code{genas} produces a list with the following components:
 	  \item{technical.correlation}{estimate of the technical correlation}
@@ -67,6 +72,11 @@ Phipson, B. (2013).
 \emph{Empirical Bayes modelling of expression profiles and their associations}.
 PhD Thesis. University of Melbourne, Australia.
 \url{http://repository.unimelb.edu.au/10187/17614}
+
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
 }
 
 \examples{
diff --git a/man/getEAWP.Rd b/man/getEAWP.Rd
index 396c022..84ff6fc 100644
--- a/man/getEAWP.Rd
+++ b/man/getEAWP.Rd
@@ -10,7 +10,7 @@ getEAWP(object)
 }
 \arguments{
   \item{object}{a microarray data object.
-  An object of class \code{list}, \code{MAList}, \code{EList}, \code{marrayNorm}, \code{PLMset}, \code{vsn}, or any class inheriting from \code{ExpressionSet}, or any object that can be coerced to a numeric matrix.}
+  An object of class \code{MAList}, \code{EList}, \code{marrayNorm}, \code{PLMset}, \code{vsn}, or any class inheriting from \code{ExpressionSet}, or any object that can be coerced to a numeric matrix.}
 }
 \details{
 In the case of two-color objects, the \code{Amean} is computed from the matrix of A-values.
diff --git a/man/goana.MArrayLM.Rd b/man/goana.MArrayLM.Rd
deleted file mode 100644
index 975b81c..0000000
--- a/man/goana.MArrayLM.Rd
+++ /dev/null
@@ -1,89 +0,0 @@
-\name{goana.MarrayLM}
-\alias{goana.MArrayLM}
-\title{Gene Ontology Analysis of Differentially Expressed Genes}
-
-\description{
-Test for over-representation of gene ontology (GO) terms in the up and down differentially expressed genes from a linear model fit.
-}
-
-\usage{
-\method{goana}{MArrayLM}(de, coef = ncol(de), geneid = rownames(de), FDR = 0.05, 
-      species = "Hs", trend = FALSE, \dots)
-}
-
-\arguments{
-  \item{de}{an \code{MArrayLM} fit object.}
-  \item{coef}{column number or column name specifying for which coefficient or contrast differential expression should be assessed.}
-  \item{geneid}{Entrez Gene identifiers. Either a vector of length \code{nrow(de)} or the name of the column of \code{de$genes} containing the Entrez Gene IDs.}
-  \item{FDR}{false discovery rate cutoff for differentially expressed genes. Numeric value between 0 and 1.}
-  \item{species}{species identifier. Possible values are \code{"Hs"}, \code{"Mm"}, \code{"Rn"} or \code{"Dm"}.}
-  \item{trend}{adjust analysis for gene length or abundance?
-  Can be logical, or a numeric vector of covariate values, or the name of the column of \code{de$genes} containing the covariate values.
-  If \code{TRUE}, then \code{de$Amean} is used as the covariate.}
-  \item{\dots}{any other arguments are passed to \code{goana.default}.}
-}
-
-\details{
-Performs Gene Ontology enrichment analyses for the up and down differentially expressed genes from a linear model analysis.
-The Entrez Gene ID must be supplied for each gene.
-
-If \code{trend=FALSE}, the function computes one-sided hypergeometric tests equivalent to Fisher's exact test.
-
-If \code{trend=TRUE} or a covariate is supplied, then a trend is fitted to the differential expression results and the method of Young et al (2010) is used to adjust for this trend.
-The adjusted test uses Wallenius' noncentral hypergeometric distribution.
-}
-
-\value{
-A data frame with a row for each GO term and the following columns:
-  \item{Term}{GO term.}
-  \item{Ont}{ontology that the GO term belongs to.  Possible values are \code{"BP"}, \code{"CC"} and \code{"MF"}.}
-  \item{N}{number of genes in the GO term.}
-  \item{Up}{number of up-regulated differentially expressed genes.}
-  \item{Down}{number of down-regulated differentially expressed genes.}
-  \item{P.Up}{p-value for over-representation of GO term in up-regulated genes.}
-  \item{P.Down}{p-value for over-representation of GO term in down-regulated genes.}
-The row names of the data frame give the GO term IDs.
-}
-
-\references{
-  Young, M. D., Wakefield, M. J., Smyth, G. K., Oshlack, A. (2010).
-  Gene ontology analysis for RNA-seq: accounting for selection bias.
-  \emph{Genome Biology} 11, R14.
-  \url{http://genomebiology.com/2010/11/2/R14}
-}
-
-\seealso{
-\code{\link{goana.default}}, \code{\link{topGO}}
-
-The goseq package implements a similar GO analysis.
-The goseq version will work with a variety of gene identifiers, not only Entrez Gene as here, and includes a database of gene length information for various species.
-
-The gostats package also does GO analyses with some different options.
-}
-\author{Gordon Smyth and Yifang Hu}
-\examples{
-
-\dontrun{
-
-fit <- lmFit(y, design)
-fit <- eBayes(fit)
-
-# Standard GO analysis
-go.fisher <- goana(fit)
-topGO(go.fisher, sort = "up")
-topGO(go.fisher, sort = "down")
-
-# GO analysis adjusting for gene abundance
-go.abund <- goana(fit, geneid = "GeneID", trend = TRUE)
-topGO(go.abund, sort = "up")
-topGO(go.abund, sort = "down")
-
-# GO analysis adjusting for gene length bias
-# (assuming that y$genes$Length contains gene lengths)
-go.len <- goana(fit, geneid = "GeneID", trend = "Length")
-topGO(go.len, sort = "up")
-topGO(go.len, sort = "down")
-}
-}
-
-\keyword{gene set test}
diff --git a/man/goana.Rd b/man/goana.Rd
index 2e14d89..8466649 100644
--- a/man/goana.Rd
+++ b/man/goana.Rd
@@ -1,47 +1,92 @@
 \name{goana}
 \alias{goana}
 \alias{goana.default}
-\title{Gene Ontology Analysis}
+\alias{goana.MArrayLM}
+\alias{kegga}
+\alias{kegga.default}
+\alias{kegga.MArrayLM}
+\title{Gene Ontology or KEGG Pathway Analysis}
 
 \description{
-Test for over-representation of gene ontology (GO) terms in one or more sets of genes.
+Test for over-representation of gene ontology (GO) terms or KEGG pathways in one or more sets of genes, optionally adjusting for abundance or gene length bias.
 }
 
 \usage{
-\method{goana}{default}(de, universe = NULL, species = "Hs", prior.prob = NULL, \dots)
+\method{goana}{MArrayLM}(de, coef = ncol(de), geneid = rownames(de), FDR = 0.05, trend = FALSE, \dots)
+\method{goana}{default}(de, universe = NULL, species = "Hs", prior.prob = NULL, covariate=NULL,
+      plot=FALSE, \dots)
+\method{kegga}{MArrayLM}(de, coef = ncol(de), geneid = rownames(de), FDR = 0.05, trend = FALSE, \dots)
+\method{kegga}{default}(de, universe = NULL, species = "Hs", prior.prob = NULL, covariate=NULL,
+      plot=FALSE, \dots)
 }
 
 \arguments{
-  \item{de}{a vector of Entrez Gene IDs, or a list of such vectors.}
+  \item{de}{a vector of Entrez Gene IDs, or a list of such vectors, or an \code{MArrayLM} fit object.}
+  \item{coef}{column number or column name specifying for which coefficient or contrast differential expression should be assessed.}
+  \item{geneid}{Entrez Gene identifiers. Either a vector of length \code{nrow(de)} or the name of the column of \code{de$genes} containing the Entrez Gene IDs.}
+  \item{FDR}{false discovery rate cutoff for differentially expressed genes. Numeric value between 0 and 1.}
+  \item{species}{species identifier. Possible values are \code{"Hs"}, \code{"Mm"}, \code{"Rn"} or \code{"Dm"}.}
+  \item{trend}{adjust analysis for gene length or abundance?
+  Can be logical, or a numeric vector of covariate values, or the name of the column of \code{de$genes} containing the covariate values.
+  If \code{TRUE}, then \code{de$Amean} is used as the covariate.}
   \item{universe}{vector specifying the set of Entrez Gene identifiers to be the background universe.
   If \code{NULL} then all Entrez Gene IDs associated with any gene ontology term will be used as the universe.}
-  \item{species}{species identifier. Possible values are \code{"Hs"}, \code{"Mm"}, \code{"Rn"} or \code{"Dm"}.}
-  \item{prior.prob}{numeric vector giving the prior probability that each gene in the universe appears in a gene set.}
-  \item{\dots}{other arguments are not currently used.}
+  \item{prior.prob}{optional numeric vector of the same length as \code{universe} giving the prior probability that each gene in the universe appears in a gene set. Will be computed from \code{covariate} if the latter is provided.}
+  \item{covariate}{optional numeric vector of the same length as \code{universe} giving a covariate against which \code{prior.prob} should be computed.}
+  \item{plot}{logical, should the \code{prior.prob} vs \code{covariate} trend be plotted?}
+  \item{\dots}{any other arguments in a call to the \code{MArrayLM} method are passed to the default method.}
 }
 
 \details{
-\code{goana} is an S3 generic function.
-The default method performs a Gene Ontology enrichment analysis for one for more gene lists using the appropriate Bioconductor organism package.
-The gene lists must be supplied as Entrez Gene IDs.
+These functions performs a over-representation analysis for Gene Ontology terms or KEGG pathways in a list of Entrez Gene IDs.
+The default method accepts the gene list as a vector of gene IDs,
+while the \code{MArrayLM} method extracts the gene lists automatically from a linear model fit object.
 
-If \code{prior.prob=NULL}, the function computes one-sided hypergeometric tests equivalent to Fisher's exact test.
+\code{goana} uses annotation from the appropriate Bioconductor organism package.
+\code{kegga} uses the KEGGREST package to access KEGG pathway annotation.
 
-The \code{prior.prob} vector can be used to specify the prior probability that each gene in the universe appears in a gene set.
+The default method accepts a vector \code{prior.prob} giving the prior probability that each gene in the universe appears in a gene set.
+This vector can be used to correct for unwanted trends in the differential expression analysis associated with gene length, gene abundance or any other covariate.
+The \code{MArrayLM} object computes the \code{prior.prob} vector automatically when \code{trend} is non-\code{NULL}.
+
+If \code{prior.prob=NULL}, the function computes one-sided hypergeometric tests equivalent to Fisher's exact test.
 If prior probabilities are specified, then a test based on the Wallenius' noncentral hypergeometric distribution is used to adjust for the relative probability that each gene will appear in a gene set, following the approach of Young et al (2010).
+
+The \code{MArrayLM} methods performs over-representation analyses for the up and down differentially expressed genes from a linear model analysis.
+In this case, the universe is all the genes found in the fit object.
+
+\code{trend=FALSE} is equivalent to \code{prior.prob=NULL}.
+If \code{trend=TRUE} or a covariate is supplied, then a trend is fitted to the differential expression results and this is used to set \code{prior.prob}.
+
+The statistical approach provided here is the same as that provided by the goseq package, with one methodological difference and a few restrictions.
+Unlike the goseq package, the gene identifiers here must be Entrez Gene IDs and the user is assumed to be able to supply gene lengths if necessary.
+The goseq package has additional functionality to convert gene identifiers and to provide gene lengths.
+The only methodological difference is that \code{goana} and \code{kegga} computes gene length or abundance bias using \code{tricubeMovingAverage} instead of monotonic regression.
+While \code{tricubeMovingAverage} does not enforce monotonicity, it has the advantage of numerical stability when \code{de} contains only a small number of genes.
 }
 
 \value{
-A data frame with a row for each GO term and the following columns:
+The \code{goana} default method produces a data frame with a row for each GO term and the following columns:
   \item{Term}{GO term.}
   \item{Ont}{ontology that the GO term belongs to.  Possible values are \code{"BP"}, \code{"CC"} and \code{"MF"}.}
   \item{N}{number of genes in the GO term.}
-  \item{DE1}{number of genes in the \code{DE1} set.}
-  \item{P.DE1}{p-value for over-representation of the GO term in the set.}
-The last two column names above assume one gene set with the name \code{DE1}.
-In general, there will be a pair of such columns for each gene set and the name of the set will appear in place of \code{"DE1"}.
+  \item{DE}{number of genes in the \code{DE} set.}
+  \item{P.DE}{p-value for over-representation of the GO term in the set.}
+The last two column names above assume one gene set with the name \code{DE}.
+In general, there will be a pair of such columns for each gene set and the name of the set will appear in place of \code{"DE"}.
+
+The \code{goana} method for \code{MArrayLM} objects produces a data frame with a row for each GO term and the following columns:
+  \item{Term}{GO term.}
+  \item{Ont}{ontology that the GO term belongs to.  Possible values are \code{"BP"}, \code{"CC"} and \code{"MF"}.}
+  \item{N}{number of genes in the GO term.}
+  \item{Up}{number of up-regulated differentially expressed genes.}
+  \item{Down}{number of down-regulated differentially expressed genes.}
+  \item{P.Up}{p-value for over-representation of GO term in up-regulated genes.}
+  \item{P.Down}{p-value for over-representation of GO term in down-regulated genes.}
 
 The row names of the data frame give the GO term IDs.
+
+The output from \code{kegga} is the same except that row names become KEGG pathway IDs, \code{Term} becomes \code{Path} and there is no \code{Ont} column.
 }
 
 \references{
@@ -52,18 +97,42 @@ The row names of the data frame give the GO term IDs.
 }
 
 \seealso{
-\code{\link{goana.MArrayLM}}, \code{\link{topGO}}
+\code{\link{topGO}}, \code{\link{topKEGG}}
 
-The goseq package implements a similar GO analysis.
-The goseq version will work with a variety of gene identifiers, not only Entrez Gene as here, and includes a database of gene length information for various species.
+The goseq package provides an alternative implementation of methods from Young et al (2010).
+Unlike the limma functions documented here, goseq will work with a variety of gene identifiers and includes a database of gene length information for various species.
 
-The gostats package also does GO analyses with some different options.
+The gostats package also does GO analyses without adjustment for bias but with some other options.
+
+See \link{10.GeneSetTests} for a description of other functions used for gene set testing.
 }
 
 \author{Gordon Smyth and Yifang Hu}
 
 \examples{
 \dontrun{
+## Linear model usage:
+
+fit <- lmFit(y, design)
+fit <- eBayes(fit)
+
+# Standard GO analysis
+go.fisher <- goana(fit)
+topGO(go.fisher, sort = "up")
+topGO(go.fisher, sort = "down")
+
+# GO analysis adjusting for gene abundance
+go.abund <- goana(fit, geneid = "GeneID", trend = TRUE)
+topGO(go.abund, sort = "up")
+topGO(go.abund, sort = "down")
+
+# GO analysis adjusting for gene length bias
+# (assuming that y$genes$Length contains gene lengths)
+go.len <- goana(fit, geneid = "GeneID", trend = "Length")
+topGO(go.len, sort = "up")
+topGO(go.len, sort = "down")
+
+## Default usage with a gene list:
 
 go.de <- goana(list(DE1 = EG.DE1, DE2 = EG.DE2, DE3 = EG.DE3))
 topGO(go.de, sort = "DE1")
diff --git a/man/imageplot.Rd b/man/imageplot.Rd
index 12e4e45..e7bebc2 100755
--- a/man/imageplot.Rd
+++ b/man/imageplot.Rd
@@ -49,7 +49,7 @@ It differs from \code{maImage} in that any statistic may be plotted and in its u
 \value{An plot is created on the current graphics device.}
 \author{Gordon Smyth}
 \seealso{
-\code{\link[marray]{maImage}}, \code{\link[graphics]{image}}.
+\code{maImage} in the marray package, \code{\link{image}} in the graphics package.
 
 An overview of diagnostic functions available in LIMMA is given in \link{09.Diagnostics}.
 }
diff --git a/man/lmFit.Rd b/man/lmFit.Rd
index dd26fb9..a3f0da2 100755
--- a/man/lmFit.Rd
+++ b/man/lmFit.Rd
@@ -7,7 +7,8 @@ lmFit(object, design=NULL, ndups=1, spacing=1, block=NULL, correlation, weights=
       method="ls", \dots)
 }
 \arguments{
-  \item{object}{any data object that can be processed by \code{\link{getEAWP}} containing log-ratios or log-values of expression for a series of microarrays.}
+  \item{object}{A matrix-like data object containing log-ratios or log-expression values for a series of arrays, with rows corresponding to genes and columns to samples.
+  Any type of data object that can be processed by \code{\link{getEAWP}} is acceptable.}
   \item{design}{the design matrix of the microarray experiment, with rows corresponding to arrays and columns to coefficients to be estimated.  Defaults to the unit vector meaning that the arrays are treated as replicates.} 
   \item{ndups}{positive integer giving the number of times each distinct probe is printed on each array.}
   \item{spacing}{positive integer giving the spacing between duplicate occurrences of the same probe, \code{spacing=1} for consecutive rows.}
@@ -99,8 +100,8 @@ topTreat(fit2,coef=2)
 # Volcano plot
 volcanoplot(fit,coef=2,highlight=2)
 
-# MA plot
-plot(fit,coef=2)
+# Mean-difference plot
+plotMD(fit,column=2)
 
 # Q-Q plot of moderated t-statistics
 qqt(fit$t[,2],df=fit$df.residual+fit$df.prior)
diff --git a/man/malist.Rd b/man/malist.Rd
index 614955f..64df62f 100755
--- a/man/malist.Rd
+++ b/man/malist.Rd
@@ -45,7 +45,7 @@ and \code{\link{plotPrintTipLoess}}.
 \seealso{
   \link{02.Classes} gives an overview of all the classes defined by this package.
   
-  \code{\link[marray:marrayNorm-class]{marrayNorm}} is the corresponding class in the marray package.
+  \code{marrayNorm} is the corresponding class in the marray package.
 }
 
 \keyword{classes}
diff --git a/man/mdplot.Rd b/man/mdplot.Rd
index cedcf46..0156877 100644
--- a/man/mdplot.Rd
+++ b/man/mdplot.Rd
@@ -1,41 +1,53 @@
-\title{mdplot}
 \name{mdplot}
 \alias{mdplot}
-\description{
-Creates a mean-difference plot.
-}
-\usage{
-mdplot(x, xlab="Mean", ylab="Difference", \dots)
-}
+\title{Mean-Difference Plot}
+\description{Creates a mean-difference plot of two columns of a matrix.}
+
+\usage{mdplot(x, columns=c(1,2), xlab="Mean", ylab="Difference", main=NULL, \dots)}
+
 \arguments{
   \item{x}{numeric \code{matrix} with at least two columns.}
+  \item{columns}{which columns of \code{x} to compare. Plot will display second minus first.}
   \item{xlab}{label for the x-axis.}
   \item{ylab}{label for the y-axis.}
+  \item{main}{title of the plot. Defaults to }
   \item{\dots}{any other arguments are passed to \code{\link{plotWithHighlights}}.}
 }
 
 \details{
 Plots differences vs means for a set of bivariate values.
-This is useful to contrast expression values for two microarrays.
-
-An MA-plot \code{\link{plotMA}} is a type of mean-difference plot.
+This is a generally useful approach for comparing two correlated measures of the same underlying phenomenon.
+Bland and Altman (1986) argue it is more information than a simple scatterplot of the two variables.
+The bivariate values are stored as columns of \code{x}.
 }
 
 \value{A plot is created on the current graphics device.}
 
 \references{
-Chambers, J. M., Cleveland, W. S., Kleiner, B., and Tukey, P. A. (1983). Graphical Methods of Data Analysis. Wadsworth (pp. 48-57).
-
 Cleveland, W. S., (1993). Visualizing Data. Hobart Press.
 
-Bland, J. M., and Altman, D. G. (1986). Statistical methods for assessing agreement between two methods of clinical measurement. Lancet i, 307-310.
+Bland, J. M., and Altman, D. G. (1986). Statistical methods for assessing agreement between two methods of clinical measurement. Lancet 327, 307-310.
 
 See also \url{http://www.statsci.org/micrarra/refs/maplots.html}
 }
+
 \author{Gordon Smyth}
+
 \seealso{
-\code{\link{plotMA}}, \code{\link{plotWithHighlights}}
+\code{\link{plotWithHighlights}}
+
+\code{\link{plotMD}} is an object-oriented implementation of mean-difference plots for expression data.
 
 An overview of diagnostic functions available in LIMMA is given in \link{09.Diagnostics}.
 }
+
+\examples{
+x1 <- runif(100)
+x2 <- (x1 + rnorm(100,sd=0.01))^1.2
+oldpar <- par(mfrow=c(1,2))
+plot(x1,x2)
+mdplot(cbind(x1,x2),bg.pch=1,bg.cex=1)
+par(oldpar)
+}
+
 \keyword{hplot}
diff --git a/man/modifyWeights.Rd b/man/modifyWeights.Rd
index 5532023..1d1798a 100755
--- a/man/modifyWeights.Rd
+++ b/man/modifyWeights.Rd
@@ -1,6 +1,6 @@
-\title{modifyWeights}
 \name{modifyWeights}
 \alias{modifyWeights}
+\title{Modify Matrix of Weights By Control Status of Rows}
 \description{
 Modify weights matrix for given gene status values.
 }
diff --git a/man/normalizeRobustSpline.Rd b/man/normalizeRobustSpline.Rd
index 640f4fa..9c995ff 100755
--- a/man/normalizeRobustSpline.Rd
+++ b/man/normalizeRobustSpline.Rd
@@ -1,12 +1,15 @@
 \name{normalizeRobustSpline}
 \alias{normalizeRobustSpline}
 \title{Normalize Single Microarray Using Shrunk Robust Splines}
+
 \description{
 Normalize the M-values for a single microarray using robustly fitted regression splines and empirical Bayes shrinkage.
 }
+
 \usage{
 normalizeRobustSpline(M,A,layout=NULL,df=5,method="M")
 }
+
 \arguments{
   \item{M}{numeric vector of M-values}
   \item{A}{numeric vector of A-values}
@@ -14,6 +17,7 @@ normalizeRobustSpline(M,A,layout=NULL,df=5,method="M")
   \item{df}{degrees of freedom for regression spline, i.e., the number of regression coefficients and the number of knots}
   \item{method}{choices are \code{"M"} for M-estimation or \code{"MM"} for high breakdown point regression}
 }
+
 \details{
 This function implements an idea similar to print-tip loess normalization but uses regression splines in place of the loess curves and uses empirical Bayes ideas to shrink the individual print-tip curves towards a common value.
 This allows the technique to introduce less noise into good quality arrays with little spatial variation while still giving good results on arrays with strong spatial variation.
@@ -29,19 +33,27 @@ regression replacing the loess robustifying weights.
 Robust spline normalization with \code{method="MM"} has potential advantages over global loess normalization when there a lot of differential expression or the differential expression is assymetric, because of the increased level of robustness.
 The potential advantages of this approach have not been fully explored in a refereed publication however.
 }
+
 \value{
 Numeric vector containing normalized M-values.
 }
+
 \author{Gordon Smyth}
+
 \references{
-The function is based on unpublished work by the author.
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
 }
+
 \seealso{
 \code{normalizeRobustSpline} uses \code{ns} in the splines package to specify regression splines and \code{rlm} in the MASS package for robust regression.
 
 This function is usually accessed through \code{\link{normalizeWithinArrays}}.
 An overview of LIMMA functions for normalization is given in \link{05.Normalization}.
 }
+
 \examples{
 A <- 1:100
 M <- rnorm(100)
diff --git a/man/normalizeWithinArrays.Rd b/man/normalizeWithinArrays.Rd
index dcb8e98..8d42082 100755
--- a/man/normalizeWithinArrays.Rd
+++ b/man/normalizeWithinArrays.Rd
@@ -81,7 +81,7 @@ In particular, see \code{\link{normalizeBetweenArrays}} for between-array normal
 The original loess normalization function was the \code{statma} funtion in the sma package.
 \code{normalizeWithinArrays} is a direct generalization of that function, with more options and with support for quantitative spot quality weights.
 
-A different implementation of loess normalization methods, with potentially different behavior, is provided by the \code{\link[marray:maNorm]{maNorm}} in the marray package.
+A different implementation of loess normalization methods, with potentially different behavior, is provided by the \code{maNorm} in the marray package.
 }
 
 \keyword{normalization}
diff --git a/man/normalizebetweenarrays.Rd b/man/normalizebetweenarrays.Rd
index 46f18e5..6f2da16 100755
--- a/man/normalizebetweenarrays.Rd
+++ b/man/normalizebetweenarrays.Rd
@@ -89,7 +89,7 @@ In: D. R. Goldstein (ed.), \emph{Science and Statistics: A Festschrift for Terry
 
   Note that vsn normalization, previously offered as a method of this function, is now performed by the \code{\link{normalizeVSN}} function.
 
-  See also \code{\link[marray:maNormScale]{maNormScale}} in the marray package and
+  See also \code{maNormScale} in the marray package and
   \code{\link[affy:normalize-methods]{normalize-methods}} in the affy package.
 }
 
diff --git a/man/normexpfit.Rd b/man/normexpfit.Rd
index 285d099..90b119d 100644
--- a/man/normexpfit.Rd
+++ b/man/normexpfit.Rd
@@ -53,13 +53,13 @@ Parameter estimation for the exponential-normal convolution model for background
 
 Ritchie, M. E., Silver, J., Oshlack, A., Silver, J., Holmes, M., Diyagama, D., Holloway, A., and Smyth, G. K. (2007).
 A comparison of background correction methods for two-colour microarrays.
-\emph{Bioinformatics}
-\url{http://bioinformatics.oxfordjournals.org/cgi/content/abstract/btm412}
+\emph{Bioinformatics} 23, 2700-2707.
+\url{http://bioinformatics.oxfordjournals.org/content/23/20/2700}
 
 Silver, JD, Ritchie, ME, and Smyth, GK (2009).
 Microarray background correction: maximum likelihood estimation for the normal-exponential convolution.
 \emph{Biostatistics} 10, 352-363.
-\url{http://biostatistics.oxfordjournals.org/cgi/content/abstract/kxn042}
+\url{http://biostatistics.oxfordjournals.org/content/10/2/352}
 }
 
 \seealso{
diff --git a/man/normexpsignal.Rd b/man/normexpsignal.Rd
index 18647cb..8f79643 100644
--- a/man/normexpsignal.Rd
+++ b/man/normexpsignal.Rd
@@ -22,13 +22,13 @@ Numeric vector containing adjusted intensities.
 \references{
 Ritchie, M. E., Silver, J., Oshlack, A., Silver, J., Holmes, M., Diyagama, D., Holloway, A., and Smyth, G. K. (2007).
 A comparison of background correction methods for two-colour microarrays.
-\emph{Bioinformatics}
-\url{http://bioinformatics.oxfordjournals.org/cgi/content/abstract/btm412}
+\emph{Bioinformatics} 23, 2700-2707.
+\url{http://bioinformatics.oxfordjournals.org/content/23/20/2700}
 
 Silver, JD, Ritchie, ME, and Smyth, GK (2009).
 Microarray background correction: maximum likelihood estimation for the normal-exponential convolution.
 \emph{Biostatistics} 10, 352-363.
-\url{http://biostatistics.oxfordjournals.org/cgi/content/abstract/kxn042}
+\url{http://biostatistics.oxfordjournals.org/content/10/2/352}
 }
 
 \author{Gordon Smyth}
diff --git a/man/plot.Rd b/man/plot.Rd
deleted file mode 100644
index 19825fa..0000000
--- a/man/plot.Rd
+++ /dev/null
@@ -1,94 +0,0 @@
-\title{plot.MArrayLM}
-\name{plot.MArrayLM}
-\alias{plot.RGList}
-\alias{plot.MAList}
-\alias{plot.EList}
-\alias{plot.MArrayLM}
-\alias{plotWithHighlights}
-\description{
-Plot data or model fit objects.
-These represent the object by creating an MA-plot, with optional color coding for control spots.
-}
-\usage{
-plotWithHighlights(x, y, status = NULL, values = NULL, pch = 16, col = NULL, cex = 1,
-     legend = "topleft", pch.bg = 16, col.bg = "black", cex.bg = 0.3, \dots)
-\method{plot}{EList}(x, y, array = 1, xlab = "Average log-expression",
-     ylab = "Expression log-ratio (this sample vs others)", main = colnames(x)[array],
-     status=x$genes$Status, zero.weights = FALSE, \dots)
-\method{plot}{RGList}(x, y, array = 1, xlab = "A", ylab = "M", main = colnames(x)[array],
-     status=x$genes$Status, zero.weights = FALSE, \dots)
-\method{plot}{MAList}(x, y, array = 1, xlab = "A", ylab = "M", main = colnames(x)[array],
-     status=x$genes$Status, zero.weights = FALSE, \dots)
-\method{plot}{MArrayLM}(x, y, coef = ncol(x), xlab = "Average log-expression", ylab = "log-fold-change",
-     main = colnames(x)[coef], status = x$genes$Status, zero.weights = FALSE, \dots)
-}
-\arguments{
-  \item{x}{an \code{RGList}, \code{MAList}, \code{EList} or \code{MArrayLM} object.}
-  \item{y}{not used.}
-  \item{array}{integer giving the array to be plotted (if \code{x} is an \code{RGList}, \code{MAList} or \code{EList} object).}
-  \item{coef}{integer giving the linear model coefficient to be plotted.}
-  \item{xlab}{character string giving label for x-axis}
-  \item{ylab}{character string giving label for y-axis}
-  \item{main}{character string giving title for plot}
-  \item{status}{character vector giving the control status of each spot on the array, of same length as the number of rows of \code{MA$M}.
-  If \code{NULL}, then all points are plotted in the default color, symbol and size.}
-  \item{values}{character vector giving values of \code{status} to be highlighted on the plot.
-  Defaults to unique values of \code{status} in decreasing order of frequency, with the most frequent value set as the background value.
-  Ignored if there is no \code{status} vector.}
-  \item{pch}{vector or list of plotting characters.
-  Ignored is there is no \code{status} vector.}
-  \item{col}{numeric or character vector of colors, of the same length as \code{values}.
-  Defaults to \code{1+1:length(values)}.
-  Ignored if there is no \code{status} vector.}
-  \item{cex}{numeric vector of plot symbol expansions.
-  If a vector, then of the same length as \code{values}. 
-  Ignored if there is no \code{status} vector.}
-  \item{legend}{character string giving position to place legend.
-  See \code{\link{legend}} for possible values.
-  Can also be logical, with \code{FALSE} meaning no legend.
-  Ignored if there is no \code{status} vector.}
-  \item{zero.weights}{logical, should spots with zero or negative weights be plotted?}
-  \item{pch.bg}{plotting character for background (non-highlighted) points.}
-  \item{col.bg}{color for background (non-highlighted) points.}
-  \item{cex.bg}{plot symbol expansion for background (non-highlighted) points.}
-  \item{\dots}{The \code{plot} methods pass other arguments to \code{plotWithHighlights}, and \code{plotWithHighlights} passes other arguments to \code{plot.default}.}
-}
-
-\details{
-An MA-plot is a plot of log-intensity ratios (M-values) versus log-intensity averages (A-values).
-If \code{x} is an \code{RGList} or \code{MAList} then this function produces an ordinary within-array MA-plot.
-If \code{x} is an \code{MArrayLM} object, then the plot is an fitted model MA-plot in which the estimated coefficient is on the y-axis and the average A-value is on the x-axis.
-
-If \code{x} is a \code{EList} object, then this function produces a between-array MA-plot.
-An articifial array is produced by averaging all the arrays other than the array specified.
-A mean-difference plot is then producing from the specified array and the artificial array.
-Note that this procedure reduces to an ordinary mean-difference plot when there are just two arrays total.
-
-The \code{status} vector is intended to specify the control status of each spot, for example \code{"gene"}, \code{"ratio control"}, \code{"house keeping gene"}, \code{"buffer"} and so on.
-The vector is often computed using the function \code{\link{controlStatus}} and a spot-types file.
-However the function may be used to highlight any subset of spots.
-
-The \code{status} can be included as the component \code{x$genes$Status} instead of being passed as an argument to \code{plot}.
-The arguments \code{values}, \code{pch}, \code{col} and \code{cex} can be included as attributes to \code{status} instead of being passed as arguments to \code{plotMA}.
-
-See \code{\link[graphics]{points}} for possible values for \code{pch}, \code{col} and \code{cex}.
-}
-
-\value{A plot is created on the current graphics device.}
-\references{See \url{http://www.statsci.org/micrarra/refs/maplots.html}}
-\author{Gordon Smyth}
-
-\examples{
-A <- runif(1000,4,16)
-y <- A + matrix(rnorm(1000*3,sd=0.2),1000,3)
-status <- rep(c(0,-1,1),c(950,40,10))
-y[,1] <- y[,1] + status
-E <- new("EList",list(E=y))
-plot(E,array=1,status=status,values=c(-1,1),col=c("blue","red"))
-}
-
-\seealso{
-\code{\link[limma:plotma]{plotMA}}, \code{\link{plotFB}}, \code{\link{plotMDS}}, \code{\link{plotSA}}
-
-An overview of diagnostic plots available in LIMMA is given in \link{09.Diagnostics}.
-}
diff --git a/man/plotDensities.Rd b/man/plotDensities.Rd
index dbec96b..d4fd1ea 100755
--- a/man/plotDensities.Rd
+++ b/man/plotDensities.Rd
@@ -13,10 +13,9 @@ Plot the density of expression values for multiple arrays on the same plot.
 \method{plotDensities}{RGList}(object, log=TRUE, group=NULL, col=NULL, main="RG Densities",
               bc.method="subtract", \dots)
 \method{plotDensities}{MAList}(object, log=TRUE, group=NULL, col=NULL, main="RG Densities", \dots)
-\method{plotDensities}{EListRaw}(object, log=TRUE, group=NULL, col=NULL, main=NULL,
-              bc.method="subtract", \dots)
-\method{plotDensities}{EList}(object, log=TRUE, group=NULL, col=NULL, main=NULL, \dots)
-\method{plotDensities}{default}(object, group=NULL, col=NULL, main=NULL, \dots)
+\method{plotDensities}{EListRaw}(object, log=TRUE, bc.method="subtract", \dots)
+\method{plotDensities}{EList}(object, log=TRUE, \dots)
+\method{plotDensities}{default}(object, group=NULL, col=NULL, main=NULL, legend="topleft", \dots)
 }
 \arguments{
   \item{object}{an \code{RGList}, \code{MAList}, \code{EListRaw} or \code{EList} object containing expression data.  Or any data object that can be coerced to a matrix.}
@@ -25,7 +24,10 @@ Plot the density of expression values for multiple arrays on the same plot.
   \item{col}{optional vector of colors of the same length as the number of groups.}
   \item{main}{the main title for the plot.}
   \item{bc.method}{background subtraction method passed to \code{\link{backgroundCorrect}}.}
-  \item{\ldots}{other arguments are passed to \code{\link{density}}.}
+  \item{legend}{character string giving position to place legend.
+  See \code{\link{legend}} for possible values.
+  Can also be logical, with \code{FALSE} meaning no legend.}
+  \item{\ldots}{other arguments are passed to \code{plotDensities.default} or \code{\link{density}}.}
 }
 
 \details{
diff --git a/man/plotExons.Rd b/man/plotExons.Rd
index 2478dd2..c62cb90 100644
--- a/man/plotExons.Rd
+++ b/man/plotExons.Rd
@@ -30,7 +30,7 @@ The size of the dots are weighted by its significance.
 \seealso{
 \code{\link{lmFit}}, \code{\link{eBayes}}, \code{\link{plotSplice}}
 
-An overview of diagnostic functions available in LIMMA is given in \link{09.Diagnostics}.
+A summary of functions available in LIMMA for RNA-seq analysis is given in \link{11.RNAseq}.
 }
 \examples{
 
diff --git a/man/plotMD.Rd b/man/plotMD.Rd
new file mode 100644
index 0000000..a3d51a3
--- /dev/null
+++ b/man/plotMD.Rd
@@ -0,0 +1,133 @@
+\title{Mean-Difference Plot of Expression Data}
+\name{plotMD}
+\alias{plotMD}
+\alias{plotMD.RGList}
+\alias{plotMD.MAList}
+\alias{plotMD.EListRaw}
+\alias{plotMD.EList}
+\alias{plotMD.MArrayLM}
+\alias{plotMD.default}
+
+\description{
+Creates a mean-difference plot (aka MA plot) with color coding for highlighted points.
+}
+
+\usage{
+\method{plotMD}{default}(object, column = 1, xlab = "Average log-expression",
+       ylab = "Expression log-ratio (this sample vs others)",
+       main = colnames(object)[column], status=NULL, \dots)
+\method{plotMD}{EList}(object, column = 1, array = NULL, xlab = "Average log-expression",
+       ylab = "Expression log-ratio (this sample vs others)",
+       main = colnames(object)[column], status=object$genes$Status,
+       zero.weights = FALSE, \dots)
+\method{plotMD}{RGList}(object, column = 1, array = NULL, xlab = "A", ylab = "M",
+       main = colnames(object)[column], status=object$genes$Status,
+       zero.weights = FALSE, \dots)
+\method{plotMD}{MAList}(object, column = 1, array = NULL, xlab = "A", ylab = "M",
+       main = colnames(object)[column], status=object$genes$Status,
+       zero.weights = FALSE, \dots)
+\method{plotMD}{MArrayLM}(object, column = ncol(object), coef = NULL, xlab = "Average log-expression",
+       ylab = "log-fold-change", main = colnames(object)[column],
+       status=object$genes$Status, zero.weights = FALSE, \dots)
+}
+
+\arguments{
+  \item{object}{an \code{RGList}, \code{MAList}, \code{EList}, \code{ExpressionSet} or \code{MArrayLM} object.
+  Alternatively a numeric \code{matrix}.}
+  \item{column}{integer, column of \code{object} to be plotted.}
+  \item{array}{alternative to \code{column} for microarray data objects. If specified, then \code{column} is ignored.}
+  \item{coef}{alternative to \code{column} for fitted model objects. If specified, then \code{column} is ignored.}
+  \item{xlab}{character string, label for x-axis}
+  \item{ylab}{character string, label for y-axis}
+  \item{main}{character string, title for plot}
+  \item{status}{vector giving the control status of each spot on the array, of same length as the number of rows of \code{object}.
+  If \code{NULL}, then all points are plotted in the default color, symbol and size.}
+  \item{zero.weights}{logical, should spots with zero or negative weights be plotted?}
+  \item{\dots}{other arguments are passed to \code{\link{plotWithHighlights}}.}
+}
+
+\details{
+A mean-difference plot (MD-plot) is a plot of log-intensity ratios (differences) versus log-intensity averages (means).
+For two color data objects, a within-array MD-plot is produced with the M and A values computed from the two channels for the specified array.
+This is the same as a mean-difference plot (\code{\link{mdplot}}) with the red and green log2-intensities of the array providing the two columns.
+
+For single channel data objects, a between-array MD-plot is produced.
+An articifial array is produced by averaging all the arrays other than the array specified.
+A mean-difference plot is then producing from the specified array and the artificial array.
+Note that this procedure reduces to an ordinary mean-difference plot when there are just two arrays total.
+
+If \code{object} is an \code{MArrayLM} object, then the plot is an fitted model MD-plot in which the estimated coefficient is on the y-axis and the average A-value is on the x-axis.
+
+The \code{status} vector can correspond to any grouping of the probes that is of interest.
+If \code{object} is a fitted model object, then \code{status} vector is often used to indicate statistically significance, so that differentially expressed points are highlighted.
+If \code{object} is a microarray data object, then \code{status} might distinguish control probes from regular probes so that different types of controls are highlighted.
+
+The \code{status} can be included as the component \code{object$genes$Status} instead of being passed as an argument to \code{plotMD}.
+
+See \code{\link{plotWithHighlights}} for how to set colors and graphics parameters for the highlighted and non-highlighted points.
+}
+
+\note{
+This function is an alternative to \code{plotMA}, which was one of the original functions of the limma package in 2002.
+The history of mean-difference plots and MA-plots is reviewed in Ritchie et al (2015).
+}
+
+\value{A plot is created on the current graphics device.}
+
+\references{
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} Volume 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
+}
+
+\author{Gordon Smyth}
+
+\examples{
+A <- runif(1000,4,16)
+y <- A + matrix(rnorm(1000*3,sd=0.2),1000,3)
+status <- rep(c(0,-1,1),c(950,40,10))
+y[,1] <- y[,1] + status
+plotMD(y, column=1, status=status, values=c(-1,1), hl.col=c("blue","red"))
+
+MA <- new("MAList")
+MA$A <- runif(300,4,16)
+MA$M <- rt(300,df=3)
+
+# Spike-in values
+MA$M[1:3] <- 0
+MA$M[4:6] <- 3
+MA$M[7:9] <- -3
+
+status <- rep("Gene",300)
+status[1:3] <- "M=0"
+status[4:6] <- "M=3"
+status[7:9] <- "M=-3"
+values <- c("M=0","M=3","M=-3")
+hl.col <- c("blue","red","green")
+
+plotMD(MA,main="MA-Plot with 12 spiked-in points",
+       status=status, values=values, hl.col=hl.col)
+
+#  Same as above but setting graphical parameters as attributes
+attr(status,"values") <- values
+attr(status,"col") <- hl.col
+plotMD(MA, main="Mean-Difference Plot with 12 spiked-in points", status=status)
+
+#  Same as above but passing status as part of object
+MA$genes$Status <- status
+plotMD(MA, main="Mean-Difference Plot with 12 spiked-in points")
+
+#  Change settings for background points
+MA$genes$Status <- status
+plotMD(MA, bg.pch=1, bg.cex=0.5)
+}
+
+\seealso{
+The driver function for \code{plotMD} is \code{\link{plotWithHighlights}}.
+See also \code{\link{mdplot}} for a very basic mean-difference plot function.
+
+An overview of plot functions available in LIMMA is given in \link{09.Diagnostics}.
+}
+
+\keyword{hplot}
diff --git a/man/plotMDS.Rd b/man/plotMDS.Rd
index 4db21df..5038e11 100644
--- a/man/plotMDS.Rd
+++ b/man/plotMDS.Rd
@@ -1,4 +1,4 @@
-\title{Multidimensional scaling plot of microarray data}
+\title{Multidimensional scaling plot of distances between gene expression profiles}
 \name{plotMDS}
 \alias{plotMDS}
 \alias{plotMDS.MDS}
@@ -7,29 +7,28 @@
 \alias{show,MDS-method}
 
 \description{
-Plot the sample relations based on multi-dimensional scaling (MDS).
-Distances on the plot can be interpreted in terms of \emph{leading log2-fold-change}.
+Plot samples on a two-dimensional scatterplot so that distances on the plot approximate the typical log2 fold changes between the samples.
 }
 
 \usage{
-\method{plotMDS}{default}(x, top=500, labels=NULL, pch=NULL, cex=1,
-     dim.plot=c(1,2), ndim=max(dim.plot), gene.selection="pairwise",
-     xlab=paste("Dimension",dim.plot[1]), ylab=paste("Dimension",dim.plot[2]), \dots)
-\method{plotMDS}{MDS}(x, labels=NULL, pch=NULL, cex=1, dim.plot=x$dim.plot,
-     xlab=paste("Dimension",dim.plot[1]), ylab=paste("Dimension",dim.plot[2]), \dots)
+\method{plotMDS}{default}(x, top = 500, labels = NULL, pch = NULL, cex = 1,
+     dim.plot = c(1,2), ndim = max(dim.plot), gene.selection = "pairwise",
+     xlab = NULL, ylab = NULL, \dots)
+\method{plotMDS}{MDS}(x, labels = NULL, pch = NULL, cex = 1, dim.plot = NULL,
+     xlab = NULL, ylab = NULL, \dots)
 }
 
 \arguments{
   \item{x}{any data object which can be coerced to a matrix, such as \code{ExpressionSet} or \code{EList}.}
   \item{top}{number of top genes used to calculate pairwise distances.}
-  \item{labels}{character vector of sample names or labels. If \code{x} has no column names, then defaults the index of the samples.}
+  \item{labels}{character vector of sample names or labels. Defaults to \code{colnames(x)}.}
   \item{pch}{plotting symbol or symbols. See \code{\link{points}} for possible values. Ignored if \code{labels} is non-\code{NULL}.}
   \item{cex}{numeric vector of plot symbol expansions.}
-  \item{dim.plot}{which two dimensions should be plotted, numeric vector of length two.}
-  \item{ndim}{number of dimensions in which data is to be represented}
-  \item{gene.selection}{character, \code{"pairwise"} to choose the top genes separately for each pairwise comparison between the samples or \code{"common"} to select the same genes for all comparisons}
-  \item{xlab}{title for the x-axis}
-  \item{ylab}{title for the y-axis}
+  \item{dim.plot}{integer vector of length two specifying which principal components should be plotted.}
+  \item{ndim}{number of dimensions in which data is to be represented.}
+  \item{gene.selection}{character, \code{"pairwise"} to choose the top genes separately for each pairwise comparison between the samples or \code{"common"} to select the same genes for all comparisons.}
+  \item{xlab}{title for the x-axis.}
+  \item{ylab}{title for the y-axis.}
   \item{\dots}{any other arguments are passed to \code{plot}, and also to \code{text} (if \code{pch} is \code{NULL}).}
 }
 
@@ -61,6 +60,13 @@ This is a list containing the following components:
 
 \author{Di Wu and Gordon Smyth}
 
+\references{
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
+}
+
 \seealso{
 \code{\link{cmdscale}}
 
diff --git a/man/plotSplice.Rd b/man/plotSplice.Rd
index 3dcb346..df88787 100644
--- a/man/plotSplice.Rd
+++ b/man/plotSplice.Rd
@@ -25,9 +25,10 @@ The significantly spliced individual exons are highlighted as red dots. The size
 \value{A plot is created on the current graphics device.}
 \author{Gordon Smyth and Yifang Hu}
 \seealso{
-\code{\link{diffSplice}}
+\code{\link{diffSplice}}, \code{\link{topSplice}}
 
-An overview of diagnostic functions available in LIMMA is given in \link{09.Diagnostics}.
+A summary of functions available in LIMMA for RNA-seq analysis is given in \link{11.RNAseq}.
 }
 \examples{# See diffSplice}
+\keyword{hplot}
 \keyword{rna-seq}
diff --git a/man/plotWithHighlights.Rd b/man/plotWithHighlights.Rd
new file mode 100644
index 0000000..d43981c
--- /dev/null
+++ b/man/plotWithHighlights.Rd
@@ -0,0 +1,96 @@
+\name{plotWithHighlights}
+\alias{plotWithHighlights}
+\title{Scatterplot With Highlighting of Special Points}
+\description{
+Creates scatterplot, with optional size and color coding for points of special interest.
+This is the engine for \code{plotMD} and \code{plotMA}.
+}
+\usage{
+plotWithHighlights(x, y, status = NULL, values = NULL,
+                   hl.pch = 16, hl.col = NULL, hl.cex = 1, legend = "topleft",
+                   bg.pch = 16, bg.col = "black", bg.cex = 0.3,
+                   pch = NULL, col = NULL, cex = NULL, \dots)
+}
+\arguments{
+  \item{x}{numeric vector.}
+
+  \item{y}{numeric vector.}
+
+  \item{status}{character vector giving the control status of each point, of same length as \code{x} and \code{y}.
+  If \code{NULL}, then all points are plotted in the background color, symbol and size.}
+
+  \item{values}{character vector giving values of \code{status} to be highlighted on the plot.
+  Defaults to unique values of \code{status} in decreasing order of frequency, with the most frequent value set as the background value.
+  Ignored if there is no \code{status} vector.}
+
+  \item{hl.pch}{vector of plotting characters for highlighted points, either of unit length or of same length as \code{values}.
+  Ignored is there is no \code{status} vector.}
+
+  \item{hl.col}{vector of colors for highlighted points, either of unit length or of same length as \code{values}.
+  Defaults to \code{1+1:length(values)}.
+  Ignored if there is no \code{status} vector.}
+
+  \item{hl.cex}{numeric vector of plot symbol expansions for highlighted points, either of unit length or of same length as \code{values}.
+  Ignored if there is no \code{status} vector.}
+
+  \item{legend}{character string giving position to place legend.
+  See \code{\link{legend}} for possible values.
+  Can also be logical, with \code{FALSE} meaning no legend.
+  Ignored if there is no \code{status} vector.}
+
+  \item{bg.pch}{plotting character for background (non-highlighted) points.}
+
+  \item{bg.col}{color for background (non-highlighted) points.}
+
+  \item{bg.cex}{plot symbol expansion for background (non-highlighted) points.}
+
+  \item{pch}{synonym for \code{hl.pch} allowed for backward compatibility.}
+
+  \item{col}{synonym for \code{hl.col} allowed for backward compatibility.}
+
+  \item{cex}{synonym for \code{hl.cex} allowed for backward compatibility.}
+
+  \item{\dots}{other arguments are passed to \code{plot}.}
+}
+
+\details{
+This function produces a scatterplot in which the highlighted points are, by default, larger and colored compared to background points.
+
+The \code{status} vector establishes the status of each point and \code{values} indicates which values of \code{status} should be highlighted.
+If \code{values=NULL}, then the most common value of \code{status} is assumed to correspond to background points and all other values are highlighted.
+
+The arguments \code{hl.pch}, \code{hl.col} and \code{hl.cex} give graphics settings for highlighted points.
+By default, highlighted points are larger than background points and a different color is used for each distinct highlighted value.
+
+The arguments \code{bg.pch}, \code{bg.col} and \code{bg.cex} give the graphics settings for non-highlighted (background) points.
+The same settings are used for all background points.
+
+The arguments \code{values}, \code{pch}, \code{col} and \code{cex} can be included as attributes to \code{status} instead of being passed as arguments to \code{plotWithHighlights}.
+This is for compatibility with \code{\link{controlStatus}}.
+
+See \code{\link[graphics]{points}} for possible values for the graphics parameters.
+}
+
+\value{A plot is created on the current graphics device.}
+
+\references{
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
+}
+
+\author{Gordon Smyth}
+
+\examples{
+x <- runif(1000, min=4, max=16)
+status <- rep(c(0,-1,1), c(950,40,10))
+y <- status + rnorm(1000, sd=0.2)
+plotWithHighlights(x, y, status=status)
+}
+
+\seealso{
+\code{\link{plotMD}}, \code{\link{plotMA}}, \code{\link{mdplot}}
+
+An overview of diagnostic plots available in LIMMA is given in \link{09.Diagnostics}.
+}
diff --git a/man/plotma.Rd b/man/plotma.Rd
index 139a609..383924e 100755
--- a/man/plotma.Rd
+++ b/man/plotma.Rd
@@ -1,8 +1,9 @@
-\title{MA-Plot}
+\title{MA-Plot of Expression Data}
 \name{plotMA}
 \alias{plotMA}
 \alias{plotMA.RGList}
 \alias{plotMA.MAList}
+\alias{plotMA.EListRaw}
 \alias{plotMA.EList}
 \alias{plotMA.MArrayLM}
 \alias{plotMA.default}
@@ -35,9 +36,9 @@ Creates an MA-plot with color coding for control spots.
   Alternatively a numeric \code{matrix}.}
   \item{array}{integer giving the array to be plotted.}
   \item{coef}{integer giving the linear model coefficient to be plotted.}
-  \item{xlab}{character string giving label for x-axis}
-  \item{ylab}{character string giving label for y-axis}
-  \item{main}{character string giving title for plot}
+  \item{xlab}{character string, label for x-axis}
+  \item{ylab}{character string, label for y-axis}
+  \item{main}{character string, title for plot}
   \item{status}{vector giving the control status of each spot on the array, of same length as the number of rows of \code{object}.
   If \code{NULL}, then all points are plotted in the default color, symbol and size.}
   \item{zero.weights}{logical, should spots with zero or negative weights be plotted?}
@@ -46,31 +47,49 @@ Creates an MA-plot with color coding for control spots.
 
 \details{
 An MA-plot is a plot of log-intensity ratios (M-values) versus log-intensity averages (A-values).
+See Ritchie et al (2015) for a brief historical review.
+
 For two color data objects, a within-array MA-plot is produced with the M and A values computed from the two channels for the specified array.
 This is the same as a mean-difference plot (\code{\link{mdplot}}) with the red and green log2-intensities of the array providing the two columns.
 
-For single channel data objects, then a between-array MA-plot is produced.
-An articifial array is produced by averaging all the arrays other than the array specified.
+For single channel data objects, a between-array MA-plot is produced.
+An artificial array is produced by averaging all the arrays other than the array specified.
 A mean-difference plot is then producing from the specified array and the artificial array.
 Note that this procedure reduces to an ordinary mean-difference plot when there are just two arrays total.
 
 If \code{object} is an \code{MArrayLM} object, then the plot is an fitted model MA-plot in which the estimated coefficient is on the y-axis and the average A-value is on the x-axis.
 
-The \code{status} vector is intended to specify the control status of each spot, for example \code{"gene"}, \code{"ratio control"}, \code{"house keeping gene"}, \code{"buffer"} and so on.
-The vector is often computed using the function \code{\link{controlStatus}} and a spot-types file.
-However the function may be used to highlight any subset of spots.
+The \code{status} vector can correspond to any grouping of the probes that is of interest.
+If \code{object} is a fitted model object, then \code{status} vector is often used to indicate statistically significance, so that differentially expressed points are highlighted.
+If \code{object} is a microarray data object, then \code{status} might distinguish control probes from regular probes so that different types of controls are highlighted.
 
 The \code{status} can be included as the component \code{object$genes$Status} instead of being passed as an argument to \code{plotMA}.
-The arguments \code{values}, \code{pch}, \code{col} and \code{cex} can be included as attributes to \code{status} instead of being passed as arguments to \code{plotMA}.
+
+See \code{\link{plotWithHighlights}} for how to set colors and graphics parameters for the highlighted and non-highlighted points.
+}
+
+\note{
+The \code{\link{plotMD}} function provides the same functionality as \code{plotMA} with slightly different arguments.
 }
 
 \value{A plot is created on the current graphics device.}
 
-\references{See \url{http://www.statsci.org/micrarra/refs/maplots.html}}
+\references{
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} Volume 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
+}
 
 \author{Gordon Smyth}
 
 \examples{
+A <- runif(1000,4,16)
+y <- A + matrix(rnorm(1000*3,sd=0.2),1000,3)
+status <- rep(c(0,-1,1),c(950,40,10))
+y[,1] <- y[,1] + status
+plotMA(y, array=1, status=status, values=c(-1,1), hl.col=c("blue","red"))
+
 MA <- new("MAList")
 MA$A <- runif(300,4,16)
 MA$M <- rt(300,df=3)
@@ -88,7 +107,7 @@ values <- c("M=0","M=3","M=-3")
 col <- c("blue","red","green")
 
 plotMA(MA,main="MA-Plot with 12 spiked-in points",
-       status=status, values=values, col=col)
+       status=status, values=values, hl.col=col)
 
 #  Same as above but setting graphical parameters as attributes
 attr(status,"values") <- values
@@ -101,11 +120,13 @@ plotMA(MA, main="MA-Plot with 12 spiked-in points")
 
 #  Change settings for background points
 MA$genes$Status <- status
-plotMA(MA, pch.bg=1, cex.bg=0.5)
+plotMA(MA, bg.pch=1, bg.cex=0.5)
 }
 
 \seealso{
-An overview of diagnostic functions available in LIMMA is given in \link{09.Diagnostics}.
+The driver function for \code{plotMA} is \code{\link{plotWithHighlights}}.
+
+An overview of plot functions available in LIMMA is given in \link{09.Diagnostics}.
 }
 
 \keyword{hplot}
diff --git a/man/plotma3by2.Rd b/man/plotma3by2.Rd
index 2ba7465..4c10108 100755
--- a/man/plotma3by2.Rd
+++ b/man/plotma3by2.Rd
@@ -37,6 +37,8 @@ The number of files is determined by the number of columns of \code{object}.
 \author{Gordon Smyth}
 
 \seealso{
+\code{\link[limma:plotma]{plotMA}}
+
 An overview of diagnostic functions available in LIMMA is given in \link{09.Diagnostics}.
 }
 \keyword{hplot}
diff --git a/man/predFCm.Rd b/man/predFCm.Rd
index 614b6e4..f60a0bf 100644
--- a/man/predFCm.Rd
+++ b/man/predFCm.Rd
@@ -3,24 +3,36 @@
 \alias{predFCm}
 \title{Predictive log fold change for microarrays}
 \description{
-Calculates the predictive log fold change for a particular coefficient from a fit object.
+Calculate the predictive log fold change for a particular coefficient from a fit object.
 }
 \usage{
-predFCm(fit,coef=2,prob=TRUE,VarRel=NULL)
+predFCm(fit, coef=2, var.indep.of.fc=TRUE, all.de=TRUE, prop.true.null.method="lfdr")
 }
+
 \arguments{
- \item{fit}{an \code{MArrayLM} fitted model object produced by \code{lmFit} or \code{contrasts.fit} and followed by \code{eBayes}}
- \item{coef}{integer indicating which contrasts/columns in the fit object are to be used}
- \item{prob}{logical, whether the probability that the gene is differentially expressed should be taken into account}
- \item{VarRel}{string, options are "Independent" or "Increasing"}
-  }
+ \item{fit}{an \code{MArrayLM} fitted model object produced by \code{lmFit} and \code{eBayes}}
+ \item{coef}{integer vector indicating which columns in the fit object are to be shrunk}
+ \item{var.indep.of.fc}{assume the genewise variances are independent of genewise fold changes?}
+ \item{all.de}{assume all genes are have a non-zero true fold change (\code{TRUE})?
+ If \code{FALSE}, then the proportion of truly non-differentially (non-DE) genes expressed will be estimated.}
+ \item{prop.true.null.method}{method used to estimate proportion of truly non-DE genes. See \code{\link{propTrueNull}} for possible values.}
+}
+
 \details{
-The predictive log fold changes are calculated as the posterior log fold changes in the empirical Bayes hierarchical model. The log fold changes are shrunk towards zero depending on how variable they are. The \code{VarRel} argument specifies whether the prior belief is that the log fold changes are independent of the variability of the genes (option "Independent"), or whether the log fold changes increase with increasing variability of the genes (option "Increasing"). The \code{prob} arg [...]
+The predictive log fold changes are calculated as the posterior mean log fold changes in the empirical Bayes hierarchical model.
+We call them predictive log fold changes because they are the best prediction of what the log fold change will be for each gene in a comparable future experiment.
+
+The log fold changes are shrunk towards zero depending on how variable they are.
+The \code{var.indep.of.fc} argument specifies whether the prior belief is that the log fold changes are independent of the variability of the genes or whether the log fold changes increase with increasing variability of the genes.
+
+If \code{all.de=TRUE}, then all genes are assumed to have a non-zero log fold change, even if quite small.
+If \code{all.de=FALSE}, then some genes are assumed to have log fold changes exactly zero.
+The proportion of non-DE genes is estimated and taken into account in the calculation.
 }
-\value{
-	\code{predFCm} produces a numeric vector corresponding to the predictive or posterior log fold changes of the specified contrast
- }
- \seealso{
+
+\value{numeric vector of predictive (shrunk) log fold changes}
+
+\seealso{
 \code{\link{lmFit}}, \code{\link{eBayes}}, \code{\link{contrasts.fit}}
 }
 
@@ -34,24 +46,19 @@ PhD Thesis. University of Melbourne, Australia.
 }
 
 \examples{
-library(limma)
 #  Simulate gene expression data,
 #  6 microarrays with 1000 genes on each array 
 set.seed(2004)
-y<-matrix(rnorm(6000),ncol=6)
+y <- matrix(rnorm(6000),ncol=4)
 
 # two experimental groups and one control group with two replicates each
-group<-factor(c("A","A","B","B","control","control"))
-design<-model.matrix(~0+group)
-colnames(design)<-c("A","B","control")
+group <- factor(c("A","A","B","B"))
+design <- model.matrix(~group)
 
 # fit a linear model
-fit<-lmFit(y,design)
-contrasts<-makeContrasts(A-control,B-control,levels=design)
-fit2<-contrasts.fit(fit,contrasts)
-fit2<-eBayes(fit2)
-
-# output predictive log fold changes for first contrast for first 5 genes
-pfc<-predFCm(fit2,coef=1,prob=FALSE)
-cbind(pfc[1:5],fit2$coeff[1:5,1])
-}
\ No newline at end of file
+fit <- lmFit(y,design)
+fit <- eBayes(fit)
+
+# output predictive log fold changes for first 5 genes
+pfc <- predFCm(fit,coef=2)
+}
diff --git a/man/propTrueNull.Rd b/man/propTrueNull.Rd
index f02d7f5..d0355c2 100644
--- a/man/propTrueNull.Rd
+++ b/man/propTrueNull.Rd
@@ -23,7 +23,7 @@ convest(p, niter=100, plot=FALSE, report=FALSE, file="", tol=1e-6)
   \item{report}{logical, should the estimated proportion be printed at each iteration?}
   \item{file}{name of file to which to write the report. Defaults to standard output.}
   \item{tol}{accuracy of the bisectional search for finding a new convex combination of the current iterate and the mixing density}
-  \item{\dots}{other arguments are passed to \code{convest} (if \code{method="convest"}.}
+  \item{\dots}{other arguments are passed to \code{convest} if \code{method="convest"}.}
 }
 
 \details{
@@ -61,6 +61,11 @@ Phipson, B (2013).
 Empirical Bayes Modelling of Expression Profiles and Their Associations.
 PhD Thesis, University of Melbourne, Australia.
 \url{http://repository.unimelb.edu.au/10187/17614}
+
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
 }
 
 \author{Belinda Phipson and Gordon Smyth for \code{propTrueNull}; Egil Ferkingstad, Mette Langaas and Marcus Davy for \code{convest}}
diff --git a/man/rankSumTestwithCorrelation.Rd b/man/rankSumTestwithCorrelation.Rd
index f9ff1ac..4ca3894 100644
--- a/man/rankSumTestwithCorrelation.Rd
+++ b/man/rankSumTestwithCorrelation.Rd
@@ -19,7 +19,7 @@ rankSumTestWithCorrelation(index, statistics, correlation=0, df=Inf)
 }
 
 \value{
-Numeric vector containing \code{left.tail} and \code{right.tail} p-values respectively.
+Numeric vector of length 2 containing the \code{left.tail} and \code{right.tail} p-values.
 }
 
 \details{
@@ -48,7 +48,8 @@ A statistical framework for testing functional categories in microarray data.
 \emph{Annals of Applied Statistics} 2, 286-315.
 
 Wu, D, and Smyth, GK (2012). Camera: a competitive gene set test accounting for inter-gene correlation.
-\emph{Nucleic Acids Research}. (Accepted 1 May 2012)
+\emph{Nucleic Acids Research} 40, e133.
+\url{http://nar.oxfordjournals.org/content/40/17/e133}
 
 Zar, JH (1999). \emph{Biostatistical Analysis 4th Edition}.
 Prentice-Hall International, Upper Saddle River, New Jersey.
diff --git a/man/read.idat.Rd b/man/read.idat.Rd
index a43967b..a2e247d 100644
--- a/man/read.idat.Rd
+++ b/man/read.idat.Rd
@@ -6,13 +6,14 @@
 \description{Read Illumina BeadArray data from IDAT and manifest (.bgx) files for gene expression platforms.}
 
 \usage{
-read.idat(idatfiles, bgxfile, dateinfo=FALSE)
+read.idat(idatfiles, bgxfile, dateinfo=FALSE, tolerance=0)
 }
 
 \arguments{
   \item{idatfiles}{character vector specifying idat files to be read in.}
   \item{bgxfile}{character string specifying bead manifest file (.bgx) to be read in.}
   \item{dateinfo}{logical. Should date and software version info be read in?}
+  \item{tolerance}{numeric. The number of probe ID discrepancies allowed between the manifest and a given idat file.} 
 }
 
 \details{
@@ -39,9 +40,9 @@ read.idat(idatfiles, bgxfile, dateinfo=FALSE)
 }
 
 \references{
-  Smith ML, Baggerly KA, Bengtsson H, Ritchie ME, Hansen KD (2013). 
-  illuminaio: An open source IDAT parsing tool. \emph{F1000 Research}, 2:264.
-  \url{http://f1000research.com/articles/2-264/v1}
+Smith ML, Baggerly KA, Bengtsson H, Ritchie ME, Hansen KD (2013). 
+illuminaio: An open source IDAT parsing tool. \emph{F1000 Research} 2, 264.
+\url{http://f1000research.com/articles/2-264/v1}
 }
 
 \author{Matt Ritchie}
diff --git a/man/read.maimages.Rd b/man/read.maimages.Rd
index 44f955d..5ff79ed 100755
--- a/man/read.maimages.Rd
+++ b/man/read.maimages.Rd
@@ -117,8 +117,15 @@ For two-color data, an \code{\link[limma:rglist]{RGList}} object containing the
   \item{source}{character string giving the image analysis program name}
   \item{printer}{list of class \code{\link[=PrintLayout-class]{PrintLayout}}, currently set only if \code{source="imagene"}}
 }
+
 \author{Gordon Smyth, with speed improvements suggested by Marcus Davy}
+
 \references{
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
+
 Web pages for the image analysis software packages mentioned here are listed at \url{http://www.statsci.org/micrarra/image.html}
 }
 \seealso{
diff --git a/man/readGPRHeader.Rd b/man/readGPRHeader.Rd
index 0930cfd..36aa0e8 100755
--- a/man/readGPRHeader.Rd
+++ b/man/readGPRHeader.Rd
@@ -29,13 +29,9 @@ A key component is \code{NHeaderRecords} which gives the number of lines in the
 All other components are character vectors.
 }
 \references{
-See
-\url{http://www.moleculardevices.com/Products/Software/GenePix-Pro.html} 
-or
-\url{http://www.cryer.co.uk/file-types/a/atf/genepix_file_formats.htm}
-for GenePix formats.
+See \url{http://www.cryer.co.uk/file-types/a/atf/genepix_file_formats.htm} for GenePix formats.
 
-See \url{http://http://smd.princeton.edu} for the SMD.
+See \url{http://smd.princeton.edu} for the SMD.
 }
 \author{Gordon Smyth}
 \seealso{\code{\link{read.maimages}}
diff --git a/man/readImaGeneHeader.Rd b/man/readImaGeneHeader.Rd
index db8c583..6650abf 100755
--- a/man/readImaGeneHeader.Rd
+++ b/man/readImaGeneHeader.Rd
@@ -22,7 +22,7 @@ See the ImaGene documentation for further information.
 The output object will also contain a component \code{NHeaderRecords}giving the number of lines in the file before the intensity data begins.
 }
 \references{
-\url{http://www.biodiscovery.com/imagene.asp}
+\url{http://www.biodiscovery.com/software/imagene}
 }
 \author{Gordon Smyth}
 \seealso{\code{\link{read.imagene}}
diff --git a/man/readgal.Rd b/man/readgal.Rd
index cd2ccb0..0e5273f 100755
--- a/man/readgal.Rd
+++ b/man/readgal.Rd
@@ -38,7 +38,7 @@ The data frame will be sorted so that \code{Column} is the fastest moving index,
 }
 \author{Gordon Smyth}
 \seealso{
-\link[marray:read.Galfile]{read.Galfile} in the marray package.
+\code{read.Galfile} in the marray package.
 
 An overview of LIMMA functions for reading data is given in \link{03.ReadingData}.
 }
diff --git a/man/rglist.Rd b/man/rglist.Rd
index 25348c4..8643798 100755
--- a/man/rglist.Rd
+++ b/man/rglist.Rd
@@ -48,7 +48,7 @@ Other functions in LIMMA which operate on \code{RGList} objects include
 \seealso{
   \link{02.Classes} gives an overview of all the classes defined by this package.
   
-  \code{\link[marray:marrayRaw-class]{marrayRaw}} is the corresponding class in the marray package.
+  \code{marrayRaw} is the corresponding class in the marray package.
 }
 
 \keyword{classes}
diff --git a/man/roast.Rd b/man/roast.Rd
index 05e3982..c4c64d3 100644
--- a/man/roast.Rd
+++ b/man/roast.Rd
@@ -5,19 +5,25 @@
 \alias{mroast.default}
 \alias{Roast-class}
 \alias{show,Roast-method}
+\alias{fry}
+\alias{fry.default}
 \title{Rotation Gene Set Tests}
 \description{
 Rotation gene set testing for linear models.
 }
 
 \usage{
-\S3method{roast}{default}(y, index=NULL, design=NULL, contrast=ncol(design), set.statistic="mean",
-     gene.weights=NULL, array.weights=NULL, weights=NULL, block=NULL, correlation,
-     var.prior=NULL, df.prior=NULL, trend.var=FALSE, nrot=999, approx.zscore=TRUE, \dots)
-\S3method{mroast}{default}(y, index=NULL, design=NULL, contrast=ncol(design), set.statistic="mean",
-     gene.weights=NULL, array.weights=NULL, weights=NULL, block=NULL, correlation,
-     var.prior=NULL, df.prior=NULL, trend.var=FALSE, nrot=999, approx.zscore=TRUE,
-     adjust.method="BH", midp=TRUE, sort="directional", \dots)
+\S3method{fry}{default}(y, index = NULL, design = NULL, contrast = ncol(design),
+      weights = NULL, sort = TRUE, \dots)
+\S3method{roast}{default}(y, index = NULL, design = NULL, contrast = ncol(design),
+      set.statistic = "mean", gene.weights = NULL, array.weights = NULL, weights = NULL,
+      block = NULL, correlation, var.prior = NULL, df.prior = NULL, trend.var = FALSE,
+      nrot = 999, approx.zscore = TRUE, \dots)
+\S3method{mroast}{default}(y, index = NULL, design = NULL, contrast = ncol(design),
+       set.statistic = "mean", gene.weights = NULL, array.weights = NULL, weights = NULL,
+       block = NULL, correlation, var.prior = NULL, df.prior = NULL, trend.var = FALSE,
+       nrot = 999, approx.zscore = TRUE, adjust.method = "BH", midp = TRUE,
+       sort = "directional", \dots)
 }
 
 \arguments{
@@ -40,7 +46,7 @@ Rotation gene set testing for linear models.
   \item{nrot}{number of rotations used to estimate the p-values.}
   \item{adjust.method}{method used to adjust the p-values for multiple testing. See \code{\link{p.adjust}} for possible values.}
   \item{midp}{logical, should mid-p-values be used in instead of ordinary p-values when adjusting for multiple testing?}
-  \item{sort}{character, whether to sort output table by directional p-value (\code{"directional"}), non-directional p-value (\code{"mixed"}), or not at all (\code{"none"}).}
+  \item{sort}{character, whether to sort output table by directional p-value (\code{"directional"}), non-directional p-value (\code{"mixed"}), or not at all (\code{"none"}).  For \code{fry} it is logical, whether to sort or not.}
   \item{approx.zscore}{logical, if \code{TRUE} then a fast approximation is used to convert t-statistics into z-scores prior to computing set statistics. If \code{FALSE}, z-scores will be exact.}
   \item{\dots}{other arguments not currently used.}
 }
@@ -103,6 +109,9 @@ This means that the smallest possible p-value is \code{1/(nrot+1)}.
 \code{mroast} does roast tests for multiple sets, including adjustment for multiple testing.
 By default, \code{mroast} reports ordinary p-values but uses mid-p-values (Routledge, 1994) at the multiple testing stage.
 Mid-p-values are probably a good choice when using false discovery rates (\code{adjust.method="BH"}) but not when controlling the family-wise type I error rate (\code{adjust.method="holm"}).
+
+\code{fry} is a fast version of \code{mroast} in the special case that \code{df.prior} is large and \code{set.statistic="mean"}.
+In this situation, it gives the same result as \code{mroast} with an infinite number of rotations.
 }
 
 \note{
@@ -110,9 +119,7 @@ The default setting for the set statistic was changed in limma 3.5.9 (3 June 201
 }
 
 \seealso{
-\code{\link{camera}}, \code{\link{romer}}, \code{\link{geneSetTest}}, \code{\link{ids2indices}}.
-
-There is a topic page on \link{10.GeneSetTests}.
+See \link{10.GeneSetTests} for a description of other functions used for gene set testing.
 }
 \author{Gordon Smyth and Di Wu}
 
diff --git a/man/romer.Rd b/man/romer.Rd
index 4fd5b2c..b5ec1b8 100644
--- a/man/romer.Rd
+++ b/man/romer.Rd
@@ -7,8 +7,8 @@
 Gene set enrichment analysis for linear models using rotation tests (ROtation testing using MEan Ranks).
 }
 \usage{
-\S3method{romer}{default}(y, index, design, contrast=ncol(design), array.weights=NULL,
-      block=NULL, correlation, set.statistic="mean", nrot=9999, \dots)
+\S3method{romer}{default}(y, index, design, contrast = ncol(design), array.weights = NULL, block = NULL,
+      correlation, set.statistic = "mean", nrot = 9999, shrink.resid = TRUE, \dots)
 }
 \arguments{
   \item{y}{numeric matrix giving log-expression values.}
@@ -20,6 +20,7 @@ Gene set enrichment analysis for linear models using rotation tests (ROtation te
   \item{correlation}{correlation between blocks.}
   \item{set.statistic}{statistic used to summarize the gene ranks for each set. Possible values are \code{"mean"}, \code{"floormean"} or \code{"mean50"}.}
   \item{nrot}{number of rotations used to estimate the p-values.}
+  \item{shrink.resid}{logical, should the residuals be shrunk to remove systematics effects before rotation.}
   \item{\dots}{other arguments not currently used.}
 }
 \value{
@@ -28,11 +29,11 @@ Rows correspond to gene sets.
 There are four columns giving the number of genes in the set and p-values for the alternative hypotheses mixed, up or down.
 }
 \details{
-This function implements the ROMER procedure described by Majewski et al (2010).
+This function implements the ROMER procedure described by Majewski et al (2010) and Ritchie et al (2015).
 \code{romer} tests a hypothesis similar to that of Gene Set Enrichment Analysis (GSEA) (Subramanian et al, 2005) but is designed for use with linear models.
 Like GSEA, it is designed for use with a database of gene sets.
 Like GSEA, it is a competitive test in that the different gene sets are pitted against one another.
-Instead of permutation, it uses rotation, a parametric resampling method suitable for linear models (Langsrud, 2005).
+Instead of permutation, it uses rotation, a parametric resampling method suitable for linear models (Langsrud, 2005; Wu et al, 2010).
 \code{romer} can be used with any linear model with some level of replication.
 
 Curated gene sets suitable for use with \code{romer} can be downloaded from
@@ -47,10 +48,10 @@ In this case, the test will be significant if the set contains mostly large test
 The first two alternatives are appropriate if you have a prior expection that all the genes in the set will react in the same direction.
 The "mixed" alternative is appropriate if you know only that the genes are involved in the relevant pathways, without knowing the direction of effect for each gene.
 
-Note that \code{romer} estimates p-values by simulation, specifically by random rotations of the orthogonalized residuals.
+Note that \code{romer} estimates p-values by simulation, specifically by random rotations of the orthogonalized residuals (called effects in R).
 This means that the p-values will vary slightly from run to run.
 To get more precise p-values, increase the number of rotations \code{nrot}.
-The strategy of random rotations is due to Langsrud (2005).
+By default, the orthogonalized residual corresponding to the contrast being tested is shrunk have the same expected squared size as a null residual.
 
 The argument \code{set.statistic} controls the way that t-statistics are summarized to form a summary test statistic for each set.
 In all cases, genes are ranked by moderated t-statistic.
@@ -59,6 +60,7 @@ If \code{set.statistic="floormean"} then negative t-statistics are put to zero b
 This improves the power for detecting genes with a subset of responding genes.
 If \code{set.statistics="mean50"}, the mean of the top 50\% ranks in each set is the summary statistic.
 This statistic performs well in practice but is slightly slower to compute.
+See Wu et al (2010) for discussion of these set statistics.
 }
 
 \seealso{
@@ -74,22 +76,28 @@ There is a topic page on \link{10.GeneSetTests}.
 
 
 \references{
-Langsrud, O, 2005.
+Langsrud, O (2005).
 Rotation tests.
 \emph{Statistics and Computing} 15, 53-60
 
-Doerum G, Snipen L, Solheim M, Saeboe S (2009).
-Rotation testing in gene set enrichment analysis for small direct comparison experiments.
-\emph{Stat Appl Genet Mol Biol}, Article 34.
-
 Majewski, IJ, Ritchie, ME, Phipson, B, Corbin, J, Pakusch, M, Ebert, A, Busslinger, M, Koseki, H, Hu, Y, Smyth, GK, Alexander, WS, Hilton, DJ, and Blewitt, ME (2010).
 Opposing roles of polycomb repressive complexes in hematopoietic stem and progenitor cells.
-\emph{Blood}, published online 5 May 2010.
+\emph{Blood} 116, 731-739.
 \url{http://www.ncbi.nlm.nih.gov/pubmed/20445021}
 
-Subramanian, A, Tamayo, P, Mootha, VK, Mukherjee, S, Ebert, BL, Gillette, MA, Paulovich, A, Pomeroy, SL, Golub, TR, Lander, ES and Mesirov JP, 2005.
+Ritchie, ME, Phipson, B, Wu, D, Hu, Y, Law, CW, Shi, W, and Smyth, GK (2015).
+limma powers differential expression analyses for RNA-sequencing and microarray studies.
+\emph{Nucleic Acids Research} 43, e47.
+\url{http://nar.oxfordjournals.org/content/43/7/e47}
+
+Subramanian, A, Tamayo, P, Mootha, VK, Mukherjee, S, Ebert, BL, Gillette, MA, Paulovich, A, Pomeroy, SL, Golub, TR, Lander, ES and Mesirov JP (2005).
 Gene set enrichment analysis: a knowledge-based approach for interpreting genome-wide expression profiles.
 \emph{Proc Natl Acad Sci U S A} 102, 15545-15550
+
+Wu, D, Lim, E, Francois Vaillant, F, Asselin-Labat, M-L, Visvader, JE, and Smyth, GK (2010).
+ROAST: rotation gene set tests for complex microarray experiments.
+\emph{Bioinformatics} 26, 2176-2182.
+\url{http://bioinformatics.oxfordjournals.org/content/26/17/2176}
 }
 
 \examples{
diff --git a/man/topGO.Rd b/man/topGO.Rd
index 360448c..54648c1 100644
--- a/man/topGO.Rd
+++ b/man/topGO.Rd
@@ -1,38 +1,46 @@
 \name{topGO}
 \alias{topGO}
-\title{Table of Top GO Terms}
+\alias{topKEGG}
+\title{Table of Top GO Terms or Top KEGG Pathways}
 
 \description{
-Extract top GO terms from goana results.
+Extract top GO terms from goana output or top KEGG terms from kegga output.
 }
 
 \usage{
-topGO(results, ontology = c("BP", "CC", "MF"), sort = NULL, number = 20L)
+topGO(results, ontology = c("BP", "CC", "MF"), sort = NULL, number = 20L, 
+      truncate.term = NULL)
+topKEGG(results, sort = NULL, number = 20L, truncate.term = NULL)
 }
 
 \arguments{
   \item{results}{data frame produced by \code{\link{goana}}.} 
   \item{ontology}{character vector of ontologies to be included in output.  Elements should be one or more of \code{"BP"}, \code{"CC"} or \code{"MF"}.}
-  \item{sort}{name of gene set for which results are required.  Should be one of the column names of \code{results}.  Defaults to first set.}
+  \item{sort}{character vector of names of gene lists for which results are required.  Should be one or more of the column names of \code{results}.  Defaults to all gene lists.}
   \item{number}{maximum number of top GO terms to list. For all terms, set \code{number=Inf}.}
+  \item{truncate.term}{truncate the name of the GO term at this number of characters.}
 }
 
 \details{
-This function is organize the output from \code{\link{goana}} into top-tables of the most significant GO terms.
+\code{topGO} organizes the output from \code{\link{goana}} into top-tables of the most significant GO terms.
+\code{topKEGG} similarly extracts the most significant KEGG pathways from \code{\link{kegga}} output. 
+In either case, rows are sorted by the minimum p-value of any of the result columns specified by \code{sort}.
 }
 
 \value{
-Same as \code{results} but with rows subsetted by Ontology and sorted by the specified p-value.
+Same as \code{results} but with rows subsetted by Ontology and sorted by p-value.
 }
 
 \seealso{
-\code{\link{goana}}, \code{\link{goana.MArrayLM}}
+\code{\link{goana}}, \code{\link{kegga}}
+
+See \link{10.GeneSetTests} for a description of other functions used for gene set testing.
 }
 
 \author{Gordon Smyth and Yifang Hu}
 
 \examples{
-# See goana and goana.MArrayLM examples
+# See goana examples
 }
 
 \keyword{gene set test}
diff --git a/man/topSplice.Rd b/man/topSplice.Rd
index 92207dc..509996d 100644
--- a/man/topSplice.Rd
+++ b/man/topSplice.Rd
@@ -41,7 +41,9 @@ The exon-level t-tests are not recommended for formal error rate control.
 
 \author{Gordon Smyth}
 \seealso{
-An overview of diagnostic functions available in LIMMA is given in \link{09.Diagnostics}.
+\code{\link{diffSplice}}, \code{\link{plotSplice}}
+
+A summary of functions available in LIMMA for RNA-seq analysis is given in \link{11.RNAseq}.
 }
 \examples{# See diffSplice}
 
diff --git a/man/toptable.Rd b/man/toptable.Rd
index 5c03114..e1ac722 100755
--- a/man/toptable.Rd
+++ b/man/toptable.Rd
@@ -95,6 +95,14 @@ Alternatively, by specifying \code{p.value} and \code{number=Inf}, all genes wit
 The argument \code{lfc} gives the ability to filter genes by log-fold change.
 This argument is not available for \code{topTreat} because \code{treat} already handles fold-change thresholding in a more sophisticated way.
 }
+\note{
+Although \code{topTable} enables users to set p-value and lfc cutoffs simultaneously, this is not generally recommended.
+If the fold changes and p-values are not highly correlated, then the use of a fold change cutoff can increase the false discovery rate above the nominal level.
+Users wanting to use fold change thresholding are usually recommended to use \code{treat} and \code{topTreat} instead.
+
+In general, the adjusted p-values returned by \code{adjust.method="BH"} remain valid as FDR bounds only when the genes remain sorted by p-value.
+Resorting the table by log-fold-change can increase the false discovery rate above the nominal level for genes at the top of resorted table.
+}
 \seealso{
 An overview of linear model and testing functions is given in \link{06.LinearModels}.
 See also \code{\link[stats]{p.adjust}} in the \code{stats} package.
diff --git a/man/venn.Rd b/man/venn.Rd
index 1eadbb8..7f8d6db 100755
--- a/man/venn.Rd
+++ b/man/venn.Rd
@@ -19,8 +19,8 @@ vennDiagram(object, include="both", names=NULL, mar=rep(1,4), cex=c(1.5,1,0.7),
   \item{mar}{numeric vector of length 4 specifying the width of the margins around the plot. This argument is passed to \code{par}.}
   \item{cex}{numerical vector of length 3 giving scaling factors for large, medium and small text on the plot.}
   \item{lwd}{numerical value giving the amount by which the circles should be scaled on the plot. See \code{par}.}
-  \item{circle.col}{vector of color specifications defining the colors by which the circles should be drawn. See \code{par}.}
-  \item{counts.col}{vector of color specifications, of same length as \code{include}, defining the colors by which the counts should be drawn. See \code{par}.}
+  \item{circle.col}{vector of colors for the circles. See \code{par} for possible values.}
+  \item{counts.col}{vector of colors for the counts. Of same length as \code{include}. See \code{par} for possible values.}
   \item{show.include}{logical value whether the value of \code{include} should be printed on the plot. Defaults to \code{FALSE} if \code{include} is a single value and \code{TRUE} otherwise}
   \item{\dots}{any other arguments are passed to \code{plot}}
 }
@@ -53,7 +53,10 @@ print(a)
 mfrow.old <- par()$mfrow
 par(mfrow=c(1,2))
 vennDiagram(a)
-vennDiagram(results,include=c("up","down"),counts.col=c("red","green"))
+vennDiagram(results, 
+    include=c("up", "down"),
+    counts.col=c("red", "blue"),
+    circle.col = c("red", "blue", "green3"))
 par(mfrow=mfrow.old)
 }
 
diff --git a/man/voom.Rd b/man/voom.Rd
index bafa114..af41d09 100644
--- a/man/voom.Rd
+++ b/man/voom.Rd
@@ -49,11 +49,6 @@ An \code{\link[limma:EList]{EList}} object with the following components:
 \author{Charity Law and Gordon Smyth}
 
 \references{
-Law, CW (2013).
-\emph{Precision weights for gene expression analysis}.
-PhD Thesis. University of Melbourne, Australia.
-\url{http://repository.unimelb.edu.au/10187/17598}
-
 Law, CW, Chen, Y, Shi, W, Smyth, GK (2014).
 Voom: precision weights unlock linear model analysis tools for RNA-seq read counts.
 \emph{Genome Biology} 15, R29.
@@ -61,9 +56,11 @@ Voom: precision weights unlock linear model analysis tools for RNA-seq read coun
 }
 
 \seealso{
-A \code{voom} case study is given in the User's Guide.
+\code{\link{voomWithQualityWeights}}
+
+A summary of functions for RNA-seq analysis is given in \link{11.RNAseq}.
 
-\code{\link{vooma}} is a similar function but for microarrays instead of RNA-seq.
+\code{\link{vooma}} is similar to \code{voom} but for microarrays instead of RNA-seq.
 }
 
 \keyword{rna-seq}
diff --git a/man/voomWithQualityWeights.Rd b/man/voomWithQualityWeights.Rd
index b59255f..6174f52 100644
--- a/man/voomWithQualityWeights.Rd
+++ b/man/voomWithQualityWeights.Rd
@@ -7,7 +7,7 @@ Combine voom observational-level weights with sample-specific quality weights in
 \usage{
 voomWithQualityWeights(counts, design=NULL, lib.size=NULL, normalize.method="none",
              plot=FALSE, span=0.5, var.design=NULL, method="genebygene", maxiter=50,
-             tol=1e-10, trace=FALSE, replace.weights=TRUE, ...) 
+             tol=1e-10, trace=FALSE, replace.weights=TRUE, col=NULL, ...) 
 }
 \arguments{
  \item{counts}{a numeric \code{matrix} containing raw counts, or an \code{ExpressionSet} containing raw counts, or a \code{DGEList} object.}
@@ -27,10 +27,11 @@ voomWithQualityWeights(counts, design=NULL, lib.size=NULL, normalize.method="non
  \item{tol}{convergence tolerance.}
  \item{trace}{logical variable. If true then output diagnostic information
           at each iteration of the '"reml"' algorithm, or at every 1000th iteration of the 
-          '"genebygene"' algorithm.}
+          \code{"genebygene"} algorithm.}
  \item{replace.weights}{logical variable. If TRUE then the weights in the voom object will be replaced with 
        the combined voom and sample-specific weights and the \code{\link[limma:EList]{EList}} object from voom is returned.
        If FALSE, then a matrix of combined weights is returned.}
+ \item{col}{colours to use in the barplot of sample-specific weights (only used if \code{plot=TRUE}). If \code{NULL}, bars are plotted in grey.}
  \item{\dots}{other arguments are passed to \code{lmFit}.}
 }
 \details{
@@ -39,34 +40,33 @@ This function is intended to process RNA-Seq data prior to linear modelling in l
 It combines observational-level weights from \code{voom} with sample-specific weights estimated using the \code{arrayWeights} function.
 }
 \value{
-	Either an \code{\link[limma:EList]{EList}} object with the following components:
-\item{E}{numeric matrix of normalized expression values on the log2 scale}
-\item{weights}{numeric matrix of inverse variance weights}
-\item{design}{design matrix}
-\item{lib.size}{numeric vector of total normalized library sizes}
-\item{genes}{dataframe of gene annotation extracted from \code{counts}}
-       or a matrix of combined voom and sample-specific weights with same dimension as \code{counts}.
+A numeric matrix of same dimension as \code{counts} containing consolidated voom and sample-specific weights.
+If \code{replace.weights=TRUE}, then an \code{\link[limma:EList]{EList}} object is returned with the \code{weights} component containing the consolidated weights.
 }
 
 \author{Matthew Ritchie and Cynthia Liu}
 
 \references{
-Ritchie, M. E., Diyagama, D., Neilson, van Laar, R., J., Dobrovic, A., Holloway, A., and Smyth, G. K. (2006).
-Empirical array quality weights in the analysis of microarray data.
-BMC Bioinformatics 7, 261.
-\url{http://www.biomedcentral.com/1471-2105/7/261/abstract}
-
-Law, CW, Chen, Y, Shi, W, Smyth, GK (2014).
+Law, C. W., Chen, Y., Shi, W., Smyth, G. K. (2014).
 Voom: precision weights unlock linear model analysis tools for RNA-seq read counts.
 \emph{Genome Biology} 15, R29.
 \url{http://genomebiology.com/2014/15/2/R29}
+
+Liu, R., Holik, A. Z., Su, S., Jansz, N., Chen, K., Leong, H. S., Blewitt, M. E., Asselin-Labat, M.-L., Smyth, G. K., Ritchie, M. E. (2015).
+Why weight? Combining voom with estimates of sample quality improves power in RNA-seq analyses.
+\emph{Nucleic Acids Research} 43.
+(Accepted 17 April 2015)
+
+Ritchie, M. E., Diyagama, D., Neilson, van Laar, R., J., Dobrovic, A., Holloway, A., and Smyth, G. K. (2006).
+Empirical array quality weights in the analysis of microarray data.
+\emph{BMC Bioinformatics} 7, 261.
+\url{http://www.biomedcentral.com/1471-2105/7/261}
 }
 
 \seealso{
 \code{\link{voom}}, \code{\link{arrayWeights}}
 
-An overview of linear model functions in limma is given by \link{06.LinearModels}.
-A \code{voomWithQualityWeights} case study is given in the User's Guide.
+A summary of functions for RNA-seq analysis is given in \link{11.RNAseq}.
 }
 
 \keyword{regression}
diff --git a/man/vooma.Rd b/man/vooma.Rd
index 6b1b6fc..654b39d 100644
--- a/man/vooma.Rd
+++ b/man/vooma.Rd
@@ -50,7 +50,7 @@ An EList object with the following components:
  }
 
 \seealso{
-\code{\link{voom}}
+\code{\link{voom}}, \code{\link{arrayWeights}}
 }
 
 \author{Charity Law and Gordon Smyth}
diff --git a/src/weighted_lowess.c b/src/weighted_lowess.c
index da02c0c..d1d96a8 100644
--- a/src/weighted_lowess.c
+++ b/src/weighted_lowess.c
@@ -5,7 +5,7 @@
 #define THRESHOLD 0.0000001
 
 /* This function determines the number of points to be used in the analysis,
- * based on the chosen delta. It returns that number as well as the index 
+ * based on the chosen delta. It returns that number as well as the index
  * values of those points in a pointer reference. Note that the first
  * and last point (i.e. smallest and largest) are always considered.
  */
@@ -13,7 +13,7 @@
 void find_seeds (int ** indices, int * number, const double* xptr, const int npts, const double delta) {
 	int pt, last_pt=0;
 	int total=2;
-	for (pt=1; pt<npts-1; ++pt) {	
+	for (pt=1; pt<npts-1; ++pt) {
 		if (xptr[pt] - xptr[last_pt] > delta) {
 			++total;
 			last_pt=pt;
@@ -34,18 +34,19 @@ void find_seeds (int ** indices, int * number, const double* xptr, const int npt
 		}
 	}
 	idptr[total]=npts-1;
+	++total;
 	(*indices)=idptr;
 	return;
 }
 
-/* This function identifies the start and end index in the span for each chosen sampling 
+/* This function identifies the start and end index in the span for each chosen sampling
  * point. It returns two arrays via reference containing said indices. It also returns
- * an array containing the maximum distance between points at each span. 
+ * an array containing the maximum distance between points at each span.
  *
- * We don't use the update-based algorithm in Cleveland's paper, as it ceases to be 
- * numerically stable once you throw in double-precision weights. It's not particularly 
+ * We don't use the update-based algorithm in Cleveland's paper, as it ceases to be
+ * numerically stable once you throw in double-precision weights. It's not particularly
  * amenable to updating through cycles of addition and subtraction. At any rate, the
- * algorithm as a whole remains quadratic (as weights must be recomputed) so there's no 
+ * algorithm as a whole remains quadratic (as weights must be recomputed) so there's no
  * damage to scalability.
  */
 
@@ -54,7 +55,7 @@ void find_limits (const int* indices, const int num, const double* xptr, const d
 	int* spbegin=(int*)R_alloc(num, sizeof(int));
 	int* spend=(int*)R_alloc(num, sizeof(int));
 	double* spdist=(double*)R_alloc(num, sizeof(double));
-	
+
 	int curx;
 	for (curx=0; curx<num; ++curx) {
 		const int curpt=indices[curx];
@@ -70,14 +71,14 @@ void find_limits (const int* indices, const int num, const double* xptr, const d
 				curw+=wptr[left];
 				if (left==0) { ends=1; }
 				ldist=xptr[curpt]-xptr[left];
-				if (mdist < ldist) { mdist=ldist; }	
+				if (mdist < ldist) { mdist=ldist; }
 			} else if (ends) {
 				/* Can only extend forwards. */
 				++right;
 				curw+=wptr[right];
 				if (right==npts-1) { ende=1; }
 				rdist=xptr[right]-xptr[curpt];
-				if (mdist < rdist) { mdist=rdist; }	
+				if (mdist < rdist) { mdist=rdist; }
 			} else {
 				/* Can do either; extending by the one that minimizes the curpt mdist. */
 				ldist=xptr[curpt]-xptr[left-1];
@@ -93,7 +94,7 @@ void find_limits (const int* indices, const int num, const double* xptr, const d
 					if (right==npts-1) { ende=1; }
 					if (mdist < rdist) { mdist=rdist; }
 				}
-			}		
+			}
 		}
 
 		/* Extending to ties. */
@@ -110,9 +111,9 @@ void find_limits (const int* indices, const int num, const double* xptr, const d
 	(*end)=spend;
 	(*dist)=spdist;
 	return;
-}	
+}
 
-/* Computes the lowess fit at a given point using linear regression with a combination of tricube, 
+/* Computes the lowess fit at a given point using linear regression with a combination of tricube,
  * prior and robustness weighting. Some additional effort is put in to avoid numerical instability
  * and undefined values when divisors are near zero.
  */
@@ -121,8 +122,8 @@ double lowess_fit (const double* xptr, const double* yptr, const double* wptr, c
 		const int npts, const int curpt, const int left, const int right, const double dist, double* work) {
 	double ymean=0, allweight=0;
 	int pt;
-	if (dist < THRESHOLD) { 
-		for (pt=left; pt<=right; ++pt) { 
+	if (dist < THRESHOLD) {
+		for (pt=left; pt<=right; ++pt) {
 			work[pt]=wptr[pt]*rwptr[pt];
 			ymean+=yptr[pt]*work[pt];
 			allweight+=work[pt];
@@ -131,8 +132,8 @@ double lowess_fit (const double* xptr, const double* yptr, const double* wptr, c
 		return ymean;
 	}
 	double xmean=0;
-	for (pt=left; pt<=right; ++pt) { 
-		work[pt]=pow(1-pow(fabs(xptr[curpt]-xptr[pt])/dist, 3.0), 3.0)*wptr[pt]*rwptr[pt]; 
+	for (pt=left; pt<=right; ++pt) {
+		work[pt]=pow(1-pow(fabs(xptr[curpt]-xptr[pt])/dist, 3.0), 3.0)*wptr[pt]*rwptr[pt];
 		xmean+=work[pt]*xptr[pt];
 		ymean+=work[pt]*yptr[pt];
 		allweight+=work[pt];
@@ -154,9 +155,9 @@ double lowess_fit (const double* xptr, const double* yptr, const double* wptr, c
 }
 
 /* This is a C version of the local weighted regression (lowess) trend fitting algorithm,
- * based on the Fortran code in lowess.f from http://www.netlib.org/go written by Cleveland. 
- * Consideration of non-equal prior weights is added to the span calculations and linear 
- * regression. These weights are intended to have the equivalent effect of frequency weights 
+ * based on the Fortran code in lowess.f from http://www.netlib.org/go written by Cleveland.
+ * Consideration of non-equal prior weights is added to the span calculations and linear
+ * regression. These weights are intended to have the equivalent effect of frequency weights
  * (at least, in the integer case; extended by analogy to all non-negative values).
  */
 
@@ -178,7 +179,7 @@ SEXP weighted_lowess(SEXP covariate, SEXP response, SEXP weight, SEXP span, SEXP
 	const int niter=INTEGER_VALUE(iter);
 	if (niter<=0) { error("number of robustness iterations should be positive"); }
 	if (!IS_NUMERIC(delta) || LENGTH(delta)!=1) { error("delta should be a double-precision scalar"); }
-	const double dv=NUMERIC_VALUE(delta); 
+	const double dv=NUMERIC_VALUE(delta);
 
 	/*** NO MORE ERRORS AT THIS POINT, MEMORY ASSIGNMENTS ARE ACTIVE. ***/
 
@@ -187,6 +188,7 @@ SEXP weighted_lowess(SEXP covariate, SEXP response, SEXP weight, SEXP span, SEXP
 	int pt;
 	for (pt=0; pt<npts; ++pt) { totalweight+=weiptr[pt]; }
 	double spanweight=totalweight*spv;
+	const double subrange=(covptr[npts-1]-covptr[0])/npts;
 
 	/* Setting up the indices of points for sampling; the frame start and end for those indices, and the max dist. */
 	int *seed_index;
@@ -198,35 +200,35 @@ SEXP weighted_lowess(SEXP covariate, SEXP response, SEXP weight, SEXP span, SEXP
 
 	/* Setting up arrays to hold the fitted values, residuals and robustness weights. */
 	SEXP output=PROTECT(NEW_LIST(2));
-	SET_VECTOR_ELT(output, 0, NEW_NUMERIC(npts));	
+	SET_VECTOR_ELT(output, 0, NEW_NUMERIC(npts));
 	double* fitptr=NUMERIC_POINTER(VECTOR_ELT(output, 0));
 	double* rsdptr=(double*)R_alloc(npts, sizeof(double));
 	SET_VECTOR_ELT(output, 1, NEW_NUMERIC(npts));
 	double* robptr=NUMERIC_POINTER(VECTOR_ELT(output, 1));
 	int* rorptr=(int*)R_alloc(npts, sizeof(int));
-	for (pt=0; pt<npts; ++pt) { robptr[pt]=1; } 
+	for (pt=0; pt<npts; ++pt) { robptr[pt]=1; }
 
 	/* Robustness iterations. */
 	int it=0;
-	for (it=0; it<niter; ++it) {	
+	for (it=0; it<niter; ++it) {
 		int cur_seed, last_pt=0, subpt;
 		double current;
 
 		/* Computing fitted values for seed points, and interpolating to the intervening points. */
 		fitptr[0]=lowess_fit(covptr, resptr, weiptr, robptr, npts, 0, frame_start[0], frame_end[0], max_dist[0], rsdptr);
-		for (cur_seed=1; cur_seed<nseeds; ++cur_seed) {	
+		for (cur_seed=1; cur_seed<nseeds; ++cur_seed) {
 			pt=seed_index[cur_seed];
-			fitptr[pt]=lowess_fit(covptr, resptr, weiptr, robptr, npts, pt, frame_start[cur_seed], 
+			fitptr[pt]=lowess_fit(covptr, resptr, weiptr, robptr, npts, pt, frame_start[cur_seed],
 				frame_end[cur_seed], max_dist[cur_seed], rsdptr); /* using rsdptr as a holding cell. */
 
 			if (pt-last_pt > 1) {
-	 			/* Some protection is provided against infinite slopes. This shouldn't be 
+	 			/* Some protection is provided against infinite slopes. This shouldn't be
  				 * a problem for non-zero delta; the only concern is at the final point
  				 * where the covariate distance may be zero. Besides, if delta is not
  				 * positive, pt-last_pt could never be 1 so we'd never reach this point.
  				 */
-				current = covptr[pt]-covptr[last_pt]; 
-				if (current > THRESHOLD) {
+				current = covptr[pt]-covptr[last_pt];
+				if (current > THRESHOLD*subrange) {
 					const double slope=(fitptr[pt]-fitptr[last_pt])/current;
 					const double intercept=fitptr[pt] - slope*covptr[pt];
 					for (subpt=last_pt+1; subpt<pt; ++subpt) { fitptr[subpt]=slope*covptr[subpt]+intercept; }
@@ -237,15 +239,19 @@ SEXP weighted_lowess(SEXP covariate, SEXP response, SEXP weight, SEXP span, SEXP
 			}
 			last_pt=pt;
 		}
-	
+
 		/* Computing the weighted MAD of the absolute values of the residuals. */
-		for (pt=0; pt<npts; ++pt) { 
-			rsdptr[pt]=fabs(resptr[pt]-fitptr[pt]); 
+		double resid_scale=0;
+		for (pt=0; pt<npts; ++pt) {
+			rsdptr[pt]=fabs(resptr[pt]-fitptr[pt]);
+			resid_scale+=rsdptr[pt];
 			rorptr[pt]=pt;
 		}
+		resid_scale/=npts;
 		rsort_with_index(rsdptr, rorptr, npts);
+
 		current=0;
-		double cmad=THRESHOLD;
+		double cmad=0;
 		const double halfweight=totalweight/2;
 		for (pt=0; pt<npts; ++pt) {
 			current+=weiptr[rorptr[pt]];
@@ -258,12 +264,18 @@ SEXP weighted_lowess(SEXP covariate, SEXP response, SEXP weight, SEXP span, SEXP
 			}
 		}
 
+		/* If it's too small, then robustness weighting will have no further effect.
+		 * Any points with large residuals would already be pretty lowly weighted.
+		 * This is based on a similar step in lowess.c in the core R code.
+		 */
+		if (cmad <= THRESHOLD * resid_scale) { break; }
+
 		/* Computing the robustness weights. */
 		for (pt=0; pt<npts; ++pt) {
 			if (rsdptr[pt]<cmad) {
 				robptr[rorptr[pt]]=pow(1-pow(rsdptr[pt]/cmad, 2.0), 2.0);
 			} else { robptr[rorptr[pt]]=0; }
-		}		
+		}
 	}
 
 	UNPROTECT(1);
diff --git a/tests/limma-Tests.R b/tests/limma-Tests.R
index 0a715e9..63597d3 100755
--- a/tests/limma-Tests.R
+++ b/tests/limma-Tests.R
@@ -273,5 +273,16 @@ summary(v$weights)
 
 ### goana
 
-go <- goana(fit,FDR=0.6,geneid=1:100)
+EB <- c("133746","1339","134","1340","134083","134111","134147","134187","134218","134266",
+"134353","134359","134391","134429","134430","1345","134510","134526","134549","1346",
+"134637","1347","134701","134728","1348","134829","134860","134864","1349","134957",
+"135","1350","1351","135112","135114","135138","135152","135154","1352","135228",
+"135250","135293","135295","1353","135458","1355","1356","135644","135656","1357",
+"1358","135892","1359","135924","135935","135941","135946","135948","136","1360",
+"136051","1361","1362","136227","136242","136259","1363","136306","136319","136332",
+"136371","1364","1365","136541","1366","136647","1368","136853","1369","136991",
+"1370","137075","1371","137209","1373","137362","1374","137492","1375","1376",
+"137682","137695","137735","1378","137814","137868","137872","137886","137902","137964")
+go <- goana(fit,FDR=0.8,geneid=EB)
 topGO(go,n=10)
+topGO(go,n=10,sort="down")
diff --git a/tests/limma-Tests.Rout.save b/tests/limma-Tests.Rout.save
index 33f6bb2..bbc91d6 100755
--- a/tests/limma-Tests.Rout.save
+++ b/tests/limma-Tests.Rout.save
@@ -1,6 +1,6 @@
 
-R Under development (unstable) (2014-07-19 r66202) -- "Unsuffered Consequences"
-Copyright (C) 2014 The R Foundation for Statistical Computing
+R version 3.2.0 (2015-04-16) -- "Full of Ingredients"
+Copyright (C) 2015 The R Foundation for Statistical Computing
 Platform: x86_64-w64-mingw32/x64 (64-bit)
 
 R is free software and comes with ABSOLUTELY NO WARRANTY.
@@ -912,7 +912,6 @@ A -1.715769 0.9181357 -6.307429 1.747263e-07 1.747263e-06 12.83865
 > ### duplicateCorrelation
 > 
 > cor.out <- duplicateCorrelation(M)
-Loading required package: statmod
 > cor.out$consensus.correlation
 [1] -0.09290714
 > cor.out$atanh.correlations
@@ -943,7 +942,6 @@ Loading required package: statmod
 > ### mrlm
 > 
 > fit <- mrlm(M,design)
-Loading required package: MASS
 Warning message:
 In rlm.default(x = X, y = y, weights = w, ...) :
   'rlm' failed to converge in 20 steps
@@ -1024,6 +1022,9 @@ alpha-beta  0.6666667 3.333333e-01 -3.333333e-01
 mu+alpha    0.3333333 3.333333e-01  5.551115e-17
 mu+beta    -0.3333333 5.551115e-17  3.333333e-01
 
+$rank
+[1] 3
+
 $Amean
 [1]  0.2034961  0.1954604 -0.2863347  0.1188659  0.1784593
 
@@ -1175,12 +1176,91 @@ Up                 1 0.0010005
 UpOrDown           1 0.0020000
 Mixed              1 0.0020000
 > mroast(y=y,list(set1=iset1,set2=iset2),design,contrast=2,gene.weights=runif(100))
-     NGenes PropDown PropUp Direction PValue    FDR PValue.Mixed FDR.Mixed
-set1      5        0      1        Up  0.008 0.0150        0.008    0.0150
-set2      5        0      0        Up  0.959 0.9585        0.687    0.6865
+     NGenes PropDown PropUp Direction PValue   FDR PValue.Mixed FDR.Mixed
+set1      5        0      1        Up  0.008 0.015        0.008     0.015
+set2      5        0      0        Up  0.959 0.959        0.687     0.687
 > mroast(y=y,list(set1=iset1,set2=iset2),design,contrast=2,array.weights=c(0.5,1,0.5,1))
-     NGenes PropDown PropUp Direction PValue    FDR PValue.Mixed FDR.Mixed
-set1      5      79276 0.06289638 -0.9004934
+     NGenes PropDown PropUp Direction PValue   FDR PValue.Mixed FDR.Mixed
+set1      5        0      1        Up  0.004 0.007        0.004     0.007
+set2      5        0      0        Up  0.679 0.679        0.658     0.658
+> mroast(y=y,list(set1=iset1,set2=iset2),design,contrast=2,weights=w)
+     NGenes PropDown PropUp Direction PValue   FDR PValue.Mixed FDR.Mixed
+set1      5      0.0      1        Up  0.003 0.005        0.003     0.005
+set2      5      0.2      0      Down  0.950 0.950        0.250     0.250
+> mroast(y=y,list(set1=iset1,set2=iset2),design,contrast=2,weights=w,array.weights=c(0.5,1,0.5,1))
+     NGenes PropDown PropUp Direction PValue   FDR PValue.Mixed FDR.Mixed
+set1      5        0      1        Up  0.001 0.001        0.001     0.001
+set2      5        0      0      Down  0.791 0.791        0.146     0.146
+> 
+> ### camera
+> 
+> camera(y=y,iset1,design,contrast=2,weights=c(0.5,1,0.5,1))
+     NGenes Correlation Direction      PValue
+set1      5  -0.2481655        Up 0.001050253
+> camera(y=y,list(set1=iset1,set2=iset2),design,contrast=2)
+     NGenes Correlation Direction       PValue        FDR
+set1      5  -0.2481655        Up 0.0009047749 0.00180955
+set2      5   0.1719094      Down 0.9068364381 0.90683644
+> 
+> ### with EList arg
+> 
+> y <- new("EList",list(E=y))
+> roast(y=y,iset1,design,contrast=2)
+         Active.Prop     P.Value
+Down               0 0.997498749
+Up                 1 0.003001501
+UpOrDown           1 0.006000000
+Mixed              1 0.006000000
+> camera(y=y,iset1,design,contrast=2)
+     NGenes Correlation Direction       PValue
+set1      5  -0.2481655        Up 0.0009047749
+> 
+> ### eBayes with trend
+> 
+> fit <- lmFit(y,design)
+> fit <- eBayes(fit,trend=TRUE)
+> topTable(fit,coef=2)
+       logFC     AveExpr         t      P.Value  adj.P.Val          B
+3   3.488703  1.03931081  4.860410 0.0002436118 0.01647958  0.6722078
+2   3.729512  1.73488969  4.700998 0.0003295917 0.01647958  0.3777787
+4   2.696676  1.74060725  3.280613 0.0053915597 0.17971866 -2.3313104
+1   2.391846  1.72305203  3.009776 0.0092611288 0.23152822 -2.8478458
+5   2.387967  1.63066783  2.786529 0.0144249169 0.26573834 -3.2671364
+33 -1.492317 -0.07525287 -2.735781 0.0159443006 0.26573834 -3.3613142
+80 -1.839760 -0.32802306 -2.594532 0.0210374835 0.30053548 -3.6207072
+95 -1.907074  1.26297763 -2.462009 0.0272186263 0.33449167 -3.8598265
+39  1.366141 -0.27360750  2.409767 0.0301042507 0.33449167 -3.9527943
+70 -1.789476  0.21771869 -2.184062 0.0462410739 0.46241074 -4.3445901
+> fit$df.prior
+[1] 12.17481
+> fit$s2.prior
+  [1] 0.7108745 0.7186517 0.3976222 0.7224388 0.6531157 0.3014062 0.3169880
+  [8] 0.3149772 0.3074632 0.2917431 0.3329334 0.3378027 0.2900500 0.3031741
+ [15] 0.3221763 0.2981580 0.2897078 0.2925188 0.2924234 0.3042822 0.2923686
+ [22] 0.2897022 0.3251669 0.2929813 0.4922090 0.2902725 0.3018205 0.3029119
+ [29] 0.3030051 0.3331358 0.3259651 0.2939051 0.3077824 0.3553515 0.3139985
+ [36] 0.3181689 0.3197601 0.4687993 0.3316536 0.2897621 0.2910744 0.2907116
+ [43] 0.2907966 0.3265722 0.3240487 0.3241126 0.3003970 0.3064187 0.3645035
+ [50] 0.2994391 0.3295512 0.2901076 0.2898658 0.3086659 0.2897209 0.2982976
+ [57] 0.3043910 0.2900320 0.3006936 0.2935101 0.3646949 0.3596385 0.3064203
+ [64] 0.3027439 0.3076483 0.3363356 0.3504336 0.3496698 0.2897618 0.2898810
+ [71] 0.3182290 0.3121707 0.2945001 0.2897549 0.3579410 0.3434376 0.3037970
+ [78] 0.3201893 0.3048412 0.3394079 0.3516034 0.3034589 0.3120384 0.3007827
+ [85] 0.3013925 0.2902524 0.3527793 0.2969359 0.3033756 0.3170187 0.2978833
+ [92] 0.2908437 0.3139422 0.3050183 0.4727609 0.2897104 0.2931671 0.2904177
+ [99] 0.3231607 0.2941699
+> summary(fit$s2.post)
+   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
+ 0.2518  0.2746  0.3080  0.3425  0.3583  0.7344 
+> 
+> y$E[1,1] <- NA
+> y$E[1,3] <- NA
+> fit <- lmFit(y,design)
+> fit <- eBayes(fit,trend=TRUE)
+> topTable(fit,coef=2)
+       logFC     AveExpr         t      P.Value  adj.P.Val          B
+3   3.488703  1.03931081  4.697008 0.0003209946 0.03209946  0.4203254
+2   3.729512  1.73488969  3.999120 0.0012579276 0.06289638 -0.9004934
 4   2.696676  1.74060725  2.813904 0.0135288060 0.39858921 -3.1693877
 33 -1.492317 -0.07525287 -2.731110 0.0159435682 0.39858921 -3.3232081
 80 -1.839760 -0.32802306 -2.589351 0.0210816889 0.42163378 -3.5833549
@@ -1239,81 +1319,64 @@ set1      5      79276 0.06289638 -0.9004934
 > 
 > ### goana
 > 
-> go <- goana(fit,FDR=0.6,geneid=1:100)
+> EB <- c("133746","1339","134","1340","134083","134111","134147","134187","134218","134266",
++ "134353","134359","134391","134429","134430","1345","134510","134526","134549","1346",
++ "134637","1347","134701","134728","1348","134829","134860","134864","1349","134957",
++ "135","1350","1351","135112","135114","135138","135152","135154","1352","135228",
++ "135250","135293","135295","1353","135458","1355","1356","135644","135656","1357",
++ "1358","135892","1359","135924","135935","135941","135946","135948","136","1360",
++ "136051","1361","1362","136227","136242","136259","1363","136306","136319","136332",
++ "136371","1364","1365","136541","1366","136647","1368","136853","1369","136991",
++ "1370","137075","1371","137209","1373","137362","1374","137492","1375","1376",
++ "137682","137695","137735","1378","137814","137868","137872","137886","137902","137964")
+> go <- goana(fit,FDR=0.8,geneid=EB)
 > topGO(go,n=10)
-                                                                   Term Ont N
-GO:0001867                        complement activation, lectin pathway  BP 1
-GO:0001868          regulation of complement activation, lectin pathway  BP 1
-GO:0001869 negative regulation of complement activation, lectin pathway  BP 1
-GO:0002020                                             protease binding  MF 1
-GO:0002673                    regulation of acute inflammatory response  BP 1
-GO:0002920                        regulation of humoral immune response  BP 1
-GO:0002921               negative regulation of humoral immune response  BP 1
-GO:0006102                                 isocitrate metabolic process  BP 1
-GO:0006956                                        complement activation  BP 1
-GO:0006959                                      humoral immune response  BP 1
-           Up Down   P.Up P.Down
-GO:0001867  1    0 0.0625      1
-GO:0001868  1    0 0.0625      1
-GO:0001869  1    0 0.0625      1
-GO:0002020  1    0 0.0625      1
-GO:0002673  1    0 0.0625      1
-GO:0002920  1    0 0.0625      1
-GO:0002921  1    0 0.0625      1
-GO:0006102  1    0 0.0625      1
-GO:0006956  1    0 0.0625      1
-GO:0006959  1    0 0.0625      1
+                                                                       Term Ont
+GO:0055082                                    cellular chemical homeostasis  BP
+GO:0006897                                                      endocytosis  BP
+GO:0019725                                             cellular homeostasis  BP
+GO:0006915                                                apoptotic process  BP
+GO:0012501                                            programmed cell death  BP
+GO:0008283                                               cell proliferation  BP
+GO:0042127                                 regulation of cell proliferation  BP
+GO:0097190                                      apoptotic signaling pathway  BP
+GO:0006909                                                     phagocytosis  BP
+GO:0007169 transmembrane receptor protein tyrosine kinase signaling pathway  BP
+           N Up Down        P.Up      P.Down
+GO:0055082 2  0    2 1.000000000 0.004242424
+GO:0006897 3  3    0 0.005046382 1.000000000
+GO:0019725 3  0    2 1.000000000 0.012294372
+GO:0006915 4  3    1 0.017844424 0.255402330
+GO:0012501 4  3    1 0.017844424 0.255402330
+GO:0008283 4  1    2 0.553950615 0.023749721
+GO:0042127 4  1    2 0.553950615 0.023749721
+GO:0097190 2  2    0 0.030909091 1.000000000
+GO:0006909 2  2    0 0.030909091 1.000000000
+GO:0007169 2  2    0 0.030909091 1.000000000
+> topGO(go,n=10,sort="down")
+                                                Term Ont  N Up Down      P.Up
+GO:0055082             cellular chemical homeostasis  BP  2  0    2 1.0000000
+GO:0019725                      cellular homeostasis  BP  3  0    2 1.0000000
+GO:0008283                        cell proliferation  BP  4  1    2 0.5539506
+GO:0042127          regulation of cell proliferation  BP  4  1    2 0.5539506
+GO:0048878                      chemical homeostasis  BP  5  1    2 0.6375849
+GO:0032502                     developmental process  BP 22  3    4 0.8185069
+GO:0048519 negative regulation of biological process  BP 14  2    3 0.7685153
+GO:0043230                   extracellular organelle  CC 14  1    3 0.9502416
+GO:0065010  extracellular membrane-bounded organelle  CC 14  1    3 0.9502416
+GO:0070062           extracellular vesicular exosome  CC 14  1    3 0.9502416
+                P.Down
+GO:0055082 0.004242424
+GO:0019725 0.012294372
+GO:0008283 0.023749721
+GO:0042127 0.023749721
+GO:0048878 0.038228009
+GO:0032502 0.040079017
+GO:0048519 0.055161144
+GO:0043230 0.055161144
+GO:0065010 0.055161144
+GO:0070062 0.055161144
 > 
 > proc.time()
    user  system elapsed 
-   5.89    0.21    6.10 
-                                                                                                                                           limma/vignettes/                                                                                    0000755 0001263 0001264 00000000000 12421323653 015245  5                                                                                                    ustar 00biocbuild                       phs_compbio                                              [...]
-%\VignetteDepends{}
-%\VignetteKeywords{microarray linear model}
-%\VignettePackage{limma}
-\documentclass[12pt]{article}
-
-\textwidth=6.2in
-\textheight=8.5in
-\oddsidemargin=0.2in
-\evensidemargin=0.2in
-\headheight=0in
-\headsep=0in
-
-\begin{document}
-\title{Limma Package Introduction}
-\author{Gordon Smyth}
-\date{23 October 2004, Revised 21 October 2013}
-\maketitle
-
-Limma is an R package for the analysis of gene expression microarray data, especially the use of linear models for analysing designed experiments and the assessment of differential expression.
-Limma provides the ability to analyse comparisons between many RNA targets simultaneously in arbitrary complicated designed experiments.
-Empirical Bayesian methods are used to provide stable results even when the number of arrays is small.
-The normalization and data analysis functions are for two-color spotted microarrays.
-The linear model and differential expression functions apply to all microarray technologies including Affymetrix and other single-channel oligonucleotide platforms.
-
-The full Limma User's Guide is available as part of the online documentation.
-To reach the User's Guide you need to install the limma package.
-If you've installed the package and you're using Windows, type \texttt{library(limma)} at the R prompt then click on ``limma'' from the drop-down menu called ``Vignettes''.
-If you're not using Windows, you can type
-\begin{Schunk}
-\begin{Sinput}
-> library(limma)
-> limmaUsersGuide()
-\end{Sinput}
-\end{Schunk}
-or alternatively
-\begin{Schunk}
-\begin{Sinput}
-> help.start()
-\end{Sinput}
-\end{Schunk}
-and follow the links to the limma package help.
-
-\end{document}
-
-
-
-
-
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             [...]
\ No newline at end of file
+   3.08    0.17    4.02 
diff --git a/vignettes/intro.Rnw b/vignettes/intro.Rnw
new file mode 100644
index 0000000..88f952a
--- /dev/null
+++ b/vignettes/intro.Rnw
@@ -0,0 +1,49 @@
+%\VignetteIndexEntry{Limma One Page Introduction}
+%\VignetteDepends{}
+%\VignetteKeywords{microarray linear model}
+%\VignettePackage{limma}
+\documentclass[12pt]{article}
+
+\textwidth=6.2in
+\textheight=8.5in
+\oddsidemargin=0.2in
+\evensidemargin=0.2in
+\headheight=0in
+\headsep=0in
+
+\begin{document}
+\title{Limma Package Introduction}
+\author{Gordon Smyth}
+\date{23 October 2004, Revised 21 October 2013}
+\maketitle
+
+Limma is an R package for the analysis of gene expression microarray data, especially the use of linear models for analysing designed experiments and the assessment of differential expression.
+Limma provides the ability to analyse comparisons between many RNA targets simultaneously in arbitrary complicated designed experiments.
+Empirical Bayesian methods are used to provide stable results even when the number of arrays is small.
+The normalization and data analysis functions are for two-color spotted microarrays.
+The linear model and differential expression functions apply to all microarray technologies including Affymetrix and other single-channel oligonucleotide platforms.
+
+The full Limma User's Guide is available as part of the online documentation.
+To reach the User's Guide you need to install the limma package.
+If you've installed the package and you're using Windows, type \texttt{library(limma)} at the R prompt then click on ``limma'' from the drop-down menu called ``Vignettes''.
+If you're not using Windows, you can type
+\begin{Schunk}
+\begin{Sinput}
+> library(limma)
+> limmaUsersGuide()
+\end{Sinput}
+\end{Schunk}
+or alternatively
+\begin{Schunk}
+\begin{Sinput}
+> help.start()
+\end{Sinput}
+\end{Schunk}
+and follow the links to the limma package help.
+
+\end{document}
+
+
+
+
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-bioc-limma.git



More information about the debian-med-commit mailing list