Adjust margins of grob object in r - 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)

Related

Add a common xlab to patchwork plots in r

I'm following up on this great answer. In short, assuming we only have access to the plots object and can't manipulate the individual p objects, how can we add a common xlab="mpg" to the plots object?
Note: It would be great to add the xlab to this great answer.
library(ggplot2)
library(patchwork)
p1 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
p2 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
p3 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
p4 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
(plots = wrap_plots(p1,p2,p3,p4))
An option could be by using plot_annotation and create a title and adjust the position of this title to your x lab position like this:
library(ggplot2)
library(patchwork)
p1 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
p2 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
p3 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
p4 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
(plots = wrap_plots(p1,p2,p3,p4)) +
plot_annotation(title = "xlab") &
theme(plot.title = element_text(vjust = -110, hjust = 0.50))
Created on 2023-01-21 with reprex v2.0.2
This could also be done using the caption or subtitle instead.
Edit:
You could combine the x and y label like this:
library(ggplot2)
library(patchwork)
p1 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
p2 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
p3 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
p4 <- ggplot(mtcars, aes(mpg,vs))+ geom_point()+xlab("")+ylab("")
(plots = wrap_plots(p1,p2,p3,p4)) +
plot_annotation(title = "xlab",
subtitle = "ylab") &
theme(plot.title = element_text(vjust = -110, hjust = 0.50),
plot.subtitle = element_text(vjust = -55, hjust = -0.01, size = 12))
Created on 2023-01-21 with reprex v2.0.2

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)

Patchwork doesn't recognize plots with ggMargnial distribution elements

Trying to display 2 plots with ggMarginal but the plots are not recognized as such.
I'm pasting a simplified version of the code below where:
Before adding the ggMarginal element Patchwork displays ggplots side by side as expected
After adding marginal distributions with ggMarginal, Patchwork doesn't seem to recognize the the plot any more. The error message that I get is the following:
p1m + p2m
#> Error in p1m + p2m: non-numeric argument to binary operator
Here's the code I'm running:
library(ggplot2)
library(ggExtra)
library(patchwork)
p1 <- ggplot(mtcars) +
geom_point(aes(mpg, disp)) +
ggtitle('Plot 1')
p1m <- ggMarginal(p1,
type = "density",
size = 3)
p2 <- ggplot(mtcars) +
geom_point(aes(hp, wt, colour = mpg)) +
ggtitle('Plot 3')
p2m <- ggMarginal(p2,
type = "density",
size = 3)
p1+p2
p1m + p2m
#> Error in p1m + p2m: non-numeric argument to binary operator
Thanks a lot for your help!
Created on 2021-10-09 by the reprex package (v2.0.1)
You can wrap your marginal plots in patchwork::wrap_elements()
patchwork::wrap_elements(p1m) + patchwork::wrap_elements(p2m)
Not sure whether there is an easy option to make patchwork work with objects of class ggMarginal.
Another option to add side plots would be to make use of the ggside package which works fine with patchwork. One drawback of ggside is that (to the best of my knowledge) as of the moment it does not offer any options to style the side plots, i.e. it will inherit the style of the main plot's theme:
library(ggplot2)
library(ggside)
#> Registered S3 method overwritten by 'ggside':
#> method from
#> +.gg ggplot2
library(patchwork)
p1 <- ggplot(mtcars, aes(mpg, disp)) +
geom_point() +
geom_xsidedensity(aes(y = after_stat(density)), position = "stack") +
geom_ysidedensity(aes(x = after_stat(density)), position = "stack") +
ggtitle('Plot 1') +
theme(ggside.panel.scale = .5)
p2 <- ggplot(mtcars, aes(hp, wt, colour = mpg)) +
geom_point() +
geom_xsidedensity(aes(y = after_stat(density)), position = "stack") +
geom_ysidedensity(aes(x = after_stat(density)), position = "stack") +
ggtitle('Plot 3') +
theme(ggside.panel.scale = .5,)
p1 + p2
A second but cumbersome option would be to make the marginal plots via ggplot2 too and glue all together using patchwork:
p1 <- ggplot(mtcars) +
geom_point(aes(mpg, disp)) +
ggtitle('Plot 1')
p2 <- ggplot(mtcars) +
geom_point(aes(mpg, disp, colour = mpg)) +
ggtitle('Plot 3')
p1ma <- ggplot(mtcars) +
geom_density(aes(mpg)) +
theme_void()
p1mb <- ggplot(mtcars) +
geom_density(aes(y = disp)) +
theme_void()
wrap_plots(list(p1ma, plot_spacer(), p1ma, plot_spacer(), p1, p1mb, p2, p1mb),
widths = c(2, 1, 2, 1), heights = c(1, 2),
ncol = 4, nrow = 2, byrow = TRUE) &
theme(legend.position = "bottom")

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

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

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

Resources