Abhishek Parab
Abhishek Parab

Reputation: 234

No border color in "pheatmap" in R

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")

My heatmap

As you can see below (after zooming), the neighboring boxes are separated by lighter colors.

Zoomed heatmap with lighter borders

Upvotes: 8

Views: 11169

Answers (1)

davnovak
davnovak

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

Related Questions