Reputation: 234
I am exploring R to analyze my gene expression data.
I could create a pretty heatmap using the pheatmap
package. However, while transitioning between different colored boxes, it automatically introduces a border color which I can see after zooming in. This is in spite of adding the attribute border_color = "NA"
. Is it possible to get continuously varying heatmap? Thanks.
My code:
pheatmapM <-pheatmap(datExprM, border_color = "NA", breaks = NULL, color = colorRampPalette(c("navy", "black", "yellow"))(50), cluster_rows = TRUE, cluster_cols = TRUE, scale = "row")
As you can see below (after zooming), the neighboring boxes are separated by lighter colors.
Upvotes: 8
Views: 11169
Reputation: 57
You can edit the border colours individually for each cell, which can be used to solve this. The exact solution will depend on the exact composition of your pheatmap
object.
First, get the names of grobs (graphical objects) stored in your heatmap. You will need to grab the one which corresponds to the individual rectangles (cells) of the heatmap. For me, this is the first grob of class gTree
, but try and see which one works for you. This is how I extract the name of the grob:
grob_classes <- purrr::map(pheatmapM$gtable$grobs, class)
idx_grob <- which(purrr::map_lgl(grob_classes, function(cl) 'gTree' %in% cl))[1]
Next, we need to find a rectangle grob that is a child of the gTree
grob we've just found, like this:
grob_names <- names(pheatmapM$gtable$grobs[[idx_grob]]$children)
idx_rect <- grob_names[grep('rect', grob_names)][1]
Now, from this nested grob you can extract graphical parameters: fill
(which determines the actual fill colour of each cell) and col
(which determines border colour). By default, col
is a single value whereas fill
is a matrix of hex codes. When I replace col
with what is stored in fill
, like this...
pheatmapM$gtable$grobs[[idx_grob]]$children[[idx_rect]]$gp$col <- pheatmapM$gtable$grobs[[idx_grob]]$children[[idx_rect]]$gp$fill
...that amounts to eliminating the border, since it's now the same colour as the fill. To make extra-sure that no gaps between the cells remain, increase the border thickness as well.
pheatmapM$gtable$grobs[[idx_grob]]$children[[idx_rect]]$gp$lwd <- 3
In my estimation, potential problems might arise with identifying the correct idx_grob
or idx_rect
in your particular pheatmap
. For that reason, I include a reproducible example (with R 4.0.3
and pheatmap 1.0.12
running on macOS) that achieves the desired result (no borders as well as no gaps in between the cells) that you can use to start off:
set.seed(1)
## Generate sample data
x <- table(round(rnorm(500, 100, 2)), round(rnorm(500, 100, 2)))
ph <- pheatmap::pheatmap(x, cluster_cols = FALSE, cluster_rows = FALSE)
## Extract the right grob
grob_classes <- purrr::map(ph$gtable$grobs, class)
idx_grob <- which(purrr::map_lgl(grob_classes, function(cl) 'gTree' %in% cl))[1]
grob_names <- names(ph$gtable$grobs[[idx_grob]]$children)
idx_rect <- grob_names[grep('rect', grob_names)][1]
## Remove borders around cells
ph$gtable$grobs[[idx_grob]]$children[[idx_rect]]$gp$col <- ph$gtable$grobs[[idx_grob]]$children[[idx_rect]]$gp$fill
ph$gtable$grobs[[idx_grob]]$children[[idx_rect]]$gp$lwd <- 3
## Plot result
graphics::plot.new()
print(ph)
The result should look like this:
Upvotes: 0