This is a test version of Biostars. For the public version, visit https://www.biostars.org.
how to plot multi pheatmap into one figure

I'd want to combine 3 pheatmap into 1 figure. Here is the test code. it seems mfrow parameter does not work for it.

test = matrix(rnorm(200), 20, 10)
test[1:10, seq(1, 10, 2)] = test[1:10, seq(1, 10, 2)] + 3
test[11:20, seq(2, 10, 2)] = test[11:20, seq(2, 10, 2)] + 2
test[15:20, seq(2, 10, 2)] = test[15:20, seq(2, 10, 2)] + 4
colnames(test) = paste("Test", 1:10, sep = "")
rownames(test) = paste("Gene", 1:20, sep = "")

par(mfrow=c(1,2))
pheatmap(test)
pheatmap(test, kmeans_k = 2)
pheatmap(test, kmeans_k = 3)
pheatmap plotting par

Normally one just uses Adobe Illustrator or Inkscape to make the final figures. While you certainly can try to arrange everything in R, that's really not its forte.

@Devon, Thanks. The Inkscape or others need plot this kind of figure manually but not automatically. That's the point.

Stuff like this is why I had to write my own heatmap generating code (calls image()). I use layout() to set up multi-heatmap figures. It's pretty ugly.

2 answers

If it's just for the one figure, I'd do it manually in Inkscape. However, for high throughput figure production, I would export individual images from R and script the final figure assembly from the components, for example using ImageMagick. You could also write an SVG file directly (for example with the perl module SVG) or by scripting Inkscape.

why R can not do it ? it's strange. It usually works for other kind of plotting. I prefer using only one language if possible.

A lot of heatmap functions use layout() and image() internally, so some of the things you specify via par() will be overridden. This is at least the case for heatmap.2() in the gplots library.

I am sure R can do it (have you tried ggplot2 ?) but it's likely unwieldy and not intuitive, unless of course, one is an R aficionado :) I find that R can generate simple plots quite easily but when it comes to getting to publication-quality figures (at least for biology journals), it's quickly getting more complicated. In line with the idea of assembling the components produced separately, you can output SVG files in R with the svg function then, since SVG is XML, you could also edit/combine these files in R.

Agreed, in this case, one would need to directly modify the pheatmap source code. pheatmap directly specifies viewports to draw things in. I don't know enough about the internals of R graphics production, but I imagine that that would override anything set via users.

Sometimes R with a bit of external scripting really is the simplest route.

Hi all, I know my answer is ~3years too late but I just want to put it out there and hopefully people will find this useful in the future. I found the answer here

Basically, user hrbrmstr mentioned that "The manual page for pheatmap() clearly states in the Values section that it returns a list of components, but it fails to mention component #4, which is the gtable of the plot. You have to index it specifically since it's not going to trigger R's print method lookup/execution for that object inside the function call."

For my case, I did the following:

items=unique(ra_items$column)
plot_list=list()
for (a in items){
x=pheatmap(as.matrix(data),
             cluster_rows = F,
             fontsize = 14,
             main = a)
  plot_list[[a]] = x[[4]]     ##to save each plot into a list. note the [[4]]
}
g<-do.call(grid.arrange,plot_list)
ggsave("g.pdf",g)

Thank you for posting the answer. I can across it today, and it was very helpful for me.

Instead of grid.arrange with do.call, you could also use arrangeGrob. arrangeGrob gives you the chance to specify the layout (e.g. number of rows and columns for the combined plots.

g <- grid.arrange(arrangeGrob(grobs= plot_list,ncol=2))

You can do that with do.call as well

do.call("grid.arrange", c(plot_list, ncol=2))

Also, rather than using a for cycle, I would use lapply here.

Thanks for this. I could not use grob, but your comment and the solution here helped me:

p1=pheatmap(...)
p2=pheatmap(...)
plot_list=list()
plot_list[['p1']]=p1[[4]]
plot_list[['p2']]=p2[[4]]

grid.arrange(grobs=plot_list, ncol=2)

Log in to answer this question.