--- a +++ b/R/getMoHeatmap.R @@ -0,0 +1,269 @@ +#' @name getMoHeatmap +#' @title Get multi-omics comprehensive heatmap +#' @description This function vertically concatenates multiple heatmap derived from each omics data. `getMoHeatmap` supports customized column annotation and is able to mark the selected features if indicated. +#' @param data A list of data frame or matrix storing multiple omics data with rows for features and columns for samples. +#' @param is.binary A logicial vector to indicate if the subdata is binary matrix of 0 and 1 such as mutation. +#' @param row.title A string vector to assign titles for each subdata. +#' @param legend.name A string vector to assign legend title for each subdata. +#' @param clust.res A clust.res object returned by `getMOIC()` with one specified algorithm or `get\%algorithm_name\%` or `getConsensusMOIC()` with a list of multiple algorithms. +#' @param clust.dend A dendrogram object returned returned by `getMOIC()` with one specified algorithm or `get\%algorithm_name\%` or `getConsensusMOIC()` with a list of multiple algorithms. +#' @param show.col.dend A logical vector to indicate if showing the dendrogram for column at the top of heatmap. +#' @param show.colnames A logical vector to indicate if showing the names for column at the bottom of heatmap. +#' @param show.row.dend A logical vector to indicate if showing the dendrogram for row of each subdata. +#' @param show.rownames A logical vector to indicate if showing the names for row of each subdata. +#' @param clust.dist.row A string vector to assign distance method for clustering each subdata at feature dimension. +#' @param clust.method.row A string vector to assign clustering method for clustering each subdata at feature dimension. +#' @param clust.col A string vector storing colors for annotating each subtype at the top of heatmap. +#' @param color A list of string vectors storing colors for each subheatmap of subdata. +#' @param annCol A data.frame storing annotation information for samples with exact the same sample order with data parameter. +#' @param annColors A list of string vectors for colors matched with annCol. +#' @param annRow A list of string vectors to indicate which features belong to which subdata should be annotated specifically in subheatmap. +#' @param width An integer value to indicate the width for each subheatmap with unit of cm. +#' @param height An integer value to indicate the height for each subheatmap with unit of cm. +#' @param fig.path A string value to indicate the output path for storing the comprehensive heatmap. +#' @param fig.name A string value to indicate the name of the comprehensive heatmap. +#' @return A pdf of multi-omics comprehensive heatmap +#' @importFrom ComplexHeatmap HeatmapAnnotation Heatmap rowAnnotation anno_mark draw ht_opt %v% +#' @importFrom ClassDiscovery distanceMatrix +#' @importFrom grDevices pdf dev.off colorRampPalette +#' @importFrom circlize colorRamp2 +#' @importFrom dplyr %>% +#' @references Gu Z, Eils R, Schlesner M (2016). Complex heatmaps reveal patterns and correlations in multidimensional genomic data. Bioinformatics. +#' @export +#' @examples # There is no example and please refer to vignette. +getMoHeatmap <- function(data = NULL, + is.binary = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE), + row.title = c("Data1","Data2","Data3","Data4","Data5","Data6"), + legend.name = c("Data1","Data2","Data3","Data4","Data5","Data6"), + clust.res = NULL, + clust.dend = NULL, + show.col.dend = TRUE, + show.colnames = FALSE, + show.row.dend = c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE), + show.rownames = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE), + clust.dist.row = c("pearson","pearson","pearson","pearson","pearson","pearson"), + clust.method.row = c("ward.D","ward.D","ward.D","ward.D","ward.D","ward.D"), + clust.col = c("#2EC4B6","#E71D36","#FF9F1C","#BDD5EA","#FFA5AB","#011627","#023E8A","#9D4EDD"), + color = rep(list(c("#00FF00", "#000000", "#FF0000")),length(data)), + annCol = NULL, + annColors = NULL, + annRow = NULL, + width = 6, + height = 4, + fig.path = getwd(), + fig.name = "moheatmap") { + + ht_opt$message = FALSE + defaultW <- getOption("warn") + options(warn = -1) + + # check data + if(is.null(names(data))){ + names(data) <- sprintf("dat%s", 1:length(data)) + } + + n_dat <- length(data) + if(n_dat > 6){ + stop('current verision of MOVICS can support up to 6 datasets.') + } + if(n_dat < 2){ + stop('current verision of MOVICS needs at least 2 omics data.') + } + + colvec <- clust.col[1:length(unique(clust.res$clust))] + names(colvec) <- paste0("CS",unique(clust.res$clust)) + + if(!is.null(annCol) & !is.null(annColors)) { + + annCol <- annCol[colnames(data[[1]]), , drop = FALSE] + annCol$Subtype <- paste0("CS",clust.res[colnames(data[[1]]),"clust"]) + annColors[["Subtype"]] <- colvec + + if(is.null(clust.dend)) { + clust.res <- clust.res[order(clust.res$clust),] + annCol <- annCol[clust.res$samID, , drop = FALSE] + } + + ha <- ComplexHeatmap::HeatmapAnnotation(df = annCol, + col = annColors, + border = FALSE) + } else { + annCol <- data.frame("Subtype" = paste0("CS",clust.res[colnames(data[[1]]),"clust"]), + row.names = colnames(data[[1]]), + stringsAsFactors = FALSE) + annColors <- list("Subtype" = colvec) + + if(is.null(clust.dend)) { + clust.res <- clust.res[order(clust.res$clust),] + annCol <- annCol[clust.res$samID,,drop = FALSE] + } + + ha <- ComplexHeatmap::HeatmapAnnotation(df = annCol, + col = annColors, + border = FALSE) + } + + if(!is.null(annRow)) { + if(!is.list(annRow)) {stop("argument of annRow should be a list!")} + } + + ht <- list() + for (i in 1:n_dat) { + + hcg <- hclust(ClassDiscovery::distanceMatrix(as.matrix(t(data[[i]])), clust.dist.row[i]), clust.method.row[i]) + + if(is.null(annRow[[i]][1])) { + rowlab <- "" + rowlab.index <- 0 + } else if (is.na(annRow[[i]][1])) { + rowlab <- "" + rowlab.index <- 0 + } else { + rowlab <- intersect(rownames(data[[i]]),annRow[[i]]) + rowlab.index <- match(rowlab, rownames(data[[i]])) + } + + if(is.null(clust.dend)) { + data <- lapply(data, function(x) x[,clust.res$samID]) + + if(!is.binary[i]) { + ht[[i]] <- ComplexHeatmap::Heatmap(matrix = as.matrix(data[[i]]), + row_title = row.title[i], + name = legend.name[i], + cluster_columns = FALSE, + cluster_rows = hcg, + show_column_dend = FALSE, + show_column_names = show.colnames, + show_row_dend = show.row.dend[i], + show_row_names = show.rownames[i], + col = grDevices::colorRampPalette(color[[i]])(64), + top_annotation = switch((i == 1) + 1, NULL, ha), + width = grid::unit(width, "cm"), + height = grid::unit(height, "cm"), + heatmap_legend_param = list(at = pretty(range(data[[i]])), + labels = pretty(range(data[[i]]))), + right_annotation = ComplexHeatmap::rowAnnotation(link = + anno_mark(at = rowlab.index, + labels = rowlab, + which = "row", + lines_gp = grid::gpar(fontsize = 5), + link_width = grid::unit(3, "mm"), + padding = grid::unit(0.8, "mm"), + labels_gp = grid::gpar(fontsize = 7)))) + } else { + col_fun = circlize::colorRamp2(c(0, 1), color[[i]]) + + ht[[i]] <- ComplexHeatmap::Heatmap(matrix = as.matrix(data[[i]]), + row_title = row.title[i], + name = legend.name[i], + cluster_columns = FALSE, + cluster_rows = hcg, + show_column_dend = FALSE, + show_column_names = show.colnames, + show_row_dend = show.row.dend[i], + show_row_names = show.rownames[i], + col = color[[i]], + top_annotation = switch((i == 1) + 1, NULL, ha), + width = grid::unit(width, "cm"), + height = grid::unit(height, "cm"), + heatmap_legend_param = list(at = c(0, 1), + legend_gp = grid::gpar(fill = col_fun(c(0,1))), + labels = c("0", "1")), + right_annotation = ComplexHeatmap::rowAnnotation(link = + anno_mark(at = rowlab.index, + labels = rowlab, + which = "row", + lines_gp = grid::gpar(fontsize = 5), + link_width = grid::unit(3, "mm"), + padding = grid::unit(0.8, "mm"), + labels_gp = grid::gpar(fontsize = 7)))) + } + + } else { + if(!is.binary[i]) { + ht[[i]] <- ComplexHeatmap::Heatmap(matrix = as.matrix(data[[i]]), + row_title = row.title[i], + name = legend.name[i], + cluster_columns = clust.dend, + cluster_rows = hcg, + show_column_dend = show.col.dend, + show_column_names = show.colnames, + show_row_dend = show.row.dend[i], + show_row_names = show.rownames[i], + col = grDevices::colorRampPalette(color[[i]])(64), + top_annotation = switch((i == 1) + 1, NULL, ha), + width = grid::unit(width, "cm"), + height = grid::unit(height, "cm"), + heatmap_legend_param = list(at = pretty(range(data[[i]])), + labels = pretty(range(data[[i]]))), + right_annotation = ComplexHeatmap::rowAnnotation(link = + anno_mark(at = rowlab.index, + labels = rowlab, + which = "row", + lines_gp = grid::gpar(fontsize = 5), + link_width = grid::unit(3, "mm"), + padding = grid::unit(0.8, "mm"), + labels_gp = grid::gpar(fontsize = 7)))) + } else { + col_fun = circlize::colorRamp2(c(0, 1), color[[i]]) + + ht[[i]] <- ComplexHeatmap::Heatmap(matrix = as.matrix(data[[i]]), + row_title = row.title[i], + name = legend.name[i], + cluster_columns = clust.dend, + cluster_rows = hcg, + show_column_dend = show.col.dend, + show_column_names = show.colnames, + show_row_dend = show.row.dend[i], + show_row_names = show.rownames[i], + col = color[[i]], + top_annotation = switch((i == 1) + 1, NULL, ha), + width = grid::unit(width, "cm"), + height = grid::unit(height, "cm"), + heatmap_legend_param = list(at = c(0, 1), + legend_gp = grid::gpar(fill = col_fun(c(0,1))), + labels = c("0", "1")), + right_annotation = ComplexHeatmap::rowAnnotation(link = + anno_mark(at = rowlab.index, + labels = rowlab, + which = "row", + lines_gp = grid::gpar(fontsize = 5), + link_width = grid::unit(3, "mm"), + padding = grid::unit(0.8, "mm"), + labels_gp = grid::gpar(fontsize = 7)))) + } + } + } + + if(n_dat == 1){ + ht_list <- ht[[1]] + } + if(n_dat == 2){ + ht_list <- ht[[1]] %v% ht[[2]] + } + if(n_dat == 3){ + ht_list <- ht[[1]] %v% ht[[2]] %v% ht[[3]] + } + if(n_dat == 4){ + ht_list <- ht[[1]] %v% ht[[2]] %v% ht[[3]] %v% ht[[4]] + } + if(n_dat == 5){ + ht_list <- ht[[1]] %v% ht[[2]] %v% ht[[3]] %v% ht[[4]] %v% ht[[5]] + } + if(n_dat == 6){ + ht_list <- ht[[1]] %v% ht[[2]] %v% ht[[3]] %v% ht[[4]] %v% ht[[5]] %v% ht[[6]] + } + + outFile <- file.path(fig.path,paste0(fig.name,".pdf")) + if(is.null(annCol)) { + pdf(outFile, width = width, height = height * n_dat/2) + } else { + pdf(outFile, width = width, height = height * n_dat/1.5) + } + draw(ht_list, merge_legend = TRUE, heatmap_legend_side = "right") # output to pdf + invisible(dev.off()) + + draw(ht_list, merge_legend = TRUE, heatmap_legend_side = "right") # output to screen + + options(warn = defaultW) +}