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

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

Related

Plot Layout of Base R Plots Saved by recordPlot() Function

I can use the recordPlot() function to save Base R plots in data objects:
plot(1:5, 1:5)
my_plot1 <- recordPlot()
plot(1:10, 1:10)
my_plot2 <- recordPlot()
plot(1:20, 1:20)
my_plot3 <- recordPlot()
I would like to draw these three plots in a grid of plots. Usually, I could use the layout function for this. However, this does not work when I want to draw plots created by recordPlot.
This does not work:
layout(matrix(c(1, 0, 2, 3), ncol = 2))
plot.new()
my_plot1
my_plot2
my_plot3
How can I draw a grid of plots saved by the recordPlot() function?
I recently had to solve a similar problem, below are two solutions that may work for you.
(1) use par() to specify numbers of rows/ columns:
# create objects with base plots
plot(rnorm(50),rnorm(50))
my_plot1 <- recordPlot()
plot(rnorm(50),rnorm(50))
my_plot2 <- recordPlot()
plot(rnorm(50),rnorm(50))
my_plot3 <- recordPlot()
# clear plots in workspace
plot.new()
# plot side by side
par(mfrow= c(1,3)) # specify rows (1) and columns (3) for plotting
my_plot1
my_plot2
my_plot3
(2) Save objects to a list and then use plot_grid (cowplot library) - this is good if you need to export the figure:
library(cowplot)
# create empty list
p <- list()
# save objects to list
plot(rnorm(50),rnorm(50))
p[[1]] <- recordPlot()
plot(rnorm(50),rnorm(50))
p[[2]] <- recordPlot()
plot(rnorm(50),rnorm(50))
p[[3]] <- recordPlot()
# clear plots
plot.new()
# plot in 3 columns using plot_grid
plot_grid(plotlist = p, nrow=1, ncol=3)

How do I use qqplot() and assign the output to an object?

I'd like to make an object that has a QQ chart
This is my code
qqnorm(titanic$age)
qqline(titanic$age)
In ggplot, I can layer geoms on top of each other, so they can be in one object
What's the equivalent for this case?
Here's some code as an example. I had to use a different dataset, as the "Titanic" dataset's age column is non-numeric:
data("AirPassengers")
qqnorm(AirPassengers)
qqline(AirPassengers)
lines(x = 1:length(AirPassengers), rep(300, 144))
p <- recordPlot()
p
edit: to disable the plot:
dev.control('inhibit')
plot(rnorm(10))
p <- recordPlot()
dev.off()
in a loop:
for(i in 1:10){
# dev.control('inhibit')
plot(rnorm(10))
p <- recordPlot()
# dev.off()
l_plots[[i]] <- p
}
Somehow it seems difficult to combine the approaches. How about you just delete the plots in the plotting window after creating them?

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)

Using a pheatmap in arrangeGrob

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

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

Resources