R/subHeatmap.R

Defines functions subHeatmap

Documented in subHeatmap

#' ntp heatmap
#' @description Heatmap with marker genes and class labels.
#' @export
#' @param emat a numeric matrix with row features and sample columns.
#' @param res a data frame, result from \code{ntp} function.
#' @param templates data frame with two columns; class (factor or numeric) and
#' probe (character).
#' @param keepN a logical or numeric vector specifying which samples to keep.
#' @param classCol a character vector specifying class colors.
#' @param labRow a character specifying \code{templates} column used for labeling
#' features.
#' @param heatCol a character vector specifying heatmap colors (must be an even
#' number).
#' @param ... additional arguments passed to \code{\link[graphics]{image}}.
#' @details \code{subHeatmap} provides a simple heatmap with samples and genes
#' ordered according to subtype. The column bar indicates prediction
#' \eqn{p}-values.
#' @return a raster heatmap to visualize template feature expression.
subHeatmap <- function(emat, res, templates, keepN = TRUE,
                       labRow = NULL,
                       classCol = getOption("subClassCol"),
                       heatCol = NULL,...) {

    # checkInput ##############################################################

    if (!all(colnames(emat) == rownames(res))) stop("check if emat/res match")

    # prepareInput ############################################################

    emat <- emat[,keepN];res <- res[keepN,]
    class <- res$prediction
    K <- nlevels(class)

    if (!is.null(labRow )) {
        old.par <- graphics::par()
        on.exit(graphics::par(mar=old.par$mar))
        graphics::par(mar=old.par$mar+c(0,0,0,3))
    }

    # prepare templates
    templates <- templates[!duplicated(templates$probe),]
    rownames(templates) <- templates$probe

    # prepare res
    isDist <- grepl("^d\\.", colnames(res))
    res$prediction <- factor(levels(res$prediction)
                            [apply(res[,isDist], 1, which.min)])

    if (K == 2) {
        isClass2 <- res$prediction == levels(class)[2]
        res$p.value[isClass2] <- -res$p.value[isClass2]
    }

    # match emat and templates and order colums after prediction and p.value
    N <- order(res$prediction, res$p.value)
    P <- intersect(rownames(emat), rownames(templates))

    templates <- templates[P,]
    templates <- templates[order(templates$class),]
    emat <- ematAdjust(emat[rownames(templates),N])

    # colorBars ###############################################################

    if (is.null(heatCol)) heatCol <- subData[["hmCol"]]

    # prettyBreaks ############################################################
    pMax = 3
    breaksLeft = seq(-pMax,-.25, length = length(heatCol)/2)
    breaks <- c(breaksLeft, 0, abs(rev(breaksLeft)))

    # necessary to avoid color overflow
    emat[emat > pMax] <- pMax; emat[emat < -pMax] <- -pMax

    # makeHeatmap #############################################################
    xx <- seq(0, 1, length.out=ncol(emat)+1)
    yy <- seq(0, 1, length.out=nrow(emat)+1)

    graphics::image(x = xx, y = yy, z = t(emat),
                yaxt="n", xaxt="n",useRaster=TRUE,
                col = heatCol, breaks = breaks,
                xlab = "class predictions", ylab = "template features", ...)

    # make sample bar
    xb <- cumsum(c(0,(sapply(split(res$prediction[N], res$prediction[N]),
                             length)/length(N))))
    xl <- xb[-(K+1)]
    xr <- xb[-1]

    yy <- line2user(line=1:0, side=1)
    yy <- seq(yy[1], yy[2], length=3)

    graphics::rect(xleft = xl, xright = xr, ybottom = yy[1], ytop=yy[2],
                   col=classCol, xpd=TRUE, border=FALSE, lwd = .75)

    xxl <- xl+(xr-xl)/2
    graphics::text(xxl, yy[1], pos=1,levels(class), adj=0,xpd=TRUE, cex=.75)

    # make p-value trace if applicable
    if (min(res$p.value) < 1) {
        py <- abs(res$p.value[N])
        px <- (seq_along(N)/(length(N)))-1/length(N)/2
        py <- (py*(yy[2]-yy[1]))+yy[1]
        graphics::rect(xleft = xx[-length(xx)], xright = xx[-1],
                       ybottom=yy[1], ytop=py, border = FALSE,
                       xpd=NA, col = "white", lwd=2)
        graphics::rect(xleft = xl, xright = xr, ybottom = yy[1], ytop=yy[2],
                       col=NA, xpd=TRUE, lwd = .75)

        graphics::text(0,yy[1], pos=2, expression(italic(p)-value), xpd=TRUE, cex=.75)
        graphics::text(x=1,y=c(yy[1],yy[2]), c(0,1), pos=c(4),xpd=TRUE,cex=.75)
        graphics::text(4,2, paste(bquote(italic(p)-value)))
    }

    # make feature bar
    xx <- line2user(line=1:0, side=2)
    xx <- seq(xx[1], xx[2], length=3)

    yy <- c(0, cumsum(sapply(split(templates$probe, templates$class),
                            length)/length(templates$probe)))
    yb <- yy[-(K+1)]
    yt <- yy[-1]
    graphics::rect(xleft=xx[1],xright=xx[2],ybottom=yb,ytop=yt,
                   col=classCol, xpd=NA, lwd = .75)

    if (!is.null(labRow )) {
        textfun <- function(..., cex.text)
            graphics::text(..., xpd=TRUE, cex=.75)
        id <- templates[,labRow]
        yy <- seq(0+(1/nrow(templates)/2), 1-(1/nrow(templates)/2),
                  length.out=nrow(templates))
        textfun(1, yy, id, pos=4, adj=1)
    }
}
peterawe/CMScaller documentation built on June 13, 2020, 4:49 a.m.