R/ggplot-heatmap.R

# Copied from https://raw.githubusercontent.com/chr1swallace/random-functions/master/R/ggplot-heatmap.R
# all credit to chr1swallace

## colours, generated by
## rev(brewer.pal(11,name="RdYlBu"))
my.colours <- c("#313695", "#4575B4", "#74ADD1", "#ABD9E9", "#E0F3F8", "#FFFFBF",
                "#FEE090", "#FDAE61", "#F46D43", "#D73027", "#A50026")

mydplot <- function(ddata, row=!col, col=!row, labels=col) {
  ## plot a dendrogram
  yrange <- range(ddata$segments$y)
  yd <- yrange[2] - yrange[1]
  nc <- max(nchar(as.character(ddata$labels$label)))
  tangle <- if(row) { 0 } else { 90 }
  tshow <- col
  p <- ggplot2::ggplot() +
    ggplot2::geom_segment(data=ggdendro::segment(ddata),
                          ggplot2::aes(x=x, y=y, xend=xend, yend=yend)) +
    ggplot2::labs(x = NULL, y = NULL) + ggplot2::theme_dendro()
  if(row) {
    p <- p +
      ggplot2::scale_x_continuous(expand=c(0.5/length(ddata$labels$x),0)) +
      ggplot2::coord_flip()
  } else {
    p <- p +
      ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 90, hjust = 1))
  }
  return(p)
}

g_legend<-function(a.gplot){
  ## from
  ## http://stackoverflow.com/questions/11883844/inserting-a-table-under-the-legend-in-a-ggplot2-histogram
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  return(legend)
}
##' Display a ggheatmap
##'
##' this function sets up some viewports, and tries to plot the dendrograms to line up with the heatmap
##' @param L a list with 3 named plots: col, row, centre, generated by ggheatmap
##' @param col.width,row.width number between 0 and 1, fraction of the device devoted to the column or row-wise dendrogram. If 0, don't print the dendrogram
##' @return no return value, side effect of displaying plot in current device
##' @export
##' @author Chris Wallace
ggheatmap.show <- function(L, col.width=0.2, row.width=0.2) {
  grid::grid.newpage()
  top.layout <- grid::grid.layout(nrow = 2, ncol = 2,
                                  widths = grid::unit(c(1-row.width,row.width), "null"),
                                  heights = grid::unit(c(col.width,1-row.width), "null"))
  grid::pushViewport(grid::viewport(layout=top.layout))
  if(col.width>0)
    print(L$col, vp=grid::viewport(layout.pos.col=1, layout.pos.row=1))
  if(row.width>0)
    print(L$row, vp=grid::viewport(layout.pos.col=2, layout.pos.row=2))
  ## print centre without legend
  print(L$centre +
          ggplot2::theme(axis.line=ggplot2::element_blank(),
                         axis.text.x=ggplot2::element_blank(),
                         axis.text.y=ggplot2::element_blank(),
                         axis.ticks=ggplot2::element_blank(),
                         axis.title.x=ggplot2::element_blank(),
                         axis.title.y=ggplot2::element_blank(),
                         legend.position="none",
                         panel.background=ggplot2::element_blank(),
                         panel.border=ggplot2::element_blank(),
                         panel.grid.major=ggplot2::element_blank(),
                         panel.grid.minor=ggplot2::element_blank(),
                         plot.background=ggplot2::element_blank()),
        vp=grid::viewport(layout.pos.col=1, layout.pos.row=2))
  ## add legend
  legend <- g_legend(L$centre)
  grid::pushViewport(grid::viewport(layout.pos.col=2, layout.pos.row=1))
  grid::grid.draw(legend)
  grid::upViewport(0)
}
##' generate a heatmap + dendrograms, ggplot2 style
##'
##' @param x data matrix
##' @param hm.colours vector of colours (optional)
##' @return invisibly returns a list of ggplot2 objects. Display them with ggheatmap.show()
##' @author Chris Wallace
##' @export
##' @examples
##' ## test run
##' ## simulate data
##' library(mvtnorm)
##' sigma=matrix(0,10,10)
##' sigma[1:4,1:4] <- 0.6
##' sigma[6:10,6:10] <- 0.8
##' diag(sigma) <- 1
##' X <- rmvnorm(n=100,mean=rep(0,10),sigma=sigma)
##'
##' ## make plot
##' p <- ggheatmap(X)
##'
##' ## display plot
##' ggheatmap.show(p)
ggheatmap <- function(x,
                      hm.colours=my.colours) {
  if(is.null(colnames(x)))
    colnames(x) <- sprintf("col%s",1:ncol(x))
  if(is.null(rownames(x)))
    rownames(x) <- sprintf("row%s",1:nrow(x))
  ## plot a heatmap
  ## x is an expression matrix
  row.hc <- hclust(dist(x), "ward")
  col.hc <- hclust(dist(t(x)), "ward")
  row.dendro <- ggdendro::dendro_data(as.dendrogram(row.hc),type="rectangle")
  col.dendro <- ggdendro::dendro_data(as.dendrogram(col.hc),type="rectangle")

  ## dendro plots
  col.plot <- mydplot(col.dendro, col=TRUE, labels=TRUE) +
    ggplot2::scale_x_continuous(breaks = 1:ncol(x),labels=col.hc$labels[col.hc$order]) +
    ggplot2::theme(plot.margin = grid::unit(c(0,0,0,0), "lines"))
  row.plot <- mydplot(row.dendro, row=TRUE, labels=FALSE) +
    ggplot2::theme(plot.margin = grid::unit(rep(0, 4), "lines"))

  ## order of the dendros
  col.ord <- match(col.dendro$labels$label, colnames(x))
  row.ord <- match(row.dendro$labels$label, rownames(x))
  xx <- x[row.ord,col.ord]
  dimnames(xx) <- NULL
  xx <- reshape::melt(xx)

  centre.plot <- ggplot2::ggplot(xx, aes(X2,X1)) + ggplot2::geom_tile(ggplot2::aes(fill=value), colour="white") +
    ggplot2::scale_fill_gradientn(colours = hm.colours) +
    ggplot2::labs(x = NULL, y = NULL) +
    ggplot2::scale_x_continuous(expand=c(0,0)) +
    ggplot2::scale_y_continuous(expand=c(0,0),breaks = NULL) +
    ggplot2::theme(plot.margin = grid::unit(rep(0, 4), "lines"))
  ret <- list(col=col.plot,row=row.plot,centre=centre.plot)
  invisible(ret)
}
Sage-Bionetworks/pcbcStats documentation built on May 9, 2019, 12:12 p.m.