Efficient way to plot multiple ggplots from list using gridextra? - r

I have generated a list containing 25 ggplot elements and I want to plot them all on one page. Since I couldn't find a way to use par() for ggplots, I used the package gridextra and specifically the function grid.arrange().
It comes in less handy than par() for base-R plots....My attempt was the following and I wonder if there is a more efficient way to write it?
Thanks in advance!
plot_collection <- grid.arrange(DBScan_plots[[1]], DBScan_plots[[2]], DBScan_plots[[3]], DBScan_plots[[4]], DBScan_plots[[5]],
DBScan_plots[[6]], DBScan_plots[[7]], DBScan_plots[[8]], DBScan_plots[[9]], DBScan_plots[[10]],
DBScan_plots[[11]], DBScan_plots[[12]], DBScan_plots[[13]], DBScan_plots[[14]], DBScan_plots[[15]],
DBScan_plots[[16]], DBScan_plots[[17]], DBScan_plots[[18]], DBScan_plots[[19]], DBScan_plots[[20]],
DBScan_plots[[21]], DBScan_plots[[22]], DBScan_plots[[23]], DBScan_plots[[24]], DBScan_plots[[25]],
nrow = 5,
ncol = 5)

grid.arrange works with lists of plots. Just specify it with grobs = .
In your case:
plot_collection <- grid.arrange(grobs = DBScan_plots, nrow = 5, ncol = 5)

Related

How to save 2 separate ggplots overlapping in the same pdf in R?

I have 2 ggplots: plot1 and plot2
When I show them in R using:
multi.page <- ggarrange(plot1, plot2,
nrow = 1, ncol = 1)
I get the overlap, but when I then want to safe this overlapping images as PDF it is not possible:
ggsave('/path/image.pdf',plot=multi.page,width=8,height=5)
Does anyone know a way?
Maybe with ggplot_add?
Thank you!
Instead of using ggsave, you could use the pdf device directly:
pdf('/path/image.pdf')
print(multi.page)
dev.off()
And you will have a pdf with your two plots on separate pages.

Plot ggplots stored in list over several pages

I know similar questions have been already asked so sorry if this is a redundant question! However, I can't seem to find a solution that arranges several ggplots from a list onto 1 page over several pages.
I have a list of approximately 100 ggplots - I want to plot every 4 ggplots on 1 page, and iterate through the list until all the ggplots have been plotted. I then want to export the approximately 25 pages to a single pdf file.
So far, I've tried:
pdf("plots.pdf", onefile = TRUE, width = 11, height = 8.5)
for (i in 0:24) {
ggarrange(list[[4i+1]], list[[4i+2]], list[[4i+3]], list[[4i+4]],
nrow = 2, ncol = 2, common.legend = TRUE, legend = 'bottom'
}
dev.off()
However, I'm getting the error that the subscript is out of bounds. I've tried narrowing the range in the for loop to try to overcome this error but it's returning the same error. I also know we can use marrangeGrob(), but I can't seem to add a common legend to the file.
Really appreciate any help!
It would be helpful if you could provide some small list of plots to test on.
I have tried to recreate your scenario, and have found that it wasn't working unless I explicitly print the ggarrange object.
plot <- ggplot(mtcars, aes(x = cyl, y = mpg)) +
geom_point()
plot_list <- list(plot, plot, plot, plot, plot, plot, plot, plot)
pdf("test.pdf", 11, 8.5)
for(i in 0:3){
print(ggarrange(plot_list[[2*i + 1]], plot_list[[2*i + 1]], nrow = 2, ncol = 1))
}
dev.off()
This worked for me. Noting akrun's comment that you forgot your * symbol.

Join Multiple R Rastervis levelplots

I have two rasterstacks, each with a common legend, that I want to put on a single plot with a space in between stacks. I want the raster images to be the same size within each block and across blocks. Is there an easy way to do this using Rastervis::levelplot. I believe the best way is too add a legend to grid.arrange object, as in this MWE
library(raster)
library(rasterVis)
s <- stack(
raster( matrix(runif(9),3,3)),
raster( matrix(runif(9),3,3)) )
gridExtra::grid.arrange(
levelplot(s, colorkey=FALSE, at=seq(0,1,length.out=11)),
levelplot(s, at=seq(0,1,length.out=11)),
ncol=2)
An even simpler solution would be to do this from within a single leveplot call
I think you are looking to do something like this:
levObj <- levelplot(s)
comb_levObj <- c(levObj, levObj, layout = c(4, 1), merge.legends = F)
print(comb_levObj)
But, a simpler solution would be:
s <- stack(s,s)
levelplot(s)

single call of `plot()` for plotting 3 separate plots in R?

Suppose I have the following 3 matrices:
p.b7.4 = matrix(1:4, nrow = 2)
p.b6.4 = matrix(1:6, nrow = 3)
p.b5.4 = matrix(1:8, nrow = 4)
Further suppose, I divide my graphical device in 3 particularly ordered pieces:
m = matrix(1:3); layout(m)
Question
I'm wondering, at this point, if there is a way I could use a single plot() call to plot these 3 matrices above in my graphical device?
NOTE: This means I want 3 separate plots.
You can achieve the 3 separate plots using a lapply():
lapply(list(p.b5.4, p.b6.4, p.b7.4), plot)
I'm not quite sure what you mean. Do you mean something like this?:
plot(p.b7.4,xlim=c(1,10),ylim=c(1,10),col="red",pch=16,cex=2)
points(p.b6.4,col="blue",pch=16,cex=2)
points(p.b5.4,col="green",pch=16,cex=2)

to display two heatmaps in same pdf side by side in R

i am trying to display two or more heatmaps side by side in the same png or pdf . The layout or mfcol is not working in the case. Can someone please help me out with this.
Here's one option using the recently introduced gridGraphics package,
library(gridGraphics)
library(grid)
heatmap(as.matrix(mtcars))
library(gridGraphics)
grab_grob <- function(){
grid.echo()
grid.grab()
}
g <- grab_grob()
grid.newpage()
# library(gridExtra)
# grid.arrange(g,g, ncol=2, clip=TRUE)
lay <- grid.layout(nrow = 1, ncol=2)
pushViewport(viewport(layout = lay))
grid.draw(editGrob(g, vp=viewport(layout.pos.row = 1,
layout.pos.col = 1, clip=TRUE)))
grid.draw(editGrob(g, vp=viewport(layout.pos.row = 1,
layout.pos.col = 2, clip=TRUE)))
upViewport(1)
As stated in the help document for heatmap.2,
'heatmap.2()' uses 'layout' and draws the 'image' in the lower
right corner of a 2x2 layout. Consequentially, it can not be
used in a multi column/row layout, i.e., when 'par(mfrow= *)' or
'(mfcol= *)' has been called.
The same is true for heatmap.
Here's a way of doing that. It is very hacky but I think that when a function doesn't do what you want to do the best solution is to make it do it anyway.
Function heatmap.2 contains the following three lines at mid-way through its code:
...
op <- par(no.readonly = TRUE)
on.exit(par(op))
layout(lmat, widths = lwid, heights = lhei, respect = FALSE)
...
It is because of them that you can't use layout and par(mar=...) since it overrides it.
Copy the code of heatmap.2 into a new function (say heatmap.3) and remove those three lines:
heatmap.3 <- function(... #etc etc with the exact same code minus those 3 lines
Then your code to produce your two heatmaps side by side will be, for instance:
layout(rbind(c(4,3,8,7),c(2,1,6,5)),
widths = c(1,2,1,2), heights = c(1,2), respect = FALSE)
heatmap.3(x)
heatmap.3(y)
When preparing your layout remember that the heatmap code plot first the heatmap itself, then the "row" dendrogram, then the "col" dendrogram and finally the histogram, hence the order from top to bottom, left to right is 4, 3, 2, 1 meaning when both heatmap are side by side it becomes 4, 3, 8, 7, 2, 1, 6, 5.
After having exactly the same problem, I came up with the following solution:
1) Use ggplot2 to make your heatmap with dendrogram like here: Reproducing lattice dendrogram graph with ggplot2 and then arrange it with multiplot() function (http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_%28ggplot2%29/)
2) However, this is a lot of work and I wanted to stick with the base heatmap() function. The following is easy (though not plain R) and works on Linux if you have imagemagick installed:
m <- matrix(runif(10^2), ncol=10)
for (i1 in 1:4) {
ifile <- paste0(i1,'_heatmap.pdf')
pdf(ifile)
heatmap(m)
d <- dev.off()
}
system('montage -geometry 100% -tile 2x2 ./*_heatmap.pdf outfile.pdf')

Resources