I want to plot data for a linear model in a main plot and a plot of the effects (forest plot) as a subplot using arrangeGrob.
Here are the data:
set.seed(1)
main.df <- data.frame(sample=c(paste("E.plus.A.plus",1:3,sep="_"),paste("E.minus.A.plus",1:3,sep="_"),paste("E.plus.A.minus",1:3,sep="_"),paste("E.minus.A.minus",1:3,sep="_")),
replicate=rep(1:3,4),cpm=c(rnorm(12)),
factor.level=factor(c(rep("E.plus.A.plus",3),rep("E.minus.A.plus",3),rep("E.plus.A.minus",3),rep("E.minus.A.minus",3)),
levels=c("E.plus.A.plus","E.minus.A.plus","E.plus.A.minus","E.minus.A.minus")))
effects.df <- data.frame(factor.level=c("E.plus.A.plus-E.minus.A.plus","E.plus.A.plus-E.plus.A.minus","E.plus.A.plus-E.minus.A.minus",
"E.minus.A.plus-E.plus.A.minus","E.minus.A.plus-E.minus.A.minus","E.plus.A.minus-E.minus.A.minus"),
effect=rnorm(6),effect.df=runif(6,0,0.5),p.value=runif(6,0,1),y=1:6+0.2)
effects.df$effect.high <- effects.df$effect+effects.df$effect.df
effects.df$effect.low <- effects.df$effect-effects.df$effect.df
effects.df$factor.level <- factor(effects.df$factor.level,levels=effects.df$factor.level)
The ggplots:
require(ggplot2)
require(grid)
require(gridExtra)
main.plot <- ggplot(main.df,aes(x=replicate,y=cpm,color=factor.level))+geom_point(size=3)+
facet_wrap(~factor.level,ncol=length(levels(main.df$factor.level)))+
labs(x="replicate",y="cpm")+scale_x_continuous(breaks=unique(main.df$replicate))+theme_bw()+
theme(legend.key=element_blank(),panel.border=element_blank(),strip.background=element_blank(),axis.title=element_text(size=8),plot.title=element_text(size=9,hjust=0.5))
Which is:
sub.plot <- ggplot(effects.df,aes(x=effect,y=factor.level,color=factor.level))+geom_point(size=2.5,shape=19)+geom_errorbarh(aes(xmax=effect.high,xmin=effect.low),height=0.1)+
geom_vline(xintercept=0,linetype="longdash",colour="black",size=0.25)+theme_bw()+theme(legend.key=element_blank(),panel.border=element_blank(),strip.background=element_blank(),axis.title=element_text(size=7),axis.text=element_text(size=7),legend.text=element_text(size=7),legend.title=element_text(size=7))+
geom_text(aes(x=effects.df$effect,y=effects.df$y,label=format(signif(effects.df$p.value,2),scientific=T)),size=2.5)
And is:
And here's how I try to combine them into a single plot:
if(!is.null(dev.list())) dev.off()
blank <- grid.rect(gp = gpar(col = "white"))
sub.plot.grob <- arrangeGrob(blank,sub.plot,ncol=1)
combined.plot <- arrangeGrob(main.plot,sub.plot,ncol=2,widths=c(1,1))
grid.arrange(combined.plot)
which gives:
How do I adjust the position and dimensions so that sub.plot is smaller (all layers, e.g., text are reduced proportionally), and is positioned below the legend of main.plot?
I strongly recommend the package cowplot for this sort of task. Here, I am building three nested sets (the main plot to the left, then the two legends together at the top right, then the sub plot at the bottom right). Note the wonderful get_legend function that make pulling the legends incredibly easy.
plot_grid(
main.plot + theme(legend.position = "none")
, plot_grid(
plot_grid(
get_legend(main.plot)
, get_legend(sub.plot)
, nrow = 1
)
, sub.plot + theme(legend.position = "none")
, nrow = 2
)
, nrow = 1
)
gives:
Obviously I'd recommend changing one (or both) of the color palettes, but that should give what you want.
If you really want the legend with the sub.plot, instead of with the other legend, you could skip the get_legend.
You can also adjust the width/height of the sets using rel_widths and rel_heights if you want something other than the even sizes.
As an additional note, cowplot sets its own default theme on load. I generally revert to what I like by running theme_set(theme_minimal()) right after loading it.
here's a grid.arrange solution,
grid.arrange(grobs = replicate(4, ggplot(), simplify = FALSE),
layout_matrix = cbind(c(1,1), c(3,2), c(4, 2)),
widths = c(2,1,1))
with those bits and pieces,
get_legend <- function(p) {
g <- ggplotGrob(p)
id <- grep("guide", g$layout$name)
g$grobs[[id]]
}
leg1 <- get_legend(main.plot); leg2 <- get_legend(sub.plot)
gl <- list(main.plot + theme(legend.position = "none"),
sub.plot + theme(legend.position = "none"), leg1, leg2)
grid.arrange(grobs = gl,
layout_matrix = cbind(c(1,1), c(3,2), c(4, 2)),
widths = c(2,1,1))
Related
I am trying to combine two ggplot objects with patchwork - two plots with different subsets of data, but the same x variable (and therefore same unit). I would like to align the plots according to the x values - Each x unit should have the same physical width in the final plot.
This is very easy when actually plotting the entire width of the larger data set (see plot below) - but I struggle to plot only parts of the data and keeping the same alignment.
library(ggplot2)
library(patchwork)
library(dplyr)
p1 <-
ggplot(mtcars, aes(mpg)) +
geom_density(trim = TRUE) +
scale_x_continuous(limits = c(10,35))
p2 <-
ggplot(filter(mtcars, mpg < 20), aes(mpg)) +
geom_histogram(binwidth = 1, boundary = 1) +
scale_x_continuous(limits = c(10,35))
p1/p2
Created on 2019-08-07 by the reprex package (v0.3.0)
The desired output
That's photoshopped
adding coord_cartesian(xlim = c(10,(20 or 35)), clip = 'off'), and/or changing scale_x limits to c(0,(20 or 35)) doesn't work.
patchwork also won't let me set the widths of both plots when they are in two rows, which makes sense in a way. So I could create an empty plot for the second row and set the widths for those, but this seems a terrible hack and I feel there must be a much easier solution.
I am not restricted to patchwork, but any solution allowing to use it would be very welcome.
I modified the align_plots function from the cowplot package for this, so that its plot_grid function can now support adjustments to the dimensions of each plot.
(The main reason I went with cowplot rather than patchwork is that I haven't had much tinkering experience with the latter, and overloading common operators like + makes me slightly nervous.)
Demonstration of results
# x / y axis range of p1 / p2 have been changed for illustration purpose
p1 <- ggplot(mtcars, aes(mpg, 1 + stat(count))) +
geom_density(trim = TRUE) +
scale_x_continuous(limits = c(10,35)) +
coord_cartesian(ylim = c(1, 3.5))
p2 <- ggplot(filter(mtcars, mpg >= 15 & mpg < 30), aes(mpg)) +
geom_histogram(binwidth = 1, boundary = 1)
plot_grid(p1, p2, ncol = 1, align = "v") # plots in 1 column, x-axes aligned
plot_grid(p1, p2, nrow = 1, align = "h") # plots in 1 row, y-axes aligned
Plots in 1 column (x-axes aligned for 15-28 range):
Plots in 1 row (y-axes aligned for 1 - 3.5 range):
Caveats
This hack assumes the plots that the user intends to align (either horizontally or vertically) have reasonably similar axes of comparable magnitude. I haven't tested it on more extreme cases.
This hack expects simple non-faceted plots in Cartesian coordinates. I'm not sure what one could expect from aligning faceted plots. Similarly, I'm not considering polar coordinates (what's there to align?) or map projections (haven't looked into this, but they feel rather complicated).
This hack expects the gtable cell containing the plot panel to be in the 7th row / 5th column of the gtable object, which is based on my understanding of how ggplot objects are typically converted to gtables, and may not survive changes to the underlying code.
Code
Modified version of cowplot::align_plots:
align_plots_modified <- function (..., plotlist = NULL, align = c("none", "h", "v", "hv"),
axis = c("none", "l", "r", "t", "b", "lr", "tb", "tblr"),
greedy = TRUE) {
plots <- c(list(...), plotlist)
num_plots <- length(plots)
grobs <- lapply(plots, function(x) {
if (!is.null(x)) as_gtable(x)
else NULL
})
halign <- switch(align[1], h = TRUE, vh = TRUE, hv = TRUE, FALSE)
valign <- switch(align[1], v = TRUE, vh = TRUE, hv = TRUE, FALSE)
vcomplex_align <- hcomplex_align <- FALSE
if (valign) {
# modification: get x-axis value range associated with each plot, create union of
# value ranges across all plots, & calculate the proportional width of each plot
# (with white space on either side) required in order for the plots to align
plot.x.range <- lapply(plots, function(x) ggplot_build(x)$layout$panel_params[[1]]$x.range)
full.range <- range(plot.x.range)
plot.x.range <- lapply(plot.x.range,
function(x) c(diff(c(full.range[1], x[1]))/ diff(full.range),
diff(x)/ diff(full.range),
diff(c(x[2], full.range[2]))/ diff(full.range)))
num_widths <- unique(lapply(grobs, function(x) {
length(x$widths)
}))
num_widths[num_widths == 0] <- NULL
if (length(num_widths) > 1 || length(grep("l|r", axis[1])) > 0) {
vcomplex_align = TRUE
warning("Method not implemented for faceted plots. Placing unaligned.")
valign <- FALSE
}
else {
max_widths <- list(do.call(grid::unit.pmax,
lapply(grobs, function(x) {x$widths})))
}
}
if (halign) {
# modification: get y-axis value range associated with each plot, create union of
# value ranges across all plots, & calculate the proportional width of each plot
# (with white space on either side) required in order for the plots to align
plot.y.range <- lapply(plots, function(x) ggplot_build(x)$layout$panel_params[[1]]$y.range)
full.range <- range(plot.y.range)
plot.y.range <- lapply(plot.y.range,
function(x) c(diff(c(full.range[1], x[1]))/ diff(full.range),
diff(x)/ diff(full.range),
diff(c(x[2], full.range[2]))/ diff(full.range)))
num_heights <- unique(lapply(grobs, function(x) {
length(x$heights)
}))
num_heights[num_heights == 0] <- NULL
if (length(num_heights) > 1 || length(grep("t|b", axis[1])) > 0) {
hcomplex_align = TRUE
warning("Method not implemented for faceted plots. Placing unaligned.")
halign <- FALSE
}
else {
max_heights <- list(do.call(grid::unit.pmax,
lapply(grobs, function(x) {x$heights})))
}
}
for (i in 1:num_plots) {
if (!is.null(grobs[[i]])) {
if (valign) {
grobs[[i]]$widths <- max_widths[[1]]
# modification: change panel cell's width to a proportion of unit(1, "null"),
# then add whitespace to the left / right of the plot's existing gtable
grobs[[i]]$widths[[5]] <- unit(plot.x.range[[i]][2], "null")
grobs[[i]] <- gtable::gtable_add_cols(grobs[[i]],
widths = unit(plot.x.range[[i]][1], "null"),
pos = 0)
grobs[[i]] <- gtable::gtable_add_cols(grobs[[i]],
widths = unit(plot.x.range[[i]][3], "null"),
pos = -1)
}
if (halign) {
grobs[[i]]$heights <- max_heights[[1]]
# modification: change panel cell's height to a proportion of unit(1, "null"),
# then add whitespace to the bottom / top of the plot's existing gtable
grobs[[i]]$heights[[7]] <- unit(plot.y.range[[i]][2], "null")
grobs[[i]] <- gtable::gtable_add_rows(grobs[[i]],
heights = unit(plot.y.range[[i]][1], "null"),
pos = -1)
grobs[[i]] <- gtable::gtable_add_rows(grobs[[i]],
heights = unit(plot.y.range[[i]][3], "null"),
pos = 0)
}
}
}
grobs
}
Utilising the above modified function with cowplot package's plot_grid:
# To start using (in current R session only; effect will not carry over to subsequent session)
trace(cowplot::plot_grid, edit = TRUE)
# In the pop-up window, change `grobs <- align_plots(...)` (at around line 27) to
# `grobs <- align_plots_modified(...)`
# To stop using
untrace(cowplot::plot_grid)
(Alternatively, we can define a modified version of plot_grid function that uses align_plots_modified instead of cowplot::align_plots. Results would be the same either way.)
Here is an option with grid.arrange that does not use a blank plot, but requires a manual of adjustment of:
plot margin
x axis expansion
number of decimal places in y axis labels
library(ggplot2)
library(dplyr)
library(gridExtra)
p1 <-
ggplot(mtcars, aes(mpg)) +
geom_density(trim = TRUE) +
scale_x_continuous(limits = c(10,35), breaks=seq(10,35,5), expand = expand_scale(add=c(0,0)))
p2 <-
ggplot(filter(mtcars, mpg < 20), aes(mpg)) +
geom_histogram(binwidth = 1, boundary = 1) +
scale_x_continuous(limits = c(10,20), breaks=seq(10,20,5), expand = expand_scale(add=c(0,0))) +
scale_y_continuous(labels = scales::number_format(accuracy = 0.01)) +
theme(plot.margin = unit(c(0,1,0,0), "cm"))
grid.arrange(p1, p2,
layout_matrix = rbind(c(1, 1), c(2, NA))
)
Should make this plot:
I'm creating a list of ggplot heatmaps, which have the same number of rows but different number of columns and different lengths of their x-axis tick labels:
plot.list <- vector(mode="list",length(3))
n.cols <- c(600,30,300)
x.labs <- c("medium","this is a long label","sh")
library(ggplot2)
for(i in 1:3){
set.seed(1)
df <- reshape2::melt(matrix(rnorm(100*n.cols[i]),100,n.cols[i],dimnames = list(paste0("G",1:100),paste0("S",1:n.cols[i]))))
plot.list[[i]] <- ggplot(data=df,mapping=aes(x=Var2,y=Var1,fill=value))+
geom_tile()+theme_minimal()+scale_fill_gradient2(name="Scaled Value",low="darkblue",mid="gray",high="darkred")+
scale_x_discrete(name=NULL,breaks=unique(df$Var2)[floor(length(unique(df$Var2))/2)],labels=x.labs[i])+
scale_y_discrete(name=NULL)+
theme(legend.position=NULL,axis.title.x=element_blank(),axis.text.x=element_text(angle=90,hjust=1,vjust=0.5))
if(i != 1) plot.list[[i]] <- plot.list[[i]]+theme(axis.text.y=element_blank())
if(i != 3) plot.list[[i]] <- plot.list[[i]]+theme(legend.position = "none")
}
I then want to combine them together horizontally with a very small margin separating them, and have their widths be relative to the numbers of columns.
Trying to achieve this using gridExtra's arrangeGrob:
gridExtra::arrangeGrob(grobs=plot.list,ncol=length(plot.list),widths=n.cols,padding=0.01)
Or with cowplot's plot_grid:
cowplot::plot_grid(plotlist=plot.list,align="v",axis="tb",ncol=length(plot.list),rel_widths=n.cols)
Gives me:
So my questions are:
How to get them to have the same height and have the x-axis labels extend downwards to varying lengths?
Shrink the spaces between them? I tried reducing the padding value but see no change
Note that I know that using facet_grid might be the obvious way to create this in the first place, but I specifically need to first create the list of plots and only then combine them.
Both egg:ggarrange and cowplot::plot_grid() can accomplish this.
As far as answering 1, try out:
library(egg)
plot1 <- plot.list[[1]]
plot2 <- plot.list[[2]]
plot3 <- plot.list[[3]]
ggarrange(plot1, plot2, plot3, ncol = 3, widths = c(600,30,300)) #originally had the 20,3,10, but I don't think it scales right.
As far as 2, you can set you plot.margins beforehand and arrange like before.
plot1 <- plot.list[[1]] + theme(plot.margin = margin(1,0,1,1)) # order is top, right, bottom, left. Go negative if you want them to touch.
plot2 <- plot.list[[2]] + theme(plot.margin = margin(1,0,1,0))
plot3 <- plot.list[[3]] + theme(plot.margin = margin(1,1,1,0))
ggarrange(plot1, plot2, plot3, ncol = 3, widths = c(600,30,300))
plot_grid will give you the same image as below.
cowplot::plot_grid(plot1, plot2, plot3, ncol = 3, axis = "b", align = "h", rel_widths = c(600,30,300))
I'm trying to produce side by side tile plots using ggplot2 and gridExtra.
However, the plots produced are not scaled/aligned, see the picture and code below.
How can I produce this figure such that the cells are aligned and of the same dimensions?
Code
library(ggplot2)
library(gridExtra)
## make date frames
one <- floor(runif(56, min=0, max=5))
data.one<- cbind(one,expand.grid(h = seq(1,8,1), w = seq(1,7,1)))
two <- floor(runif(35, min=0, max=5))
data.two <- cbind(two,expand.grid(h = seq(1,7,1), w = seq(1,5,1)))
## gridExtra layout
lay <- rbind(c(1,1,1,1,1,1,1,NA,NA,NA,NA,NA),
c(1,1,1,1,1,1,1,2,2,2,2,2),
c(1,1,1,1,1,1,1,2,2,2,2,2),
c(1,1,1,1,1,1,1,2,2,2,2,2),
c(1,1,1,1,1,1,1,2,2,2,2,2),
c(1,1,1,1,1,1,1,2,2,2,2,2),
c(1,1,1,1,1,1,1,2,2,2,2,2),
c(1,1,1,1,1,1,1,2,2,2,2,2))
##plots
plot.one<-ggplot(data=data.one)+
geom_tile(aes(x=w,y=h,fill=one),colour = "grey50")+
scale_fill_gradient(low = "white", high = "blue")+
theme(legend.position= "none")
plot.two<-ggplot(data=data.two)+
geom_tile(aes(y=h,x=w,fill=two),colour = "grey50")+
scale_fill_gradient(low = "white", high = "red")+
theme(legend.position= "none")
grid.arrange(plot.one,plot.two, layout_matrix = lay)
ggplot2 doesn't assign fixed sizes to the plot panels, so you need to go to a rather low-level, find out the number of bins in each plot, and use this to set the appropriate panel size in the gtable object. The other complication is that "null" units are a bit special in grid, so to have something that scales with them it needs to be a null unit itself, as in this dummy rectGrob squeezing the second plot panel from the top,
b1 <- ggplot_build(p1)
b2 <- ggplot_build(p2)
n <- function(b) length(unique(b[["data"]][[1]][["y"]]))
library(egg)
library(grid)
gf1 <- gtable_frame(ggplot_gtable(b1))
gf2 <- gtable_frame(ggplot_gtable(b2))
gf2$grobs[[5]][["grobs"]][[1]] <- arrangeGrob(
rectGrob(gp=gpar(fill="grey95", col=NA)), gf2$grobs[[5]][["grobs"]][[1]],
heights = unit.c(unit(1 - n(b2) / n(b1), "null"), unit(n(b2) / n(b1),"null")))
grid.arrange(gf1, gf2, ncol=2)
tl;dr can't get a standalone legend (describing common colours across the whole plot) in ggpairs to my satisfaction.
Sorry for length.
I'm trying to draw a (lower-triangular) pairs plot using GGally::ggpairs (an extension package for drawing various kinds of plot matrices with ggplot2). This is essentially the same question as How to add an external legend to ggpairs()? , but I'm not satisfied with the answer to that question aesthetically, so I'm posting this as an extension (if suggested/recommended by commenters, I will delete this question and offer a bounty on that question instead). In particular, I would like the legend to appear outside the sub-plot frame, either putting it within one virtual subplot but allowing additional width to hold it, or (ideally) putting it in a separate (empty) subplot. As I show below, both of my partial solutions have problems.
Fake data:
set.seed(101)
dd <- data.frame(x=rnorm(100),
y=rnorm(100),
z=rnorm(100),
f=sample(c("a","b"),size=100,replace=TRUE))
library(GGally)
Base plot function:
ggfun <- function(...) {
ggpairs(dd,mapping = ggplot2::aes(color = f),
columns=1:3,
lower=list(continuous="points"),
diag=list(continuous="blankDiag"),
upper=list(continuous="blank"),
...)
}
Function to trim top/right column:
trim_gg <- function(gg) {
n <- gg$nrow
gg$nrow <- gg$ncol <- n-1
v <- 1:n^2
gg$plots <- gg$plots[v>n & v%%n!=0]
gg$xAxisLabels <- gg$xAxisLabels[-n]
gg$yAxisLabels <- gg$yAxisLabels[-1]
return(gg)
}
gg0 <- trim_gg(ggfun(legends=TRUE))
Get rid of legends in left column (as in the linked question above):
library(ggplot2) ## for theme()
for (i in 1:2) {
inner <- getPlot(gg0,i,1)
inner <- inner + theme(legend.position="none")
gg0 <- putPlot(gg0,inner,i,1)
}
inner <- getPlot(gg0,2,2)
inner <- inner + theme(legend.position="right")
gg0 <- putPlot(gg0,inner,2,2)
Problems:
the blank panel behind the legend is actually masking some points; I don't know why it's not outside the panel as usual, I assume that's something that ggpairs is doing
if it were outside the panel (on top or to the right), I would want to make sure to leave some extra space so the panels themselves were all the same size. However, ggmatrix/ggpairs looks very inflexible about this.
The only alternative I've been able to try to far is following ggplot separate legend and plot by extracting the legend and using gridExtra::grid.arrange():
g_legend <- function(a.gplot){
tmp <- ggplot_gtable(ggplot_build(a.gplot))
leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
legend <- tmp$grobs[[leg]]
return(legend)
}
library(gridExtra)
grid.arrange(getPlot(gg0,1,1),
g_legend(getPlot(gg0,2,2)),
getPlot(gg0,2,1),
getPlot(gg0,2,2)+theme(legend.position="none"),
nrow=2)
Problems:
the axes and labels suppressed by ggpairs are back ...
I also considered creating a panel with a special plot that contained only the legend (i.e. trying to use theme(SOMETHING=element.blank) to suppress the plot itself, but couldn't figure out how to do it.
As a last resort, I could trim the axes where appropriate myself, but this is practically reinventing what ggpairs is doing in the first place ...
With some slight modification to solution 1: First, draw the matrix of plots without their legends (but still with the colour mapping). Second, use your trim_gg function to remove the diagonal spaces. Third, for the plot in the top left position, draw its legend but position it into the empty space to the right.
data(state)
dd <- data.frame(state.x77,
State = state.name,
Abbrev = state.abb,
Region = state.region,
Division = state.division)
columns <- c(3, 5, 6, 7)
colour <- "Region"
library(GGally)
library(ggplot2) ## for theme()
# Base plot
ggfun <- function(data = NULL, columns = NULL, colour = NULL, legends = FALSE) {
ggpairs(data,
columns = columns,
mapping = ggplot2::aes_string(colour = colour),
lower = list(continuous = "points"),
diag = list(continuous = "blankDiag"),
upper = list(continuous = "blank"),
legends = legends)
}
# Remove the diagonal elements
trim_gg <- function(gg) {
n <- gg$nrow
gg$nrow <- gg$ncol <- n-1
v <- 1:n^2
gg$plots <- gg$plots[v > n & v%%n != 0]
gg$xAxisLabels <- gg$xAxisLabels[-n]
gg$yAxisLabels <- gg$yAxisLabels[-1]
return(gg)
}
# Get the plot
gg0 <- trim_gg(ggfun(dd, columns, colour))
# For plot in position (1,1), draw its legend in the empty panels to the right
inner <- getPlot(gg0, 1, 1)
inner <- inner +
theme(legend.position = c(1.01, 0.5),
legend.direction = "horizontal",
legend.justification = "left") +
guides(colour = guide_legend(title.position = "top"))
gg0 <- putPlot(gg0, inner, 1, 1)
gg0
I'm creating ggplots in a loop and then using grid.arrange to plot each of my figures on one page in a lattice-type graph. The problem I have is that I have a border around each figure and they merge together when I plot them. Does anyone know how to add white space between the figures. I've looked for information about figure padding and also toyed around with trying to add blank geom_rect between my plots, but so far no luck. Some simplified code is provided below. Thanks for any help you can offer.
p = vector("list", 3) #List for arranging grid
for(ii in 1:3){
p[[ii]] = ggplot(mtcars, aes(x = wt, y = mpg))+
geom_point()+
theme(plot.background = element_rect(colour = 'black', size = 2))
}
do.call("grid.arrange", c(p, ncol=1))
I tried quite a few different efforts to get the viewports to be smaller within a 3 x 1 layout and finally realized that just adding some blank space with narrow heights in the 5 x 1 layout was pretty easy:
Layout <- grid.layout(nrow = 5, ncol = 1,
heights=c(1, .1, 1, .1, 1) )
# could have written code to alternate heights or widths with gaps
grid.show.layout(Layout)
vplayout <- function(...) { # sets up new page with Layout
grid.newpage()
pushViewport(viewport(layout = Layout))
}
subplot <- function(x, y) viewport(layout.pos.row = x,
layout.pos.col = y)
mmplot <- function(p=p) { # could make more general
vplayout()
print(p[[1]], vp = subplot(1, 1 ))
print(p[[2]], vp = subplot(3, 1))
print(p[[3]], vp = subplot(5, 1 ))
}
mmplot(a, z)
alternatively, this experimental version of gtable offers a similar interface to grid.arrange,
library(ggplot2)
library(gtable)
lp <- replicate(3, qplot(rnorm(10), rnorm(10)) +
theme(plot.background=element_rect(size = 3, colour="black")),
simplify = FALSE)
lg <- lapply(lp, ggplotGrob)
g <- do.call(gtable_arrange, c(lg, ncol=1, draw=FALSE))
g <- gtable_add_rows(g, heights = unit(1, "line"), pos = 1)
g <- gtable_add_rows(g, heights = unit(1, "line"), pos = 3)
grid.newpage()
grid.draw(g)