Using a pheatmap in arrangeGrob - r

I'm attempting to plate two plots in the same .jpg using arrangeGrob().
I've only just started learning about grids and grobs and I think I know what the problem is: pheatmap is a grid object and containing grob objects, not allowing me to put it in arrangeGrob. Is this true?
Would I somehow need to put the qplot in a grid and the pheatmap in a grid and then put those grids in a new grid?
library(grid)
library(gridExtra)
library(pheatmap)
library(ggplot2)
hmdat=rbind(c(1,2,3),
c(3,4,5),
c(5,6,7))
hm=pheatmap(hmdat)
qp=qplot(1,1)
lm=rbind(c(1,2,2),
c(1,2,2))
jpeg("plots.jpg")
arrangeGrob(qp,hm, layout_matrix=lm)
dev.off()
The above code snippet runs just fine when using
arrangeGrob(qp,qp, layout_matrix=lm)

I'm not sure if you wanted to have 6 figures or you wanted to have two figures one with twice as wide as the other one (I tried to do minimum code change):
library("grid")
library("gridExtra")
library("pheatmap")
library("ggplot2")
hmdat=rbind(c(1,2,3),
c(3,4,5),
c(5,6,7))
hm <- pheatmap::pheatmap(hmdat)
qp <- qplot(1,1)
lm <- rbind(c(1,2,2),
c(1,2,2))
grid.arrange(grobs = list(qp,hm[[4]]), layout_matrix = lm)
which will give you:
The same way you can have multiple pheatmaps side-by-side:
library("grid")
library("gridExtra")
library("pheatmap")
hmdat <- rbind(c(1,2,3),
c(3,4,5),
c(5,6,7))
hm <- pheatmap::pheatmap(hmdat)
lm <- rbind(c(1,2),
c(3,3))
grid.arrange(grobs = list(hm[[4]],
hm[[4]],
hm[[4]]),
layout_matrix = lm)
As #hrbrmstr mentioned in the comment, you should use the 4th item in the pheatmap object. Also remember to provide grobs as list to the grid.arrange

Related

arrange R plots: how can I arrange plots of the VIM package?

I would like to generate multiple plots using marginplot() (VIM package) and then arrange them into one big figure. I tried to use grid.arrange (grid/gridExtra package) and it did not work. The error was, that a grob was expected as input. So I tried to first convert the marginplot into a ggplot (as.ggplot) or grob (as.grob) but this did not work. Has anyone an idea how to arrange the plots?
library(VIM)
library(ggplotify)
library(grid)
library(gridExtra)
x <- cars[, c("speed", "dist")]
marginplot(x)
y <- cars[, c("speed", "dist")]
marginplot(y)
p <- qplot(1,1)
#p2 <- as.ggplot(marginplot(x))
r <- rectGrob(gp=gpar(fill="grey90"))
grid.arrange( r, p,p, r, ncol=2)
I created a small code with cars, where I managed to arrange grey squares and qplots. put I cannot add the marginplot.
With base plots this error occurs. Learned here: grid.arrange from gridExtras exiting with "only 'grobs' allowed in 'gList'" after update
grid.arrange is intended to be used with "grid graphical objects" (grobs), such as ggplot2.
One could find an equivalent grid-plot or use a base-graphics approach to stacking plots.
Try this:
library(VIM)
x <- cars[, c("speed", "dist")]
y <- cars[, c("speed", "dist")]
par(mfrow = c(2,2))
marginplot(x)
marginplot(y)
plot(rnorm(100))
hist(rnorm(100))
par(mfrow = c(1, 1)) #reset this parameter

rasterVis - setting the bottom plots in the middle with levelplot

I am using the awesome rasterVis to create a panel with maps that have the same extent (i.e. same spatial coverage) but that show different features (i.e. each with its own legend).
This is what it looks like so far:
library(raster)
library(rasterVis)
library(RColorBrewer)
library(gridExtra)
# make-up data
r <- raster(system.file("external/test.grd", package="raster"))
s <- stack(r, r*2, r*3, r*4, r*5)
names(s) <- paste0("Field ",seq(1,5))
# pre-allocate list
l <- vector("list", length=nlayers(s))
# define theme for plots
my.theme <- rasterTheme(region=brewer.pal(11,'RdYlGn'))
# loop over stack layers to fill list
for (n in (1:nlayers(s))){
l[[n]] <- levelplot(s[[n]], margin=F, main=names(s[[n]]), par.settings=my.theme)
}
# plot combined maps
grid.arrange(l[[1]], l[[2]], l[[3]], l[[4]], l[[5]], ncol=3)
Note that the default positioning for the maps is:
a b c
d e
However, I would like to have a finer control on the positioning. Specifically, I would like to "center" the bottom two facets in order to distribute the void space more evenly on the sides of the plot.
In other words, the placement I am looking for would look like:
a b c
d e
How can I achieve this? I looked up the documentation for (grid.arrange), but couldn't find any option the would solve my problem.
Thanks in advance for any hints.
Here's an approach with cowplot::plot_grid inspired by this answer
library(cowplot)
top <- plot_grid(l[[1]], l[[2]], l[[3]],
ncol=3)
bottom <- plot_grid(NULL, l[[4]], NULL, l[[5]], NULL,
ncol=6, rel_widths=c(0.12,0.34,0.12,0.34,0.06))
plot_grid(top, bottom,
ncol=1, rel_heights=c(1,1))
You can modify the rel_widths in the bottom plot_grid call to get it just like you like.
You can provide a layout with 6 columns and use NA for the blanks,
library(gridExtra)
p <- ggplot()
grid.arrange(grobs = list(p,p,p,p,p),
layout_matrix = rbind(c(1,1,2,2,3,3), c(NA,4,4,5,5,NA)))

Arrange odd number of plots using rasterVis and gridExtra

I am trying to plot a panel with seven rasters using the levelplot function of the rasterVis package, combined with gridExtra's grid.arrange.
I almost get what I need by using the following code:
# load required packages
library(rasterVis)
library(gridExtra)
# load sample raster
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
# create plots
p1 <- levelplot(r, xlab=NULL, ylab=NULL, margin=FALSE)
p2 <- levelplot(r*2, xlab=NULL, ylab=NULL, margin=FALSE,colorkey=FALSE)
# put plots in list
p.list <- list(p1,p2,p2,p2,p2,p2,p2)
# create layout
lay <- rbind(c(1,1,1),
c(2,3,4),
c(5,6,7))
# arrange plots
grid.arrange(grobs=p.list, layout_matrix=lay)
which yields this figure:
However, there are some things I still need to improve:
How to decrease the blank space between the plots in the bottom rows?
How to add a single, combined legend for the six bottom rasters, preferentially put to the bottom of the figure?
Is this possible to achieve using rasterVis and gridExtra? Is there any other approach that can be used?
The white space is a combination of lattice margin settings, but also the plots having a fixed aspect ratio (they can't be too close unless the device itself has a compatible aspect ratio).
With regards the legend, you could use draw.colorkey(), but from what I can tell you need to manually ensure that the colours match by passing them explicitly to both plots and the key.
# load required packages
library(rasterVis)
library(gridExtra)
# load sample raster
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
my_theme <- rasterTheme(region = blues9)
# create plots
p1 <- levelplot(r, xlab=NULL, ylab=NULL, margin=FALSE, par.settings = my_theme)
leg <- p1$legend$right$args$key
p1$legend <- list()
p2 <- levelplot(r*2, xlab=NULL, ylab=NULL, margin=FALSE,colorkey=FALSE, par.settings = my_theme)
# put plots in list
p.list <- list(p1,p2,p2,p2,p2,p2,p2)
# create layout
lay <- rbind(c(NA,1,NA),
c(2,3,4),
c(5,6,7),
c(8,8,8))
leg$col <- my_theme$regions$col
legGrob <- draw.colorkey(key = leg, vp = grid::viewport(height=0.5))
# arrange plots
grid.arrange(grobs=c(p.list, list(legGrob)), layout_matrix=lay,
vp = grid::viewport(width=0.7,height=1))
(needless to say, facetting seems the better option by a wide margin)

Multiple lattice plots with gridExtra

There is very convenient way of plotting multiple graphs and that's with gridExtra - grid.arrange:
grid.arrange(plot1,plot2,plot3,plot4,plot5,plot6,plot7,plot8,plot9, ncol=3)
The above command draws 3x3 graphs in one window.
Now, I'm using my own lattice setup to draw unique lines etc. via
trellis.par.set(my.setup)
However using the grid.arrange command for plotting multiple plots won't pass on the setup as the output plots are in default colours.
So the question is how to pass on the my.setup onto grid.arrange or alternatively how to plot easily multiple graphs in one go for lattice.
EDIT: Reproducible example:
Data <- data.frame(Col1=rnorm(10,0,1),Col2=rexp(10,2),Col3=rnorm(10,2,2),Col4=runif(10,0,2),
Time=seq(1,10,1))
trellis.par.set(col.whitebg())
newSet <- col.whitebg()
newSet$superpose.symbol$col <- c("blue3","orange2","gray1","tomato3")
newSet$superpose.symbol$pch <- 1
newSet$superpose.symbol$cex <- 1
newSet$superpose.line$col <- c("blue3","orange2","gray1","tomato3")
trellis.par.set(newSet)
Plot1 <- xyplot(Col1+Col2~Time, Data, type="spline")
Plot2 <- xyplot(Col2+Col3~Time, Data, type="spline")
Plot3 <- xyplot(Col1+Col3~Time, Data, type="spline")
Plot4 <- xyplot(Col3+Col4~Time, Data, type="spline")
grid.arrange(Plot1,Plot2,Plot3,Plot4, ncol=2)
I guess it's got something to do with the plot.trellis method not finding the global theme settings when it's wrapped in gridExtra::drawDetails.lattice. I don't understand these lattice options, but as far as I recall you can specify them explicitly at the plot level too,
pl = list(Plot1, Plot2, Plot3, Plot4)
# do.call(grid.arrange, c(pl, nrow=1))
do.call(grid.arrange, c(lapply(pl, update, par.settings=newSet), list(nrow=1)))

grid.arrange with John Fox's effects plots

I'd like to combine multiple effect plots in one window with the effects package, but don't know if there is an easy way to do so.
Here's an example that doesn't work:
d1 <-data.frame(x1=rnorm(100,0:10),y1=rnorm(100,0:10),x2=rnorm(100,0:10),y2=rnorm(100,0:10))
require(effects)
require(gridExtra)
plot1 <- plot(allEffects(mod=lm(y1~x1,d1)))
plot2 <- plot(allEffects(mod=lm(y2~x2,d1)))
grid.arrange(plot1,plot2,ncol=2)
I think you need to collect the values of allEffects components and then plot them as an 'efflist'. It looked to me that the plotting was base-graphics, but it is in fact 'lattice' if you follow the class-function trail (or if you read: ?plot.efflist )
Try this:
ef1 <-allEffects(mod=lm(y1~x1,d1))[[1]]
ef2 <- allEffects(mod=lm(y2~x2,d1))[[1]]
elist <- list( ef1, ef2 )
class(elist) <- "efflist"
plot(elist, col=2)
Interestingly, the result from plotting an efflist (which is the result from allEffects) is not a lattice graphic; it instead builds up a multipanel graphic of lattice graphics using the print.lattice methods. However, if you plot the individual effects, either by taking the elements from allEffects or by using effect, then you do get lattice graphics.
Either like this
p1 <- plot(allEffects(m1)[[1]])
p2 <- plot(allEffects(m2)[[1]])
or like this.
p1 <- plot(effect("x1", m1))
p2 <- plot(effect("x2", m2))
These can be combined with grid.arrange; the catch is that their class is c("plot.eff", "trellis") which grid.arrange doesn't recognize, so they have to be made into simple trellis objects first.
class(p1) <- class(p2) <- "trellis"
grid.arrange(p1, p2, ncol=2)

Resources