[R-gregmisc-users] SF.net SVN: r-gregmisc:[1317] trunk/gplots
Brought to you by:
warnes
From: <wa...@us...> - 2009-05-08 21:55:20
|
Revision: 1317 http://r-gregmisc.svn.sourceforge.net/r-gregmisc/?rev=1317&view=rev Author: warnes Date: 2009-05-08 21:55:05 +0000 (Fri, 08 May 2009) Log Message: ----------- heatmap.2: Add option to create breakpoints symmetric around 0, provide additional information in the return value Modified Paths: -------------- trunk/gplots/R/heatmap.2.R trunk/gplots/man/heatmap.2.Rd trunk/gplots/tests/heatmap2Test.Rout.save Modified: trunk/gplots/R/heatmap.2.R =================================================================== --- trunk/gplots/R/heatmap.2.R 2009-05-08 21:27:55 UTC (rev 1316) +++ trunk/gplots/R/heatmap.2.R 2009-05-08 21:55:05 UTC (rev 1317) @@ -1,164 +1,177 @@ -# $Id$ +## $Id$ heatmap.2 <- function (x, - # dendrogram control - Rowv = TRUE, - Colv=if(symm)"Rowv" else TRUE, - distfun = dist, - hclustfun = hclust, - dendrogram = c("both","row","column","none"), - symm = FALSE, + ## dendrogram control + Rowv = TRUE, + Colv=if(symm)"Rowv" else TRUE, + distfun = dist, + hclustfun = hclust, + dendrogram = c("both","row","column","none"), + symm = FALSE, - # data scaling - scale = c("none","row", "column"), - na.rm=TRUE, + ## data scaling + scale = c("none","row", "column"), + na.rm=TRUE, - # image plot - revC = identical(Colv, "Rowv"), - add.expr, - breaks, - col="heat.colors", + ## image plot + revC = identical(Colv, "Rowv"), + add.expr, - # block sepration - colsep, - rowsep, - sepcolor="white", - sepwidth=c(0.05,0.05), + ## mapping data to colors + breaks, + symbreaks=min(x < 0, na.rm=TRUE) || scale!="none", - # cell labeling - cellnote, - notecex=1.0, - notecol="cyan", - na.color=par("bg"), + ## colors + col="heat.colors", - # level trace - trace=c("column","row","both","none"), - tracecol="cyan", - hline=median(breaks), - vline=median(breaks), - linecol=tracecol, + ## block sepration + colsep, + rowsep, + sepcolor="white", + sepwidth=c(0.05,0.05), - # Row/Column Labeling - margins = c(5, 5), - ColSideColors, - RowSideColors, - cexRow = 0.2 + 1/log10(nr), - cexCol = 0.2 + 1/log10(nc), - labRow = NULL, - labCol = NULL, + ## cell labeling + cellnote, + notecex=1.0, + notecol="cyan", + na.color=par("bg"), - # color key + density info - key = TRUE, - keysize = 1.5, - density.info=c("histogram","density","none"), - denscol=tracecol, - #symkey = TRUE, # should be something like - symkey = min(x < 0, na.rm=TRUE), - densadj = 0.25, + ## level trace + trace=c("column","row","both","none"), + tracecol="cyan", + hline=median(breaks), + vline=median(breaks), + linecol=tracecol, - # plot labels - main = NULL, - xlab = NULL, - ylab = NULL, + ## Row/Column Labeling + margins = c(5, 5), + ColSideColors, + RowSideColors, + cexRow = 0.2 + 1/log10(nr), + cexCol = 0.2 + 1/log10(nc), + labRow = NULL, + labCol = NULL, - # plot layout - lmat = NULL, - lhei = NULL, - lwid = NULL, + ## color key + density info + key = TRUE, + keysize = 1.5, + density.info=c("histogram","density","none"), + denscol=tracecol, + symkey = min(x < 0, na.rm=TRUE) || symbreaks, + densadj = 0.25, - # extras - ... - ) + ## plot labels + main = NULL, + xlab = NULL, + ylab = NULL, + + ## plot layout + lmat = NULL, + lhei = NULL, + lwid = NULL, + + ## extras + ... + ) { scale01 <- function(x, low=min(x), high=max(x) ) { x <- (x-low)/(high - low) x } + + retval <- list() + + scale <- if(symm && missing(scale)) "none" else match.arg(scale) + dendrogram <- match.arg(dendrogram) + trace <- match.arg(trace) + density.info <- match.arg(density.info) - scale <- if(symm && missing(scale)) "none" else match.arg(scale) - dendrogram <- match.arg(dendrogram) - trace <- match.arg(trace) - density.info <- match.arg(density.info) + if(length(col)==1 && is.character(col) ) + col <- get(col, mode="function") - if(!missing(breaks) && (scale!="none")) - warning("Using scale=\"row\" or scale=\"column\" when breaks are", - "specified can produce unpredictable results.", - "Please consider using only one or the other.") + if(!missing(breaks) && (scale!="none")) + warning("Using scale=\"row\" or scale=\"column\" when breaks are", + "specified can produce unpredictable results.", + "Please consider using only one or the other.") - # key & density don't make sense when data is not all on the same scale -# if(scale!="none" && key==TRUE) -# { -# warning("Key cannot be plotted when scale!=\"none\".") -# key=FALSE -# } + ## key & density don't make sense when data is not all on the same scale + ## if(scale!="none" && key==TRUE) + ## { + ## warning("Key cannot be plotted when scale!=\"none\".") + ## key=FALSE + ## } - - - if ( (Colv=="Rowv") && (!isTRUE(Rowv) || is.null(Rowv) ) ) + if ( is.null(Rowv) ) + Rowv <- FALSE + if ( is.null(Colv) ) Colv <- FALSE + else if( Colv=="Rowv" && !isTRUE(Rowv) ) + Colv <- FALSE - if(length(di <- dim(x)) != 2 || !is.numeric(x)) - stop("`x' must be a numeric matrix") + + if(length(di <- dim(x)) != 2 || !is.numeric(x)) + stop("`x' must be a numeric matrix") - nr <- di[1] - nc <- di[2] + nr <- di[1] + nc <- di[2] - if(nr <= 1 || nc <= 1) - stop("`x' must have at least 2 rows and 2 columns") + if(nr <= 1 || nc <= 1) + stop("`x' must have at least 2 rows and 2 columns") - if(!is.numeric(margins) || length(margins) != 2) - stop("`margins' must be a numeric vector of length 2") + if(!is.numeric(margins) || length(margins) != 2) + stop("`margins' must be a numeric vector of length 2") - if(missing(cellnote)) - cellnote <- matrix("", ncol=ncol(x), nrow=nrow(x)) + if(missing(cellnote)) + cellnote <- matrix("", ncol=ncol(x), nrow=nrow(x)) - if(!inherits(Rowv, "dendrogram")) { - ## Check if Rowv and dendrogram arguments are consistent - if ( ( (!isTRUE(Rowv)) || (is.null(Rowv))) && (dendrogram %in% c("both","row") ) ) - { - if (is.logical(Colv) && (Colv)) - dendrogram <- "column" - else - dedrogram <- "none" - - warning("Discrepancy: Rowv is FALSE, while dendrogram is `", - dendrogram, "'. Omitting row dendogram.") - + if(!inherits(Rowv, "dendrogram")) { + ## Check if Rowv and dendrogram arguments are consistent + if ( ( (!isTRUE(Rowv)) || (is.null(Rowv))) && + (dendrogram %in% c("both","row") ) ) + { + if (is.logical(Colv) && (Colv)) + dendrogram <- "column" + else + dedrogram <- "none" + + warning("Discrepancy: Rowv is FALSE, while dendrogram is `", + dendrogram, "'. Omitting row dendogram.") + + } } -} - if(!inherits(Colv, "dendrogram")) { - ## Check if Colv and dendrogram arguments are consistent - if ( ( (!isTRUE(Colv)) || (is.null(Colv))) - && (dendrogram %in% c("both","column")) ) - { - if (is.logical(Rowv) && (Rowv)) - dendrogram <- "row" - else - dendrogram <- "none" - - warning("Discrepancy: Colv is FALSE, while dendrogram is `", - dendrogram, "'. Omitting column dendogram.") - } -} + if(!inherits(Colv, "dendrogram")) { + ## Check if Colv and dendrogram arguments are consistent + if ( ( (!isTRUE(Colv)) || (is.null(Colv))) + && (dendrogram %in% c("both","column")) ) + { + if (is.logical(Rowv) && (Rowv)) + dendrogram <- "row" + else + dendrogram <- "none" + + warning("Discrepancy: Colv is FALSE, while dendrogram is `", + dendrogram, "'. Omitting column dendogram.") + } + } ## by default order by row/col mean ## if(is.null(Rowv)) Rowv <- rowMeans(x, na.rm = na.rm) ## if(is.null(Colv)) Colv <- colMeans(x, na.rm = na.rm) - ## get the dendrograms and reordering indices + ## get the dendrograms and reordering indices - ## if( dendrogram %in% c("both","row") ) - ## { ## dendrogram option is used *only* for display purposes + ## if( dendrogram %in% c("both","row") ) + ## { ## dendrogram option is used *only* for display purposes if(inherits(Rowv, "dendrogram")) { ddr <- Rowv ## use Rowv 'as-is', when it is dendrogram rowInd <- order.dendrogram(ddr) } -else if (is.integer(Rowv)) + else if (is.integer(Rowv)) { ## Compute dendrogram and do reordering based on given vector hcr <- hclustfun(distfun(x)) ddr <- as.dendrogram(hcr) @@ -208,308 +221,342 @@ if(nc != length(colInd)) stop("column dendrogram ordering gave index of wrong length") } -else if (isTRUE(Colv)) - {## If TRUE, compute dendrogram and do reordering based on rowMeans - Colv <- colMeans(x, na.rm = na.rm) - hcc <- hclustfun(distfun(if(symm)x else t(x))) - ddc <- as.dendrogram(hcc) - ddc <- reorder(ddc, Colv) + else if (isTRUE(Colv)) + {## If TRUE, compute dendrogram and do reordering based on rowMeans + Colv <- colMeans(x, na.rm = na.rm) + hcc <- hclustfun(distfun(if(symm)x else t(x))) + ddc <- as.dendrogram(hcc) + ddc <- reorder(ddc, Colv) - colInd <- order.dendrogram(ddc) - if(nc != length(colInd)) - stop("column dendrogram ordering gave index of wrong length") - } -else - { - colInd <- 1:nc - } + colInd <- order.dendrogram(ddc) + if(nc != length(colInd)) + stop("column dendrogram ordering gave index of wrong length") + } + else + { + colInd <- 1:nc + } + + retval$rowInd <- rowInd + retval$colInd <- colInd + retval$call <- match.call() + - ## reorder x & cellnote - x <- x[rowInd, colInd] - x.unscaled <- x - cellnote <- cellnote[rowInd, colInd] + ## reorder x & cellnote + x <- x[rowInd, colInd] + x.unscaled <- x + cellnote <- cellnote[rowInd, colInd] - if(is.null(labRow)) - labRow <- if(is.null(rownames(x))) (1:nr)[rowInd] else rownames(x) - else - labRow <- labRow[rowInd] + if(is.null(labRow)) + labRow <- if(is.null(rownames(x))) (1:nr)[rowInd] else rownames(x) + else + labRow <- labRow[rowInd] - if(is.null(labCol)) - labCol <- if(is.null(colnames(x))) (1:nc)[colInd] else colnames(x) - else - labCol <- labCol[colInd] + if(is.null(labCol)) + labCol <- if(is.null(colnames(x))) (1:nc)[colInd] else colnames(x) + else + labCol <- labCol[colInd] - if(scale == "row") { - x <- sweep(x, 1, rowMeans(x, na.rm = na.rm)) - sx <- apply(x, 1, sd, na.rm = na.rm) - x <- sweep(x, 1, sx, "/") - } - else if(scale == "column") { - x <- sweep(x, 2, colMeans(x, na.rm = na.rm)) - sx <- apply(x, 2, sd, na.rm = na.rm) - x <- sweep(x, 2, sx, "/") - } + if(scale == "row") { + retval$rowMeans <- rm <- rowMeans(x, na.rm = na.rm) + x <- sweep(x, 1, rm) + retval$rowSDs <- sx <- apply(x, 1, sd, na.rm = na.rm) + x <- sweep(x, 1, sx, "/") + } + else if(scale == "column") { + retval$colMeans <- rm <- colMeans(x, na.rm = na.rm) + x <- sweep(x, 2, rm) + retval$colSDs <- sx <- apply(x, 2, sd, na.rm = na.rm) + x <- sweep(x, 2, sx, "/") + } - ## Set up breaks and force values outside the range into the endmost bins - if(missing(breaks) || is.null(breaks) || length(breaks)<1 ) - if(missing(col)) + ## Set up breaks and force values outside the range into the endmost bins + if(missing(breaks) || is.null(breaks) || length(breaks)<1 ) + { + if( missing(col) || is.function(col) ) breaks <- 16 - else + else breaks <- length(col)+1 - if(length(breaks)==1) - { + } + + if(length(breaks)==1) + { + if(!symbreaks) breaks <- seq( min(x, na.rm=na.rm), max(x,na.rm=na.rm), length=breaks) - } + else + { + extreme <- max(abs(x), na.rm=TRUE) + breaks <- seq( -extreme, extreme, length=breaks ) + } + } - nbr <- length(breaks) - ncol <- length(breaks)-1 + nbr <- length(breaks) + ncol <- length(breaks)-1 - if(class(col)=="function") - col <- col(ncol) - else if(is.character(col) && length(col)==1) - col <- do.call(col,list(ncol)) + if(class(col)=="function") + col <- col(ncol) - min.breaks <- min(breaks) - max.breaks <- max(breaks) + min.breaks <- min(breaks) + max.breaks <- max(breaks) - x[] <- ifelse(x<min.breaks, min.breaks, x) - x[] <- ifelse(x>max.breaks, max.breaks, x) + x[x<min.breaks] <- min.breaks + x[x>max.breaks] <- max.breaks - - + ## Calculate the plot layout + if( missing(lhei) || is.null(lhei) ) + lhei <- c(keysize, 4) - - ## Calculate the plot layout - if( missing(lhei) || is.null(lhei) ) - lhei <- c(keysize, 4) + if( missing(lwid) || is.null(lwid) ) + lwid <- c(keysize, 4) - if( missing(lwid) || is.null(lwid) ) - lwid <- c(keysize, 4) + if( missing(lmat) || is.null(lmat) ) + { + lmat <- rbind(4:3, 2:1) + + if(!missing(ColSideColors)) { ## add middle row to layout + if(!is.character(ColSideColors) || length(ColSideColors) != nc) + stop("'ColSideColors' must be a character vector of length ncol(x)") + lmat <- rbind(lmat[1,]+1, c(NA,1), lmat[2,]+1) + lhei <- c(lhei[1], 0.2, lhei[2]) + } - if( missing(lmat) || is.null(lmat) ) - { - lmat <- rbind(4:3, 2:1) - - if(!missing(ColSideColors)) { ## add middle row to layout - if(!is.character(ColSideColors) || length(ColSideColors) != nc) - stop("'ColSideColors' must be a character vector of length ncol(x)") - lmat <- rbind(lmat[1,]+1, c(NA,1), lmat[2,]+1) - lhei <- c(lhei[1], 0.2, lhei[2]) - } + if(!missing(RowSideColors)) { ## add middle column to layout + if(!is.character(RowSideColors) || length(RowSideColors) != nr) + stop("'RowSideColors' must be a character vector of length nrow(x)") + lmat <- cbind(lmat[,1]+1, c(rep(NA, nrow(lmat)-1), 1), lmat[,2]+1) + lwid <- c(lwid[1], 0.2, lwid[2]) + } - if(!missing(RowSideColors)) { ## add middle column to layout - if(!is.character(RowSideColors) || length(RowSideColors) != nr) - stop("'RowSideColors' must be a character vector of length nrow(x)") - lmat <- cbind(lmat[,1]+1, c(rep(NA, nrow(lmat)-1), 1), lmat[,2]+1) - lwid <- c(lwid[1], 0.2, lwid[2]) - } + lmat[is.na(lmat)] <- 0 + } + + if(length(lhei) != nrow(lmat)) + stop("lhei must have length = nrow(lmat) = ", nrow(lmat)) - lmat[is.na(lmat)] <- 0 - } - - if(length(lhei) != nrow(lmat)) - stop("lhei must have length = nrow(lmat) = ", nrow(lmat)) + if(length(lwid) != ncol(lmat)) + stop("lwid must have length = ncol(lmat) =", ncol(lmat)) - if(length(lwid) != ncol(lmat)) - stop("lwid must have length = ncol(lmat) =", ncol(lmat)) + ## Graphics `output' ----------------------- - ## Graphics `output' ----------------------- + op <- par(no.readonly = TRUE) + on.exit(par(op)) + layout(lmat, widths = lwid, heights = lhei, respect = FALSE) - op <- par(no.readonly = TRUE) - on.exit(par(op)) - layout(lmat, widths = lwid, heights = lhei, respect = FALSE) - - ## draw the side bars - if(!missing(RowSideColors)) { - par(mar = c(margins[1],0, 0,0.5)) - image(rbind(1:nr), col = RowSideColors[rowInd], axes = FALSE) + ## draw the side bars + if(!missing(RowSideColors)) { + par(mar = c(margins[1],0, 0,0.5)) + image(rbind(1:nr), col = RowSideColors[rowInd], axes = FALSE) + } + if(!missing(ColSideColors)) { + par(mar = c(0.5,0, 0,margins[2])) + image(cbind(1:nc), col = ColSideColors[colInd], axes = FALSE) + } + ## draw the main carpet + par(mar = c(margins[1], 0, 0, margins[2])) + if(!symm || scale != "none") + { + x <- t(x) + cellnote <- t(cellnote) } - if(!missing(ColSideColors)) { - par(mar = c(0.5,0, 0,margins[2])) - image(cbind(1:nc), col = ColSideColors[colInd], axes = FALSE) + if(revC) + { ## x columns reversed + iy <- nr:1 + if(exists("ddr")) + ddr <- rev(ddr) + x <- x[,iy] + cellnote <- cellnote[,iy] } - ## draw the main carpet - par(mar = c(margins[1], 0, 0, margins[2])) - if(!symm || scale != "none") - { - x <- t(x) - cellnote <- t(cellnote) - } - if(revC) - { # x columns reversed - iy <- nr:1 - ddr <- rev(ddr) - x <- x[,iy] - cellnote <- cellnote[,iy] - } - else iy <- 1:nr + else iy <- 1:nr - image(1:nc, 1:nr, x, xlim = 0.5+ c(0, nc), ylim = 0.5+ c(0, nr), - axes = FALSE, xlab = "", ylab = "", col=col, breaks=breaks, - ...) + ## display the main carpet + image(1:nc, 1:nr, x, xlim = 0.5+ c(0, nc), ylim = 0.5+ c(0, nr), + axes = FALSE, xlab = "", ylab = "", col=col, breaks=breaks, + ...) + retval$carpet <- x + if(exists("ddr")) + retval$rowDendrogram <- ddr + if(exists("ddc")) + retval$colDendrogram <- ddc + retval$breaks <- breaks + retval$col <- col + + ## fill 'na' positions with na.color + if(!invalid(na.color) & any(is.na(x))) + { + mmat <- ifelse(is.na(x), 1, NA) + image(1:nc, 1:nr, mmat, axes = FALSE, xlab = "", ylab = "", + col=na.color, add=TRUE) + } - if(!invalid(na.color) & any(is.na(x))) - { - mmat <- ifelse(is.na(x), 1, NA) - image(1:nc, 1:nr, mmat, axes = FALSE, xlab = "", ylab = "", - col=na.color, add=TRUE) - } + ## add labels + axis(1, 1:nc, labels= labCol, las= 2, line= -0.5, tick= 0, cex.axis= cexCol) + if(!is.null(xlab)) mtext(xlab, side = 1, line = margins[1] - 1.25) + axis(4, iy, labels= labRow, las= 2, line= -0.5, tick= 0, cex.axis= cexRow) + if(!is.null(ylab)) mtext(ylab, side = 4, line = margins[2] - 1.25) + ## perform user-specified function + if (!missing(add.expr)) + eval(substitute(add.expr)) - axis(1, 1:nc, labels= labCol, las= 2, line= -0.5, tick= 0, cex.axis= cexCol) - if(!is.null(xlab)) mtext(xlab, side = 1, line = margins[1] - 1.25) - axis(4, iy, labels= labRow, las= 2, line= -0.5, tick= 0, cex.axis= cexRow) - if(!is.null(ylab)) mtext(ylab, side = 4, line = margins[2] - 1.25) + ## add 'background' colored spaces to visually separate sections + if(!missing(colsep)) + for(csep in colsep) + rect(xleft =csep+0.5, ybottom=rep(0,length(csep)), + xright=csep+0.5+sepwidth[1], ytop=rep(ncol(x)+1,csep), + lty=1, lwd=1, col=sepcolor, border=sepcolor) - if (!missing(add.expr)) - eval(substitute(add.expr)) + if(!missing(rowsep)) + for(rsep in rowsep) + rect(xleft =0, ybottom= (ncol(x)+1-rsep)-0.5, + xright=nrow(x)+1, ytop = (ncol(x)+1-rsep)-0.5 - sepwidth[2], + lty=1, lwd=1, col=sepcolor, border=sepcolor) - ## add 'background' colored spaces to visually separate sections - if(!missing(colsep)) - for(csep in colsep) - rect(xleft =csep+0.5, ybottom=rep(0,length(csep)), - xright=csep+0.5+sepwidth[1], ytop=rep(ncol(x)+1,csep), - lty=1, lwd=1, col=sepcolor, border=sepcolor) + + ## show traces + min.scale <- min(breaks) + max.scale <- max(breaks) + x.scaled <- scale01(t(x), min.scale, max.scale) - if(!missing(rowsep)) - for(rsep in rowsep) - rect(xleft =0, ybottom= (ncol(x)+1-rsep)-0.5, - xright=nrow(x)+1, ytop = (ncol(x)+1-rsep)-0.5 - sepwidth[2], - lty=1, lwd=1, col=sepcolor, border=sepcolor) + if(trace %in% c("both","column") ) + { + retval$vline <- vline + vline.vals <- scale01(vline, min.scale, max.scale) + for( i in colInd ) + { + if(!is.null(vline)) + { + abline(v=i-0.5 + vline.vals, col=linecol, lty=2) + } + xv <- rep(i, nrow(x.scaled)) + x.scaled[,i] - 0.5 + xv <- c(xv[1], xv) + yv <- 1:length(xv)-0.5 + lines(x=xv, y=yv, lwd=1, col=tracecol, type="s") + } + } - # show traces - min.scale <- min(breaks) - max.scale <- max(breaks) - x.scaled <- scale01(t(x), min.scale, max.scale) + if(trace %in% c("both","row") ) + { + retval$hline <- hline + hline.vals <- scale01(hline, min.scale, max.scale) + for( i in rowInd ) + { + if(!is.null(hline)) + { + abline(h=i + hline, col=linecol, lty=2) + } + yv <- rep(i, ncol(x.scaled)) + x.scaled[i,] - 0.5 + yv <- rev(c(yv[1], yv)) + xv <- length(yv):1-0.5 + lines(x=xv, y=yv, lwd=1, col=tracecol, type="s") + } + } - if(trace %in% c("both","column") ) - { - for( i in colInd ) - { - if(!is.null(vline)) - { - vline.vals <- scale01(vline, min.scale, max.scale) - abline(v=i-0.5 + vline.vals, col=linecol, lty=2) - } - xv <- rep(i, nrow(x.scaled)) + x.scaled[,i] - 0.5 - xv <- c(xv[1], xv) - yv <- 1:length(xv)-0.5 - lines(x=xv, y=yv, lwd=1, col=tracecol, type="s") - } - } - - if(trace %in% c("both","row") ) - { - for( i in rowInd ) - { - if(!is.null(hline)) - { - hline.vals <- scale01(hline, min.scale, max.scale) - abline(h=i + hline, col=linecol, lty=2) - } - yv <- rep(i, ncol(x.scaled)) + x.scaled[i,] - 0.5 - yv <- rev(c(yv[1], yv)) - xv <- length(yv):1-0.5 - lines(x=xv, y=yv, lwd=1, col=tracecol, type="s") - } - } + if(!missing(cellnote)) + text(x=c(row(cellnote)), + y=c(col(cellnote)), + labels=c(cellnote), + col=notecol, + cex=notecex) + ## the two dendrograms : + par(mar = c(margins[1], 0, 0, 0)) + if( dendrogram %in% c("both","row") ) + { + plot(ddr, horiz = TRUE, axes = FALSE, yaxs = "i", leaflab = "none") + } + else + plot.new() - if(!missing(cellnote)) - text(x=c(row(cellnote)), - y=c(col(cellnote)), - labels=c(cellnote), - col=notecol, - cex=notecex) + par(mar = c(0, 0, if(!is.null(main)) 5 else 0, margins[2])) - ## the two dendrograms : - par(mar = c(margins[1], 0, 0, 0)) - if( dendrogram %in% c("both","row") ) - { - plot(ddr, horiz = TRUE, axes = FALSE, yaxs = "i", leaflab = "none") - } - else - plot.new() + if( dendrogram %in% c("both","column") ) + { + plot(ddc, axes = FALSE, xaxs = "i", leaflab = "none") + } + else + plot.new() - par(mar = c(0, 0, if(!is.null(main)) 5 else 0, margins[2])) + ## title + if(!is.null(main)) title(main, cex.main = 1.5*op[["cex.main"]]) - if( dendrogram %in% c("both","column") ) - { - plot(ddc, axes = FALSE, xaxs = "i", leaflab = "none") - } - else - plot.new() + ## Add the color-key + if(key) + { + par(mar = c(5, 4, 2, 1), cex=0.75) + tmpbreaks <- breaks - ## title - if(!is.null(main)) title(main, cex.main = 1.5*op[["cex.main"]]) + if(symkey) + { + max.raw <- max(abs(c(x,breaks)),na.rm=TRUE) + min.raw <- -max.raw + tmpbreaks[1] <- -max(abs(x)) + tmpbreaks[length(tmpbreaks)] <- max(abs(x)) + } + else + { + min.raw <- min(x, na.rm=TRUE) ## Again, modified to use scaled + max.raw <- max(x, na.rm=TRUE) ## or unscaled (SD 12/2/03) + } - ## Add the color-key - if(key) - { - par(mar = c(5, 4, 2, 1), cex=0.75) + z <- seq(min.raw, max.raw, length=length(col)) + image(z=matrix(z, ncol=1), + col=col, breaks=tmpbreaks, + xaxt="n", yaxt="n") - if(symkey) - { - max.raw <- max(abs(x),na.rm=TRUE) - min.raw <- -max.raw - } - else - { - min.raw <- min(x, na.rm=TRUE) # Again, modified to use scaled - max.raw <- max(x, na.rm=TRUE) # or unscaled (SD 12/2/03) - } + par(usr=c(0,1,0,1)) + lv <- pretty(breaks) + xv <- scale01(as.numeric(lv), min.raw, max.raw) + axis(1, at=xv, labels=lv) + if(scale=="row") + mtext(side=1,"Row Z-Score", line=2) + else if(scale=="column") + mtext(side=1,"Column Z-Score", line=2) + else + mtext(side=1,"Value", line=2) - z <- seq(min.raw,max.raw,length=length(col)) - image(z=matrix(z, ncol=1), - col=col, breaks=breaks, - xaxt="n", yaxt="n" ) + if(density.info=="density") + { + ## Experimental : also plot density of data + dens <- density(x, adjust=densadj, na.rm=TRUE) + omit <- dens$x < min(breaks) | dens$x > max(breaks) + dens$x <- dens$x[-omit] + dens$y <- dens$y[-omit] + dens$x <- scale01(dens$x,min.raw,max.raw) + lines(dens$x, dens$y / max(dens$y) * 0.95, col=denscol, lwd=1) + axis(2, at=pretty(dens$y)/max(dens$y) * 0.95, pretty(dens$y) ) + title("Color Key\nand Density Plot") + par(cex=0.5) + mtext(side=2,"Density", line=2) + } + else if(density.info=="histogram") + { + h <- hist(x, plot=FALSE, breaks=breaks) + hx <- scale01(breaks,min.raw,max.raw) + hy <- c(h$counts, h$counts[length(h$counts)]) + lines(hx, hy/max(hy)*0.95, lwd=1, type="s", col=denscol) + axis(2, at=pretty(hy)/max(hy) * 0.95, pretty(hy) ) + title("Color Key\nand Histogram") + par(cex=0.5) + mtext(side=2,"Count", line=2) + } + else + title("Color Key") - par(usr=c(0,1,0,1)) - lv <- pretty(breaks) - xv <- scale01(as.numeric(lv), min.raw, max.raw) - axis(1, at=xv, labels=lv) - if(scale=="row") - mtext(side=1,"Row Z-Score", line=2) - else if(scale=="column") - mtext(side=1,"Column Z-Score", line=2) - else - mtext(side=1,"Value", line=2) + } + else + plot.new() - if(density.info=="density") - { - # Experimental : also plot density of data - dens <- density(x, adjust=densadj, na.rm=TRUE) - omit <- dens$x < min(breaks) | dens$x > max(breaks) - dens$x <- dens$x[-omit] - dens$y <- dens$y[-omit] - dens$x <- scale01(dens$x,min.raw,max.raw) - lines(dens$x, dens$y / max(dens$y) * 0.95, col=denscol, lwd=1) - axis(2, at=pretty(dens$y)/max(dens$y) * 0.95, pretty(dens$y) ) - title("Color Key\nand Density Plot") - par(cex=0.5) - mtext(side=2,"Density", line=2) - } - else if(density.info=="histogram") - { - h <- hist(x, plot=FALSE, breaks=breaks) - hx <- scale01(breaks,min.raw,max.raw) - hy <- c(h$counts, h$counts[length(h$counts)]) - lines(hx, hy/max(hy)*0.95, lwd=1, type="s", col=denscol) - axis(2, at=pretty(hy)/max(hy) * 0.95, pretty(hy) ) - title("Color Key\nand Histogram") - par(cex=0.5) - mtext(side=2,"Count", line=2) - } - else - title("Color Key") + ## Create a table showing how colors match to (transformed) data ranges + retval$colorTable <- data.frame( + low=retval$breaks[-length(retval$breaks)], + high=retval$breaks[-1], + color=retval$col + ) - } - else - plot.new() - - invisible(list(rowInd = rowInd, colInd = colInd)) + + invisible( retval ) } Modified: trunk/gplots/man/heatmap.2.Rd =================================================================== --- trunk/gplots/man/heatmap.2.Rd 2009-05-08 21:27:55 UTC (rev 1316) +++ trunk/gplots/man/heatmap.2.Rd 2009-05-08 21:55:05 UTC (rev 1317) @@ -1,85 +1,92 @@ \name{heatmap.2} \alias{heatmap.2} -\title{ Draw a Heat Map } +\title{ Enhanced Heat Map } \description{ A heat map is a false color image (basically \code{\link{image}(t(x))}) with a dendrogram added to the left side and/or to the top. Typically, reordering of the rows and columns according to some set of values (row or column means) within the restrictions imposed by the dendrogram is carried out. + + This heatmap provides a number of extensions to the standard R + \code{\link[stats]{heatmap}} function. } \usage{ heatmap.2 (x, - # dendrogram control - Rowv = TRUE, - Colv=if(symm)"Rowv" else TRUE, - distfun = dist, - hclustfun = hclust, - dendrogram = c("both","row","column","none"), - symm = FALSE, + # dendrogram control + Rowv = TRUE, + Colv=if(symm)"Rowv" else TRUE, + distfun = dist, + hclustfun = hclust, + dendrogram = c("both","row","column","none"), + symm = FALSE, - # data scaling - scale = c("none","row", "column"), - na.rm=TRUE, + # data scaling + scale = c("none","row", "column"), + na.rm=TRUE, - # image plot - revC = identical(Colv, "Rowv"), - add.expr, - breaks, - col="heat.colors", + # image plot + revC = identical(Colv, "Rowv"), + add.expr, - # block sepration - colsep, - rowsep, - sepcolor="white", - sepwidth=c(0.05,0.05), + # mapping data to colors + breaks, + symbreaks=min(x < 0, na.rm=TRUE) || scale!="none", - # cell labeling - cellnote, - notecex=1.0, - notecol="cyan", - na.color=par("bg"), + # colors + col="heat.colors", - # level trace - trace=c("column","row","both","none"), - tracecol="cyan", - hline=median(breaks), - vline=median(breaks), - linecol=tracecol, + # block sepration + colsep, + rowsep, + sepcolor="white", + sepwidth=c(0.05,0.05), - # Row/Column Labeling - margins = c(5, 5), - ColSideColors, - RowSideColors, - cexRow = 0.2 + 1/log10(nr), - cexCol = 0.2 + 1/log10(nc), - labRow = NULL, - labCol = NULL, + # cell labeling + cellnote, + notecex=1.0, + notecol="cyan", + na.color=par("bg"), - # color key + density info - key = TRUE, - keysize = 1.5, - density.info=c("histogram","density","none"), - denscol=tracecol, - #symkey = TRUE, # should be something like - symkey = min(x < 0, na.rm=TRUE), - densadj = 0.25, + # level trace + trace=c("column","row","both","none"), + tracecol="cyan", + hline=median(breaks), + vline=median(breaks), + linecol=tracecol, - # plot labels - main = NULL, - xlab = NULL, - ylab = NULL, + # Row/Column Labeling + margins = c(5, 5), + ColSideColors, + RowSideColors, + cexRow = 0.2 + 1/log10(nr), + cexCol = 0.2 + 1/log10(nc), + labRow = NULL, + labCol = NULL, - # plot layout - lmat = NULL, - lhei = NULL, - lwid = NULL, + # color key + density info + key = TRUE, + keysize = 1.5, + density.info=c("histogram","density","none"), + denscol=tracecol, + symkey = min(x < 0, na.rm=TRUE) || symbreaks, + densadj = 0.25, - # extras - ... - ) - } + # plot labels + main = NULL, + xlab = NULL, + ylab = NULL, + + # plot layout + lmat = NULL, + lhei = NULL, + lwid = NULL, + + # extras + ... + ) + } \arguments{ % Dendogram Control \item{x}{numeric matrix of the values to be plotted. } @@ -121,6 +128,9 @@ splitting points for binning \code{x} into colors, or a integer number of break points to be used, in which case the break points will be spaced equally between \code{min(x)} and \code{max(x)}.} + \item{symbreaks}{Boolean indicating whether breaks should be + made symmetric about 0. Defaults to \code{TRUE} if the data includes + negative values, and to \code{FALSE} otherwise.} \item{col}{colors used for the image. Defaults to heat colors (\code{heat.colors}).} % block separation @@ -178,7 +188,8 @@ display specified by \code{density.info}, defaults to the same value as \code{tracecol}.} \item{symkey}{Boolean indicating whether the color key should be - made symmetric about 0. Defaults to \code{TRUE}.} + made symmetric about 0. Defaults to \code{TRUE} if the data includes + negative values, and to \code{FALSE} otherwise.} \item{densadj}{Numeric scaling value for tuning the kernel width when a density plot is drawn on the color key. (See the \code{adjust} parameter for the \code{density} function for details.) Defaults to @@ -244,9 +255,26 @@ } \value{ Invisibly, a list with components - \item{rowInd}{\bold{r}ow index permutation vector as returned by + \item{rowInd}{row index permutation vector as returned by \code{\link{order.dendrogram}}.} - \item{colInd}{\bold{c}olumn index permutation vector.} + \item{colInd}{column index permutation vector.} + \item{call}{the matched call} + \item{rowMeans, rowSDs}{mean and standard deviation of each row: only + present if \code{scale="row"}} + \item{colMeans, colSDs}{mean and standard deviation of each column: only + present if \code{scale="column"}} + \item{carpet}{reordered and scaled 'x' values used generate the main + 'carpet'} + \item{rowDendrogram}{row dendrogram, if present} + \item{colDendrogram}{column dendrogram, if present} + \item{breaks}{values used for color break points} + \item{col}{colors used} + \item{vline}{center-line value used for column trace, present only if + \code{trace="both"} or \code{trace="column"} } + \item{hline}{center-line value used for row trace, present only if + \code{trace="both"} or \code{trace="row"} } + \item{colorTable}{A three-column data frame providing the lower and upper + bound and color for each bin} } \author{Andy Liaw, original; R. Gentleman, M. Maechler, W. Huber, G. Warnes, revisions.} @@ -260,6 +288,9 @@ rc <- rainbow(nrow(x), start=0, end=.3) cc <- rainbow(ncol(x), start=0, end=.3) + ## + ## demonstrate the effect of row and column dendogram options + ## heatmap.2(x) ## default - dendrogram plotted and reordering done. heatmap.2(x, dendrogram="none") ## no dendrogram plotted, but reordering done. heatmap.2(x, dendrogram="row") ## row dendrogram plotted and row reordering done. @@ -267,22 +298,45 @@ heatmap.2(x, keysize=2) ## default - dendrogram plotted and reordering done. - heatmap.2(x, Rowv=FALSE, dendrogram="both") ## generate warning! heatmap.2(x, Rowv=NULL, dendrogram="both") ## generate warning! heatmap.2(x, Colv=FALSE, dendrogram="both") ## generate warning! + ## + ## Show effect of z-score scaling within columns, blue-red color scale + ## + hv <- heatmap.2(x, col=bluered, scale="column", tracecol="#303030") + ### + ## Look at the return values + ### + names(hv) + ## Show the mapping of z-score values to color bins + hv$colorTable - hv <- heatmap.2(x, col=cm.colors(256), scale="column", + ## Extract the range associated with white + hv$colorTable[hv$colorTable[,"color"]=="#FFFFFF",] + + ## Determine the original data values that map to white + whiteBin <- unlist(hv$colorTable[hv$colorTable[,"color"]=="#FFFFFF",1:2]) + rbind(whiteBin[1] * hv$colSDs + hv$colMeans, + whiteBin[2] * hv$colSDs + hv$colMeans ) + ## + ## A more decorative heatmap, with z-score scaling along columns + ## + hv <- heatmap.2(x, col=cm.colors(255), scale="column", RowSideColors=rc, ColSideColors=cc, margin=c(5, 10), xlab="specification variables", ylab= "Car Models", main="heatmap(<Mtcars data>, ..., scale=\"column\")", tracecol="green", density="density") + ## Note that the breakpoints are now symmetric about 0 - str(hv) # the two re-ordering index vectors + + + + %% want example using the `add.exp' argument! data(attitude) Modified: trunk/gplots/tests/heatmap2Test.Rout.save =================================================================== --- trunk/gplots/tests/heatmap2Test.Rout.save 2009-05-08 21:27:55 UTC (rev 1316) +++ trunk/gplots/tests/heatmap2Test.Rout.save 2009-05-08 21:55:05 UTC (rev 1317) @@ -1,6 +1,6 @@ -R version 2.6.0 (2007-10-03) -Copyright (C) 2007 The R Foundation for Statistical Computing +R version 2.9.0 (2009-04-17) +Copyright (C) 2009 The R Foundation for Statistical Computing ISBN 3-900051-07-0 R is free software and comes with ABSOLUTELY NO WARRANTY. @@ -18,6 +18,9 @@ > library(gplots) Loading required package: gtools Loading required package: gdata +Loading required package: caTools +Loading required package: bitops +Loading required package: grid Attaching package: 'gplots' @@ -112,8 +115,108 @@ + tracecol="green", density="density") > > str(hv) # the two re-ordering index vectors -List of 2 - $ rowInd: int [1:32] 31 17 16 15 5 25 29 24 7 6 ... - $ colInd: int [1:11] 2 9 8 11 6 5 10 7 1 4 ... +List of 12 + $ rowInd : int [1:32] 31 17 16 15 5 25 29 24 7 6 ... + $ colInd : int [1:11] 2 9 8 11 6 5 10 7 1 4 ... + $ call : language heatmap.2(x = x, scale = "column", col = cm.colors(256), tracecol = "green", margins = c(5, 10), ColSideColors = cc, RowSideColors = rc, ... + $ colMeans : Named num [1:11] 6.188 0.406 0.438 2.812 3.217 ... + ..- attr(*, "names")= chr [1:11] "cyl" "am" "vs" "carb" ... + $ colSDs : Named num [1:11] 1.786 0.499 0.504 1.615 0.978 ... + ..- attr(*, "names")= chr [1:11] "cyl" "am" "vs" "carb" ... + $ carpet : num [1:11, 1:32] 1.015 1.19 -0.868 3.212 0.361 ... + ..- attr(*, "dimnames")=List of 2 + .. ..$ : chr [1:11] "cyl" "am" "vs" "carb" ... + .. ..$ : chr [1:32] "Maserati Bora" "Chrysler Imperial" "Lincoln Continental" "Cadillac Fleetwood" ... + $ rowDendrogram: ..--[dendrogram w/ 2 branches and 32 members at h = 425, midpoint = 8.58, value = 1267] + .. |--[dendrogram w/ 2 branches and 9 members at h = 215, midpoint = 1.84, value = 552] + .. | |--leaf "Maserati Bora" ( value.Maserati Bora = 63.2 ) + .. | `--[dendrogram w/ 2 branches and 8 members at h = 135, midpoint = 2.69, value = 489] + .. | |--[dendrogram w/ 2 branches and 3 members at h = 40.8, midpoint = 0.75, value = 198] + .. | | |--leaf "Chrysler Imperial" ( value.Chrysler Imperial = 66 ) + .. | | `--[dendrogram w/ 2 branches and 2 members at h = 15.6, midpoint = 0.5, value = 132] + .. | | |--leaf "Lincoln Continental" ( value.Lincoln Continental = 66 ) + .. | | `--leaf "Cadillac Fleetwood" ( value.Cadillac Fleetwood = 66.2 ) + .. | `--[dendrogram w/ 2 branches and 5 members at h = 102, midpoint = 1.62, value = 290] + .. | |--[dendrogram w/ 2 branches and 2 members at h = 40, midpoint = 0.5, value = 111] + .. | | |--leaf "Hornet Sportabout" ( value.Hornet Sportabout = 53.7 ) + .. | | `--leaf "Pontiac Firebird" ( value.Pontiac Firebird = 57.4 ) + .. | `--[dendrogram w/ 2 branches and 3 members at h = 21.3, midpoint = 0.75, value = 179] + .. | |--leaf "Ford Pantera L" ( value.Ford Pantera L = 61 ) + .. | `--[dendrogram w/ 2 branches and 2 members at h = 10.1, midpoint = 0.5, value = 118] + .. | |--leaf "Camaro Z28" ( value.Camaro Z28 = 58.8 ) + .. | `--leaf "Duster 360" ( value.Duster 360 = 59.7 ) + .. `--[dendrogram w/ 2 branches and 23 members at h = 262, midpoint = 6.33, value = 716] + .. |--[dendrogram w/ 2 branches and 7 members at h = 103, midpoint = 2.06, value = 306] + .. | |--[dendrogram w/ 2 branches and 2 members at h = 33.6, midpoint = 0.5, value = 73.8] + .. | | |--leaf "Valiant" ( value.Valiant = 35.0 ) + .. | | `--leaf "Hornet 4 Drive" ( value.Hornet 4 Drive = 38.7 ) + .. | `--[dendrogram w/ 2 branches and 5 members at h = 51.8, midpoint = 1.62, value = 233] + .. | |--[dendrogram w/ 2 branches and 2 members at h = 14.0, midpoint = 0.5, value = 93.2] + .. | | |--leaf "AMC Javelin" ( value.AMC Javelin = 46 ) + .. | | `--leaf "Dodge Challenger" ( value.Dodge Challenger = 47.2 ) + .. | `--[dendrogram w/ 2 branches and 3 members at h = 2.14, midpoint = 0.75, value = 139] + .. | |--leaf "Merc 450SLC" ( value.Merc 450SLC = 46.4 ) + .. | `--[dendrogram w/ 2 branches and 2 members at h = 0.983, midpoint = 0.5, value = 93] + .. | |--leaf "Merc 450SE" ( value.Merc 450SE = 46.4 ) + .. | `--leaf "Merc 450SL" ( value.Merc 450SL = 46.5 ) + .. `--[dendrogram w/ 2 branches and 16 members at h = 142, midpoint = 3.59, value = 409] + .. |--[dendrogram w/ 2 branches and 4 members at h = 14.8, midpoint = 0.875, value = 75] + .. | |--leaf "Honda Civic" ( value.Honda Civic = 17.7 ) + .. | `--[dendrogram w/ 2 branches and 3 members at h = 10.4, midpoint = 0.75, value = 57.2] + .. | |--leaf "Toyota Corolla" ( value.Toyota Corolla = 18.8 ) + .. | `--[dendrogram w/ 2 branches and 2 members at h = 5.15, midpoint = 0.5, value = 38.4] + .. | |--leaf "Fiat X1-9" ( value.Fiat X1-9 = 18.9 ) + .. | `--leaf "Fiat 128" ( value.Fiat 128 = 19.4 ) + .. `--[dendrogram w/ 2 branches and 12 members at h = 113, midpoint = 2.30, value = 334] + .. |--leaf "Ferrari Dino" ( value.Ferrari Dino = 34.5 ) + .. `--[dendrogram w/ 2 branches and 11 members at h = 74.4, midpoint = 3.61, value = 300] + .. |--[dendrogram w/ 2 branches and 5 members at h = 64.9, midpoint = 1.25, value = 148] + .. | |--leaf "Merc 240D" ( value.Merc 240D = 24.6 ) + .. | `--[dendrogram w/ 2 branches and 4 members at h = 15.7, midpoint = 1.5, value = 124] + .. | |--[dendrogram w/ 2 branches and 2 members at h = 0.615, midpoint = 0.5, value = 59.9] + .. | | |--leaf "Mazda RX4" ( value.Mazda RX4 = 29.9 ) + .. | | `--leaf "Mazda RX4 Wag" ( value.Mazda RX4 Wag = 30 ) + .. | `--[dendrogram w/ 2 branches and 2 members at h = 1.52, midpoint = 0.5, value = 63.6] + .. | |--leaf "Merc 280C" ( value.Merc 280C = 31.8 ) + .. | `--leaf "Merc 280" ( value.Merc 280 = 31.9 ) + .. `--[dendrogram w/ 2 branches and 6 members at h = 50.1, midpoint = 0.969, value = 152] + .. |--leaf "Lotus Europa" ( value.Lotus Europa = 24.9 ) + .. `--[dendrogram w/ 2 branches and 5 members at h = 33.2, midpoint = 0.938, value = 127] + .. |--leaf "Merc 230" ( value.Merc 230 = 27.2 ) + .. `--[dendrogram w/ 2 branches and 4 members at h = 20.7, midpoint = 0.875, value = 99.5] + .. |--leaf "Volvo 142E" ( value.Volvo 142E = 26.3 ) + .. `--[dendrogram w/ 2 branches and 3 members at h = 13.1, midpoint = 0.75, value = 73.3] + .. |--leaf "Datsun 710" ( value.Datsun 710 = 23.6 ) + .. `--[dendrogram w/ 2 branches and 2 members at h = 8.65, midpoint = 0.5, value = 49.7] + .. |--leaf "Porsche 914-2" ( value.Porsche 914-2 = 24.8 ) + .. `--leaf "Toyota Corona" ( value.Toyota Corona = 24.9 ) + $ colDendrogram: ..--[dendrogram w/ 2 branches and 11 members at h = 1475, midpoint = 7, value = 436] + .. |--[dendrogram w/ 2 branches and 9 members at h = 116, midpoint = 4.5, value = 58.3] + .. | |--[dendrogram w/ 2 branches and 7 members at h = 34.8, midpoint = 1.5, value = 20.3] + .. | | |--leaf "cyl" ( value.cyl = 6.19 ) + .. | | `--[dendrogram w/ 2 branches and 6 members at h = 18.9, midpoint = 2, value = 14.2] + .. | | |--[dendrogram w/ 2 branches and 2 members at h = 3.61, midpoint = 0.5, value = 0.844] + .. | | | |--leaf "am" ( value.am = 0.406 ) + .. | | | `--leaf "vs" ( value.vs = 0.438 ) + .. | | `--[dendrogram w/ 2 branches and 4 members at h = 10.7, midpoint = 1.5, value = 13.3] + .. | | |--[dendrogram w/ 2 branches and 2 members at h = 8.6, midpoint = 0.5, value = 6.03] + .. | | | |--leaf "carb" ( value.carb = 2.81 ) + .. | | | `--leaf "wt" ( value.wt = 3.22 ) + .. | | `--[dendrogram w/ 2 branches and 2 members at h = 2.98, midpoint = 0.5, value = 7.28] + .. | | |--leaf "drat" ( value.drat = 3.6 ) + .. | | `--leaf "gear" ( value.gear = 3.69 ) + .. | `--[dendrogram w/ 2 branches and 2 members at h = 33.3, midpoint = 0.5, value = 37.9] + .. | |--leaf "qsec" ( value.qsec = 17.8 ) + .. | `--leaf "mpg" ( value.mpg = 20.1 ) + .. `--[dendrogram w/ 2 branches and 2 members at h = 657, midpoint = 0.5, value = 377] + .. |--leaf "hp" ( value.hp = 147 ) + .. `--leaf "disp" ( value.disp = 231 ) + $ breaks : num [1:257] -3.21 -3.19 -3.16 -3.14 -3.11 ... + $ col : chr [1:256] "#80FFFFFF" "#80FFFFFF" "#81FFFFFF" "#82FFFFFF" ... + $ vline : num 0 + $ colorTable :'data.frame': 256 obs. of 3 variables: + ..$ low : num [1:256] -3.21 -3.19 -3.16 -3.14 -3.11 ... + ..$ high : num [1:256] -3.19 -3.16 -3.14 -3.11 -3.09 ... + ..$ color: Factor w/ 254 levels "#80FFFFFF","#81FFFFFF",..: 1 1 2 3 4 5 6 7 8 9 ... > > This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |