Defining grid.arrange() so the third plot is in the middle? - r

I'm making three plots with ggplot2. I want to put them onto the same space. To put them into the same space I am using grid.arrange(), with 2 columns and 2 rows. Instead of having the third figure in position (2,1) be on the left, is there a way for me to center it in the middle of the space? Open to suggestions beyond grid.arrange() as well.
library(ggplot2)
library(gridExtra)
P1 <- ggplot(mtcars, aes(x = mpg)) +
geom_histogram()
P2 <- ggplot(mtcars, aes(x = wt)) +
geom_histogram()
P3 <- ggplot(mtcars, aes(x = qsec)) +
geom_histogram()
grid.arrange(P1, P2, P3, ncol = 2, nrow = 2)
Thanks so much for your help!

No idea about gridExtra, but since you said alternatives are OK, it's really straightforward with patchwork :)
library(ggplot2)
library(patchwork)
P1 <- ggplot(mtcars, aes(x = mpg)) +
geom_histogram()
P2 <- ggplot(mtcars, aes(x = wt)) +
geom_histogram()
P3 <- ggplot(mtcars, aes(x = qsec)) +
geom_histogram()
(P1 + P2) / P3

Here is the answer for anyone interested in using grid.arrange()
library(ggplot2)
library(gridExtra)
P1 <- ggplot(mtcars, aes(x = mpg)) +
geom_histogram()
P2 <- ggplot(mtcars, aes(x = wt)) +
geom_histogram()
P3 <- ggplot(mtcars, aes(x = qsec)) +
geom_histogram()
grid.arrange(P1, P2, P3, ncol = 2, nrow = 2)
#This will get you 2 plots on top and 1 plot in the middle at the bottom
grid.arrange(P1, P2, P3, ncol = 2, nrow = 2, layout_matrix= rbind(c(1,2), 3))
#This will get you 1 plot in the middle at top and 2 plots at the bottom
grid.arrange(P1, P2, P3, ncol = 2, nrow = 2, layout_matrix= rbind(c(1,1),c(2,3)))

Related

R adding word in the middle of grid arrange

I am writing R ggplot, and I am arranging multiple plots with grid.arrange.
Is there a way to add some words in in between two plots?
I want the output to be like the red word.
Thank you for your help :)
library(ggplot2)
library(gridExtra)
P1 <- ggplot(mtcars, aes(x = mpg)) +
geom_histogram()
P2 <- ggplot(mtcars, aes(x = wt)) +
geom_histogram()
grid.arrange(P1, *I want to add some information here*,P2, ncol = 1, nrow = 2)
You could use the grid.text function from grid library as follows
### Libraries
library(grid)
library(ggplot2)
library(gridExtra)
### Data
data(cars)
### Initiating plots
P1 <- ggplot(mtcars, aes(x = mpg)) +
geom_histogram()
P2 <- ggplot(mtcars, aes(x = wt)) +
geom_histogram()
### Display plots
grid.arrange(P1, P2, ncol = 1, nrow = 2)+
grid.text("I want to add some information here",
x=unit(0.25, "npc"),
y=unit(.52, "npc"),
gp=gpar(fontsize=20, col="red"))
One approach would be to create another ggplot with only text that you want and use it in cowplot::plot_grid
library(ggplot2)
P1 <- ggplot(mtcars, aes(x = mpg)) + geom_histogram()
P2 <- ggplot() +
annotate("text", x = 4, y = 25, size=8,
label = "This is some text in the middle", color = "red") +
theme_void()
P3 <- ggplot(mtcars, aes(x = wt)) + geom_histogram()
cowplot::plot_grid(P1, P2, P3, rel_heights = c(1/2, 1/12, 1/2),
align = "v", nrow = 3)

Using cowplot in R to make a ggplot chart occupy two consecutive rows

This is my code:
library(ggplot2)
library(cowplot)
df <- data.frame(
x = 1:10, y1 = 1:10, y2 = (1:10)^2, y3 = (1:10)^3, y4 = (1:10)^4
)
p1 <- ggplot(df, aes(x, y1)) + geom_point()
p2 <- ggplot(df, aes(x, y2)) + geom_point()
p3 <- ggplot(df, aes(x, y3)) + geom_point()
p4 <- ggplot(df, aes(x, y4)) + geom_point()
p5 <- ggplot(df, aes(x, y3)) + geom_point()
# simple grid
plot_grid(p1, p2,
p3, p4,
p5, p4)
But I don't want to repeat p4 I want to "stretch" p4 to occupy col2 and rows 2 and 3.
Any help?
You may find this easier using gridExtra::grid.arrange().
library(gridExtra)
grid.arrange(p1, p2, p3, p4, p5,
ncol = 2,
layout_matrix = cbind(c(1,3,5), c(2,4,4)))
Result:
This is fairly straight forward with the patchwork package.
Also, never forget about the facet option - for this you'll need the ggh4x package.
Last, also the desired cowplot solution, which requires a convoluted nesting of several plot_grid objects. Not my favourite.
## Option 1 - patchwork
library(ggplot2)
library(patchwork)
df <- data.frame(
x = 1:10, y1 = 1:10, y2 = (1:10)^2, y3 = (1:10)^3, y4 = (1:10)^4
)
## patchwork allows working with lists, which I find neat.
make_p <- function(y){
ggplot(df, aes(x, !!sym(y))) + geom_point()
}
## custom layout grid
layout <- "
AB
CD
ED
"
ls_p <- lapply(paste0("y", c(1:4,3)), make_p)
wrap_plots(ls_p) + plot_layout(design = layout)
Another option, in your particular example, is to make use of ggh4x::facet_manual.
## Option 2 - faceting with ggh4x
library(tidyverse)
library(ggh4x)
df <- data.frame(
x = 1:10, y1 = 1:10, y2 = (1:10)^2, y3 = (1:10)^3, y4 = (1:10)^4,
## adding y5 for simplicity
y5 = (1:10)^3
)
design <- "
AB
CD
ED
"
## or you can pass a matrix as design argument
# design <- matrix(c(1,2,3,4,5,4), 3, 2, byrow = TRUE)
df %>%
pivot_longer(matches("^y")) %>%
ggplot(aes(x, value)) +
geom_point() +
facet_manual(~ name, design)
Last, the cowplot option.
## option 3 nesting plot_grids with cowplot
library(cowplot)
p1 <- ggplot(df, aes(x, y1)) + geom_point()
p2 <- ggplot(df, aes(x, y2)) + geom_point()
p3 <- ggplot(df, aes(x, y3)) + geom_point()
p4 <- ggplot(df, aes(x, y4)) + geom_point()
p5 <- ggplot(df, aes(x, y3)) + geom_point()
top_row <- plot_grid(p1, p2)
left_col <- plot_grid(p3, p5, ncol = 1)
bottom_panel <- plot_grid(left_col, p4, ncol = 2)
plot_grid(top_row, bottom_panel, ncol = 1)

Controlling widths of many patchworked ggplots

I'm trying to make a graph with several ggplot2 graphs combined via patchwork.
I want first a shared y-axis for plot 1 and 3. Then plot 1 and 3 and at the end plot 2 and 4. This I have achieved with the help from #Allan Cameron - see the plot. Unfortunately I cannot control the width of plot 1,3,2 and 4. I would like plot 1 and 3 to be wider than plot 2 and 4. Also, for some reason the legend ends up in the middle of the plots. How can I put it all the way to the right?
Any ideas? All help is much appreaciated!
Here's the code:
mtcars
library(ggplot2)
library(patchwork)
p1 <- ggplot(mtcars) +
geom_point(aes(disp, wt, colour = mpg)) +
ggtitle('Plot 1')
p2 <- ggplot(mtcars) +
geom_point(aes(carb, wt)) +
ggtitle('Plot 2')
p3 <- ggplot(mtcars) +
geom_point(aes(hp, wt, colour = mpg)) +
ggtitle('Plot 3')
p4 <- ggplot(mtcars) +
geom_area(aes(gear, carb)) +
ggtitle('Plot 4')
# Patchwork graph with shared y-axis
y_axis <- ggplot(data.frame(l = p1$labels$y, x = 1, y = 1)) +
geom_text(aes(x, y, label = l), angle = 90) +
theme_void() +
coord_cartesian(clip = "off")
p1$labels$y <- p2$labels$y <- " "
y_axis + (p1 + p2) / (p3 + p4) + plot_layout(widths = c(1, 15, 5), guides = "collect")
With regards to the widths issue, the nesting you do -for example (p1 + p1)- causes the nested objects to respond differently. Instead you can use the design argument in plot_layout() to achieve the same, but responsive to the widths.
library(ggplot2)
library(patchwork)
p1 <- ggplot(mtcars) +
geom_point(aes(disp, wt, colour = mpg)) +
ggtitle('Plot 1')
p2 <- ggplot(mtcars) +
geom_point(aes(carb, wt)) +
ggtitle('Plot 2')
p3 <- ggplot(mtcars) +
geom_point(aes(hp, wt, colour = mpg)) +
ggtitle('Plot 3')
p4 <- ggplot(mtcars) +
geom_area(aes(gear, carb)) +
ggtitle('Plot 4')
# Patchwork graph with shared y-axis
y_axis <- ggplot(data.frame(l = p1$labels$y, x = 1, y = 1)) +
geom_text(aes(x, y, label = l), angle = 90) +
theme_void() +
coord_cartesian(clip = "off")
p1$labels$y <- p2$labels$y <- " "
y_axis + p1 + p2 + p3 + p4 +
plot_layout(widths = c(1, 15, 5),
guides = "collect",
design = "
123
145
")
Created on 2020-12-16 by the reprex package (v0.3.0)
Small note, you're deleting the y-axis lable of p2, whereas I think you meant to delete it from p3.
The patchwork can control the width of each part by iteral call the "plot_layout" in the sub-plot, just like :
patchwork <- (p1+p2)/(p3) + plot_layout(guides = "collect") while you want to make p1 wider than p2, you could try :
patchwork <- (p1+p2 + plot_layout(widths = c(2, 1), guides = "collect"))/(p3) + plot_layout(guides = "collect")

Adjust margins of grob object in r

I made a grob object using the cowplot package. I'm adding grid.lines() and grid.text() objects to finished grob but as it comes out of cowplot it fills the whole page. How can I adjust the margins of the grob object to add some white space around the edges? Example code below.
library(ggplot2)
library(cowplot)
p1 <- ggplot(mtcars, aes(disp, mpg)) +
geom_point()
p2 <- ggplot(mtcars, aes(qsec, mpg)) +
geom_point()
p3 <- ggplot(mtcars, aes(disp, mpg)) +
geom_point()
p4 <- ggplot(mtcars, aes(qsec, mpg)) +
geom_point()
plot_grid(p1, p2, p3, p4, ncol = 2 ,nrow = 2,align="hv")
You just use theme(plot.margin = ...) as you would in a ggplot:
library(ggplot2)
library(cowplot)
p1 <- ggplot(mtcars, aes(disp, mpg)) +
geom_point()
p2 <- ggplot(mtcars, aes(qsec, mpg)) +
geom_point()
p3 <- ggplot(mtcars, aes(disp, mpg)) +
geom_point()
p4 <- ggplot(mtcars, aes(qsec, mpg)) +
geom_point()
plot_grid(p1, p2, p3, p4, ncol = 2 ,nrow = 2,align="hv")
plot_grid(p1, p2, p3, p4, ncol = 2 ,nrow = 2,align="hv") +
theme(plot.margin = unit(c(20,20,20,20), "points"))
Created on 2020-04-29 by the reprex package (v0.3.0)

How can I align multiple plots by their titles instead of plot area?

I'm using egg to align multiple plots on a page. I'm wondering if it's possible to align two columns by the titles a) and c) instead of plot area? Thanks!
Code:
library(egg)
library(grid)
p1 <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
geom_point() + ggtitle("a)")
p1
p2 <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
geom_point() + facet_wrap(~ cyl, ncol = 2, scales = "free") +
guides(colour = "none") +
theme() + ggtitle("b)")
p2
p3 <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
geom_point() + facet_grid(. ~ am, scales = "free") + guides(colour="none") +
ggtitle("c)")
p3
g1 <- ggplotGrob(p1)
g2 <- ggplotGrob(p2)
g3 <- ggplotGrob(p3)
fg1 <- gtable_frame(g1, debug = TRUE)
fg2 <- gtable_frame(g2, debug = TRUE)
fg12 <- gtable_frame(gtable_rbind(fg1, fg2),
width = unit(2, "null"),
height = unit(1, "null"))
fg3 <-
gtable_frame(
g3,
width = unit(2, "null"),
height = unit(1, "null"),
debug = TRUE
)
grid.newpage()
combined <- gtable_cbind(fg12, fg3)
grid.draw(combined)
Plot:
I found another way by using cowplot package
left_col <- cowplot::plot_grid(p1 + ggtitle(""), p2 + ggtitle(""),
labels = c('a)', 'b)'), label_size = 14,
ncol = 1, align = 'v', axis = 'lr')
cowplot::plot_grid(left_col, p3 + ggtitle(""),
labels = c('', 'c)'), label_size = 14,
align = 'h', axis = 'b')
See also here
Edit:
A recently developed package patchwork for ggplot2 can also get the job done
library(patchwork)
{
p1 + {p2} + patchwork::plot_layout(ncol = 1)
} / p3 + patchwork::plot_layout(ncol = 2)
Adding a blank dummy faceting variable to plot p1/ a) seems like the easiest solution
p1 <- ggplot(data.frame(mtcars, dummy=''),
aes(mpg, wt, colour = factor(cyl))) +
geom_point() + ggtitle("a)") +
facet_wrap(~dummy)

Resources