4 min read

Textbox annotation

In a previous post “Word cloud as heatmap annotation”, I introduced how to make word clouds and attach them to heatmaps as annotations. Here I will introduce a more general solution for making textboxes.

The following new functions are implemented in ComplexHeatmap from version 2.13.1. Now you need to update ComplexHeatmap from GitHub.

First I will demonstrate a low-level grid.* family function grid.textbox(). The function simply accepts a vector of texts. If the col parameter is not specified in gpar(), random colors are used.

library(ComplexHeatmap)
set.seed(888)
words = sapply(1:30, function(x) strrep(sample(letters, 1), sample(3:10, 1)))
grid.newpage()
grid.textbox(words, gp = gpar(fontsize = runif(30, min = 5, max = 30)))

max_width controls the maximal width of the textbox.

grid.newpage()
grid.textbox(words, gp = gpar(col = "red", fontsize = 1:30+5), max_width = unit(9, "in"))

Set round_corners to TRUE, also set background graphics parameters:

grid.newpage()
grid.textbox(words, gp = gpar(fontsize = runif(30, min = 5, max = 30)),
    background_gp = gpar(fill = "#FFEEEE", lty = 2, col = "grey"), round_corners = TRUE,
    padding = unit(c(10, 20, 10, 20), "pt"))

One feature of grid.textbox() is it can properly handle long phrases or sentences which are composed by multiple words. By default, long phrases are treated as single words, which means, if there is no enough space in a line, the whole phrase is moved to the next line.

sentenses = c("This is sentense 1", "This is a long long long long long long long sentense.")
grid.newpage()
grid.textbox(sentenses)

Set word_wrap = TRUE so that long phrases are wrapped if they are too long:

grid.newpage()
grid.textbox(sentenses, word_wrap = TRUE)

If add_new_line is set to TRUE, each phrase is put in a separated line.

grid.newpage()
grid.textbox(sentenses, word_wrap = TRUE, add_new_line = TRUE)

Now we can implement the corresponding annotation function for heatmaps. In ComplexHeatmap, there is a new annotation function anno_textbox(). The two major arguments for anno_textbox() are:

  • align_to: It controls how the text boxes are aligned to the heatmap rows. The value can be a categorical vector which have the same length as heatmap rows, or a list of row indices. It does not necessarily include all row indices.
  • text: The corresponding texts. The value should be a list of texts. To control graphics parameters of texts in the boxes, The value of text can also be set as a list of data frames where the first column contains the text, from the second column contains graphics parameters for each text. The column names should be “col”, “fontsize”, “fontfamily” and “fontface”.
library(circlize)
mat = matrix(rnorm(100*10), nrow = 100)

split = sample(letters[1:10], 100, replace = TRUE)
text = lapply(unique(split), function(x) {
    data.frame(month.name, col = rand_color(12, friendly = TRUE), fontsize = runif(12, 6, 14))
})
names(text) = unique(split)

split
##   [1] "b" "f" "h" "h" "c" "g" "a" "h" "d" "e" "g" "c" "j" "c" "c" "j" "a" "d"
##  [19] "i" "h" "a" "i" "g" "a" "b" "e" "i" "a" "c" "h" "j" "j" "b" "c" "c" "e"
##  [37] "j" "a" "d" "d" "j" "h" "j" "d" "b" "h" "e" "h" "b" "j" "a" "a" "a" "c"
##  [55] "g" "d" "b" "a" "a" "g" "b" "g" "h" "j" "g" "f" "i" "j" "a" "d" "i" "b"
##  [73] "c" "b" "f" "e" "h" "c" "a" "c" "a" "j" "h" "e" "e" "a" "j" "h" "a" "d"
##  [91] "e" "f" "j" "j" "c" "j" "f" "d" "b" "i"
text[1:2]
## $b
##    month.name       col  fontsize
## 1     January #0E0768FF  9.891577
## 2    February #0C8B21FF  7.416968
## 3       March #2C038DFF 12.242896
## 4       April #2AA00CFF 10.454699
## 5         May #74A80DFF  9.777079
## 6        June #4C089AFF  9.825270
## 7        July #4C008FFF  6.179774
## 8      August #0B7C04FF  7.696559
## 9   September #3A810BFF 10.993755
## 10    October #360078FF  8.168969
## 11   November #980228FF  9.337481
## 12   December #960C3DFF 10.450466
## 
## $f
##    month.name       col  fontsize
## 1     January #6E0B9BFF  6.639206
## 2    February #042F7DFF 12.770203
## 3       March #099801FF  9.718325
## 4       April #490E90FF  8.623842
## 5         May #092C79FF 12.441386
## 6        June #0A1274FF  9.944144
## 7        July #051B65FF 13.958028
## 8      August #0A0161FF  6.600719
## 9   September #05833AFF  9.839931
## 10    October #4D7704FF 10.190130
## 11   November #5B098FFF  6.375925
## 12   December #007974FF 10.547464
Heatmap(mat, cluster_rows = FALSE, row_split = split,
    right_annotation = rowAnnotation(wc = anno_textbox(split, text))
)

sessionInfo()
## R version 4.2.0 (2022-04-22)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Big Sur/Monterey 10.16
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] C/UTF-8/C/C/C/C
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
## [1] circlize_0.4.16       ComplexHeatmap_2.13.1 knitr_1.39           
## 
## loaded via a namespace (and not attached):
##  [1] highr_0.9           bslib_0.3.1         compiler_4.2.0     
##  [4] RColorBrewer_1.1-3  jquerylib_0.1.4     iterators_1.0.14   
##  [7] tools_4.2.0         digest_0.6.29       clue_0.3-61        
## [10] jsonlite_1.8.0      evaluate_0.15       png_0.1-7          
## [13] rlang_1.0.2         foreach_1.5.2       cli_3.3.0          
## [16] yaml_2.3.5          parallel_4.2.0      blogdown_0.8       
## [19] xfun_0.31           fastmap_1.1.0       cluster_2.1.3      
## [22] stringr_1.4.0       sass_0.4.1          GlobalOptions_0.1.2
## [25] S4Vectors_0.34.0    IRanges_2.30.0      stats4_4.2.0       
## [28] R6_2.5.1            GetoptLong_1.0.5    rmarkdown_2.14     
## [31] bookdown_0.15       magrittr_2.0.3      codetools_0.2-18   
## [34] htmltools_0.5.2     matrixStats_0.62.0  BiocGenerics_0.42.0
## [37] shape_1.4.6         colorspace_2.0-3    stringi_1.7.6      
## [40] doParallel_1.0.17   crayon_1.5.1        rjson_0.2.21