--- title: "Interactivate heatmaps indirectly generated by pheatmap(), heatmap.2() and heatmap()" author: "Zuguang Gu ( z.gu@dkfz.de )" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: width: 8 fig_width: 5 vignette: > %\VignetteIndexEntry{5. Interactivate heatmaps indirectly generated by pheatmap(), heatmap.2() and heatmap()} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, echo = FALSE} library(knitr) knitr::opts_chunk$set( error = FALSE, tidy = FALSE, message = FALSE, warning = FALSE, fig.width = 6, fig.height = 6, fig.align = "center" ) library(GetoptLong) options(digits = 4) ``` ```{r, echo = FALSE} library(SC3) library(GOexpress) ``` With **InteractiveComplexHeatmap**, the following heatmaps can be exported as an interactive Shiny app: 1. heatmaps directly produced from **ComplexHeatmap**, 2. heatmaps from other functions or packages which are implemented with **ComplexHeatmap**, 3. heatmaps originally produced by `stats::heatmap()`, `gplots::heatmap.2()` and `pheatmap::pheatmap()`, but can be reproduced by the "translation functions": `ComplexHeatmap:::heatmap()`, `ComplexHeatmap:::heatmap.2()` and `ComplexHeatmap::pheatmap()`. All these types of heatmaps can be turned into interactive just by calling `htShiny()` after the heatmaps are drawn. E.g.: ```{r eval = FALSE} ComplexHeatmap::pheatmap(...) htShiny() ``` which means you don't need to touch your heatmap code. After you see the heatmap in your R terminal or generated in a file, directly calling `htShiny()` with no argument will produce an interactive heatmap, like magic. :P Now there is a fourth scenario where the heatmap is produced by third-party functions which internally use `stats::heatmap()`, `gplots::heatmap.2()` or `pheatmap::pheatmap()`. Since now we cannot directly interact with `heatmap()`, `heatmap.2()` or `pheatmap()`, how can we turn these heatmaps into interactive? The solution is fairly simple. We just need to go to _e.g._ **pheatmap** namespace and replace `pheatmap` with `ComplexHeatmap::pheatmap`. The following example is from the **SC3** package where function `sc3_plot_expression()` internally uses `pheatmap()`. ```{r, eval = FALSE} library(SingleCellExperiment) library(SC3) library(scater) sce <- SingleCellExperiment( assays = list( counts = as.matrix(yan), logcounts = log2(as.matrix(yan) + 1) ), colData = ann ) rowData(sce)$feature_symbol <- rownames(sce) sce <- sce[!duplicated(rowData(sce)$feature_symbol), ] sce <- runPCA(sce) sce <- sc3(sce, ks = 2:4, biology = TRUE) sc3_plot_expression(sce, k = 3) ``` To replace the internally use of `pheatmap::pheatmap` with `ComplexHeatmap::pheatmap`, we can use `assignInNamespace()` to directly change the value of `pheatmap` in **pheatmap** namespace. After that, recalling `sc3_plot_expression()` will directly use `ComplexHeatmap::pheatmap()` and now you can use `htShiny()` to export it as an interactive app. Of course, you need to regenerate the heatmap with the same code. ```{r, eval = FALSE} assignInNamespace("pheatmap", ComplexHeatmap::pheatmap, ns = "pheatmap") library(InteractiveComplexHeatmap) sc3_plot_expression(sce, k = 3) htShiny() ``` If you check the source code of `sc3_plot_expression()`, `pheatmap()` is used by explicitely adding its namespace (check the last few lines of the function definition): ```{r} selectMethod("sc3_plot_expression", signature = "SingleCellExperiment") ``` In this case, changing `pheatmap` in **pheatmap** namespace directly affects `sc3_plot_expression()`. However, if the heatmap function is called without adding the namespace (_e.g._, in previous example, the `pheatmap::` prefix), you need to first unload the package, modify the heatmap function in the heatmap namespace and later load the package back. Let's look at the next example from **GOexpress** package where the function `heatmap_GO()` internally use `heatmap.2()`. ```{r, eval = FALSE} library(GOexpress) data(AlvMac) set.seed(4543) AlvMac_results <- GO_analyse( eSet = AlvMac, f = "Treatment", GO_genes=AlvMac_GOgenes, all_GO=AlvMac_allGO, all_genes=AlvMac_allgenes) BP.5 <- subset_scores( result = AlvMac_results.pVal, namespace = "biological_process", total = 5, p.val=0.05) heatmap_GO( go_id = "GO:0034142", result = BP.5, eSet=AlvMac, cexRow=0.4, cexCol=1, cex.main=1, main.Lsplit=30) ``` Now note in `heatmap_GO()` function, `heatmap.2()` is used without **gplots** namespace (go to the end of the function definition listed below). ```{r} heatmap_GO ``` In this case, since we have already loaded the **GOexpress** namespace, the **GOexpress** namespace should firstly be removed by `detach()`, or else `heatmap_GO()` will still use `gplots::heatmap.2()`. ```{r, eval = FALSE} detach("package:GOexpress", unload = TRUE) assignInNamespace("heatmap.2", ComplexHeatmap:::heatmap.2, ns = "gplots") library(GOexpress) library(InteractiveComplexHeatmap) heatmap_GO( go_id = "GO:0034142", result = BP.5, eSet=AlvMac, cexRow=0.4, cexCol=1, cex.main=1, main.Lsplit=30) htShiny() ``` In the end, to safely change all `stats::heatmap()`, `gplots::heatmap.2()` and `pheatmap::pheatmap()` to `ComplexHeatmap:::heatmap()`, `ComplexHeatmap:::heatmap.2()` and `ComplexHeatmap::pheatmap()`, you can add following lines to the start of your R session: ```{r, eval = FALSE} library(pheatmap) library(gplots) assignInNamespace("heatmap", ComplexHeatmap:::heatmap, ns = "stats") assignInNamespace("heatmap.2", ComplexHeatmap:::heatmap.2, ns = "gplots") assignInNamespace("pheatmap", ComplexHeatmap::pheatmap, ns = "pheatmap") ``` You can find runnable examples in `htShinyExample(8.1)`, `htShinyExample(8.2)` and `htShinyExample(8.3)`.