jokergoo / ComplexHeatmap

Make Complex Heatmaps
https://jokergoo.github.io/ComplexHeatmap-reference/book/
Other
1.29k stars 225 forks source link

Capture output of complexheatmap as a grob? #110

Closed r-cheologist closed 7 years ago

r-cheologist commented 7 years ago

ComplexHeatmap is a god sent tool with respect to heatmaps as a plot type. As one of the authors of multipanelfigure, I fail, however, to find a straight forward solution to capture the produced heatmap output in a grid::grob object for easy inclusion into scientific compound figures as generated by multipanelfigure. If that doesn't exist: consider this a feature request ;).

jokergoo commented 7 years ago

Currently it is difficult or maybe impossible to save the whole plot as a grob object, but currently I am trying to restrict all viewports for a plot under a certain level of viewport tree, so that the heatmaps can be put to a sub-regions in a higher level layout by using grid.layout(), something like:

pushViewport(viewport(layout = grid.layout(...)))
pushViewport(viewport(layout.row.pos = ..., layout.col.pos = ...))
draw(ht_list, ...)
upViewport()

pushViewport(viewport(layout.row.pos = ..., layout.col.pos = ...))
# other plots
upViewport()
jokergoo commented 7 years ago

I have updated the package a little bit. Although you cannot save the heatmaps as grob object, but you can create viewports manually and fill heatmaps inside afterwards. There are two important steps:

  1. set newpage = FALSE in draw() function, which means you need to use draw() explicitly to make the heatmaps.
  2. use popViewport() to leave and remove the viewport where the heatmaps are made. (Do not use upViewport().

Following is an example

mat1 = matrix(rnorm(100), 10)
mat2 = matrix(rnorm(100), 10)

grid.newpage()
pushViewport(viewport(x = 0, width = 0.5, just = "left"))
grid.rect(gp = gpar(fill = "#FF000020"))
ht_list = Heatmap(mat1) + Heatmap(mat2)
draw(ht_list, newpage = FALSE)
popViewport()

pushViewport(viewport(x = 0.5, y = 1, width = 0.5, height = 0.5, just = c("left", "top")))
grid.rect(gp = gpar(fill = "#00FF0020"))
draw(Heatmap(mat1), newpage = FALSE)
popViewport()

pushViewport(viewport(x = 0.5, y = 0.5, width = 0.5, height = 0.5, just = c("left", "top")))
grid.rect(gp = gpar(fill = "#0000FF20"))
draw(Heatmap(mat2), newpage = FALSE)
popViewport()

image

r-cheologist commented 7 years ago

At stackexchange a kind soul pointed out that grid::grid.grabExprought to work. A colleague tried an in his case at least, he was able to use that function to capture a ConplexHeatmap as a grob and use it in a multipanelfigure compound figure.

Can you verify this? I'm traveling and can't right now. ..

On Tuesday, July 18, 2017, Zuguang Gu wrote:

Currently it is difficult or maybe impossible to save the whole plot as a grob object, but currently I am trying to restrict all viewports for a plot under a certain level of viewport tree, so that the heatmaps can be put to a sub-regions in a higher level layout by using grid.layout().

-- You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub: https://github.com/jokergoo/ComplexHeatmap/issues/110#issuecomment-31618538

-- Sent from my Jolla

jokergoo commented 7 years ago

This is great to know this function!

Yes, you can save current grid plot as a grob object by using grid.grabExpr():

ht_list = Heatmap(mat1) + Heatmap(mat2)
gb = grid.grabExpr(draw(ht_list))
gb
is.grob(gb)
pushViewport(viewport(width = 0.5, height = 0.5))
grid.draw(gb)

And it solves one of my problems which I have been struggling for quite a long time. Now I can capture any type of grid graphics and arrange them as a complex figure and put into papers. Thanks!

image

crazyhottommy commented 7 years ago

@jokergoo could you please give a more detailed code for the figure you show? thanks! for ggplot2 style figures, I use cowplot https://cran.r-project.org/web/packages/cowplot/vignettes/introduction.html.

jokergoo commented 7 years ago

@crazyhottommy here is the code:

mat = matrix(rnorm(100), 10)

gb_heatmap = grid.grabExpr(draw(Heatmap(mat)))
gb_gtrellis = grid.grabExpr({
    gtrellis_layout()
})
gb_ggplot2 = grid.grabExpr({
    p = ggplot(mtcars, aes(wt, mpg)) + geom_point()
    print(p)
})

grid.newpage()
pushViewport(viewport(y = 1, height = 0.5, just = "top"))
grid.draw(gb_gtrellis)
popViewport()

pushViewport(viewport(x = 0, y = 0, width = 0.5, height = 0.5, just = c("left", "bottom")))
grid.draw(gb_heatmap)
popViewport()

pushViewport(viewport(x = 0.5, y = 0, width = 0.5, height = 0.5, just = c("left", "bottom")))
grid.draw(gb_ggplot2)
popViewport()
funnell commented 7 years ago

To use cowplot, convert the heatmap gtree returned from grid.grabExpr into a gtable:

hm_gtable <- gtable_matrix("hm_gtbl", matrix(list(gb_heatmap)), unit(1, "null"), unit(1, "null"))
r-cheologist commented 7 years ago

Closing this issue ... next release of multipanelfigure will have automatic grid::grid.grabExpr-based integration of ComplexHeatmap objects into compound figures ...