R adding word in the middle of grid arrange - r

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)

Related

Customize position of common legend in R

I need to arrange multiple plots with common legend in a single page and used following code:
library(ggpubr)
ggarrange(fig1, fig2, fig3, nrow=2, ncol=2, common.legend = TRUE, legend="right")
Now, I'm wondering if there are other packages/ways where I can customize position of the common legend since the 'ggarrange' has only 'top', 'bottom', 'right', 'left' and 'none' options for this. Since second row and second column is empty, I want the legend be appeared there.
Perhaps the cowplot package will work?
Minimal Reproducible Example:
library(tidyverse)
library(ggpubr)
fig1 <- ggplot(mtcars, aes(x = hp, y = mpg)) +
geom_point()
fig2 <- ggplot(mtcars, aes(x = cyl, y = mpg, group = cyl, fill = factor(cyl))) +
geom_boxplot() +
scale_fill_viridis_d()
fig3 <- ggplot(mtcars, aes(x = disp, y = mpg)) +
geom_point()
ggarrange(fig1, fig2, fig3, nrow=2, ncol=2, common.legend = TRUE, legend="right")
Using the cowplot package:
library(cowplot)
legend <- get_legend(fig2)
fig2_no_legend <- ggplot(mtcars, aes(x = cyl, y = mpg, group = cyl, fill = factor(cyl))) +
geom_boxplot() +
scale_fill_viridis_d() +
theme(legend.position = "none")
cowplot::plot_grid(fig1, fig2_no_legend, fig3, legend, nrow = 2, ncol = 2)

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

Draw a "grid" between arranged plots

I'm working with 4 different plots and I'm using ggarrange() from the ggpubr-package to put them in a single plot. I've prepared an example:
library(ggpubr)
library(ggplot2)
p1 <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) + geom_point() + ggtitle("Plot 1")
p2 <- ggplot(iris, aes(x = Petal.Length, y = Petal.Width)) + geom_point() + ggtitle("Plot 2")
p3 <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Width)) + geom_point() + ggtitle("Plot 3")
p4 <- ggplot(iris, aes(x = Petal.Length, y = Sepal.Width)) + geom_point() + ggtitle("Plot 4") +
facet_wrap(~Species)
plot.list <- list(p1, p2, p3, p4)
ggarrange(plotlist = plot.list)
Output:
I would like to draw a border around the single plots, like so:
Is there any way to draw this border? Thanks!
grid.polygon() is quite manual but I think it can do the trick:
Using RStudio
library("ggpubr")
library(ggplot2)
library(gridExtra)
library(grid)
p1 <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) + geom_point() + ggtitle("Plot 1")
p2 <- ggplot(iris, aes(x = Petal.Length, y = Petal.Width)) + geom_point() + ggtitle("Plot 2")
p3 <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Width)) + geom_point() + ggtitle("Plot 3")
p4 <- ggplot(iris, aes(x = Petal.Length, y = Sepal.Width)) + geom_point() + ggtitle("Plot 4") +
facet_wrap(~Species)
plot.list <- list(p1, p2, p3, p4)
ggarrange(plotlist = plot.list)
x = c(0, 0.5, 1, 0.5, 0.5, 0.5)
y = c(0.5, 0.5, 0.5,0, 0.5, 1)
id = c(1,1,1,2,2,2)
grid.polygon(x,y,id)
Using Shiny (Edit)
When doing it within a shiny-app, ones needs to add the grid using annotation_custom(), as follows:
ggarrange(plotlist = plot.list) +
annotation_custom(
grid.polygon(c(0, 0.5, 1, 0.5, 0.5, 0.5),
c(0.5, 0.5, 0.5,0, 0.5, 1),
id = c(1,1,1,2,2,2),
gp = gpar(lwd = 1.5)))
Not sure if this will work for you, but you can just put borders around your individual plots. However, this includes borders on the outside of the layout. Your description seems like you're not opposed to that, but there are only inner gridlines in your example plot.
You could add the theme call when you create the plots; rather than editing the plot creation, I just did it to each plot in the list before sticking them all together.
library(ggpubr)
library(ggplot2)
#### same plot creation here ######
plot.list <- lapply(list(p1, p2, p3, p4),
function(p) p + theme(plot.background = element_rect(color = "black")))
ggarrange(plotlist = plot.list)

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)

Top to bottom alignment of two ggplot2 figures

I realize that the align.plots function from the ggExtra package has been deprecated and removed. However, I am using my own version as it seems to provide the specific functionality I need. I have looked into faceting to solve my problem but I don't think it will work for my particular issue. What seems to be the problem is that the top-to-bottom images don't align when I use coord_equal on one of them. This doesn't seem to affect left-to-right though. Here is a simplified (or at least as simple as I can make it) version of what I am trying to achieve.
Create some dummy data frames:
source('https://raw.github.com/jbryer/multilevelPSA/master/r/align.R')
require(psych)
df = data.frame(x=rnorm(100, mean=50, sd=10),
y=rnorm(100, mean=48, sd=10),
group=rep(letters[1:10], 10))
dfx = describe.by(df$x, df$group, mat=TRUE)[,c('group1', 'mean', 'n', 'min', 'max')]
names(dfx) = c('group', 'x', 'x.n', 'x.min', 'x.max')
dfy = describe.by(df$y, df$group, mat=TRUE)[,c('group1', 'mean', 'n', 'min', 'max')]
names(dfy) = c('group', 'y', 'y.n', 'y.min', 'y.max')
df2 = cbind(dfx, dfy[,2:ncol(dfy)])
range = c(0,100)
This will setup the three plots:
p1a = ggplot(df2, aes(x=x, y=y, colour=group)) + geom_point() +
opts(legend.position='none') +
scale_x_continuous(limits=range) + scale_y_continuous(limits=range)
p1 = p1a + coord_equal(ratio=1)
p2 = ggplot(df, aes(x=x, y=group, colour=group)) + geom_point() +
scale_x_continuous(limits=range) + opts(legend.position='none')
p3 = ggplot(df, aes(x=group, y=y, colour=group)) + geom_point() +
scale_y_continuous(limits=range) + opts(legend.position='none')
The alignment top to bottom does not work with coord_equal
grid_layout <- grid.layout(nrow=2, ncol=2, widths=c(1,2), heights=c(2,1))
grid.newpage()
pushViewport( viewport( layout=grid_layout, width=1, height=1 ) )
align.plots(grid_layout, list(p1, 1, 2), list(p3, 1, 1), list(p2, 2, 2))
Broken Plot http://bryer.org/alignplots1.png
The fix is to add respect=TRUE to the grid.layout call:
grid_layout <- grid.layout(nrow=2, ncol=2, widths=c(1,2), heights=c(2,1), respect=TRUE)
But if I don't use coord_equal the alignment works fine:
grid_layout <- grid.layout(nrow=2, ncol=2, widths=c(1,2), heights=c(2,1))
grid.newpage()
pushViewport( viewport( layout=grid_layout, width=1, height=1 ) )
align.plots(grid_layout, list(p1a, 1, 2), list(p3, 1, 1), list(p2, 2, 2))
Working Plot http://bryer.org/alignplots2.png
ggplot2 now has ggplotGrob(), which may help with this.
First, we need to update the code used to generate the plots:
p1a = ggplot(df2, aes(x=x, y=y, colour=group)) + geom_point() +
scale_x_continuous(limits=range) + scale_y_continuous(limits=range)
p1 = p1a + coord_equal(ratio=1) + theme_minimal() + theme(legend.position='none')
p2 = ggplot(df, aes(x=x, y=group, colour=group)) + geom_point() +
scale_x_continuous(limits=range) + theme_minimal() + theme(legend.position='none')
p3 = ggplot(df, aes(x=group, y=y, colour=group)) + geom_point() +
scale_y_continuous(limits=range) + theme_minimal() + theme(legend.position='none')
p4 <- ggplot(df, aes(x = group, y = y)) +
geom_blank() +
theme(line = element_blank(),
rect = element_blank(),
text = element_blank(),
title = element_blank())
p4 will be blank; we just need the grob to draw.
Then we load the grid package and draw the grobs in a list arranged in rows and columns using cbind() and rbind().
library(grid)
grid.newpage()
grid.draw(
cbind(
rbind(ggplotGrob(p3), ggplotGrob(p4), size = "first"),
rbind(ggplotGrob(p1), ggplotGrob(p2), size = "first"),
size = "first"))
I'm not sure if this method will let you plot p3 in a different width and p2 in a different height, as you have them in the original example; I normally need a grid of similarly-sized graphs, and haven't needed to figure out different sizes.
This answer is partially based on partially based on https://stackoverflow.com/a/17463184/393354
Here is an example:
m <- matrix(c(3, 1, 0, 2), 2, byrow = T)
lay <- gglayout(m, widths = c(1, 3), heights = c(3, 1))
ggtable(p1, p2, p3, layout = lay)
you can use this by
install.packages('devtools')
library(devtools)
dev_mode()
install_github("ggplot2", "kohske", "cutting-edge")
library(ggplot2)
note that this branch is experimental, so maybe there are bugs.
To solve the problem using the align.plots method, specify respect=TRUE on the layout call:
grid_layout <- grid.layout(nrow=2, ncol=2, widths=c(1,2), heights=c(2,1), respect=TRUE)

Resources