add row and column titles with ggarrange - ggplot2

I have a list of ggplots that may be too complex to arrange using facet_wrap. All plots must share the same legend and should be arranged in a grid. Each column of the grid needs a different title, also each row of the grid needs a differen title.
An absurdly simple example:
library(ggplot2)
library(ggpubr)
plot1<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot2<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot3<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot4<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plotlist<- list(plot1, plot2, plot3, plot4)
ggarrange(plotlist = plotlist, ncol = 2, nrow = 2, common.legend = TRUE, legend="bottom")
This produces everything needed except the column and row titles, and annotate_figure only adds a global title to the figure. The desired output should look like:

I prefer the patchwork package. Controlling layout is easy. The titles are a bit tricky. Patchwork uses the labs from each plot - so you could add plot titles to the upper plots and maybe add a row to the y label in the left hand side plots.
Arguably easier is to create the titles as plot and add them to your patchwork. You can easily customise your layout like explained in the patchwork vignette
library(ggplot2)
library(patchwork)
plot1<-plot2<-plot3<-plot4<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
row1 <- ggplot() + annotate(geom = 'text', x=1, y=1, label="row 1 title", angle = 90) + theme_void()
row2 <- ggplot() + annotate(geom = 'text', x=1, y=1, label="row 2 title", angle = 90) + theme_void()
col1 <- ggplot() + annotate(geom = 'text', x=1, y=1, label="col 1 title") + theme_void()
col2 <- ggplot() + annotate(geom = 'text', x=1, y=1, label="col 2 title") + theme_void()
layoutplot <- "
#cccddd
aeeefff
aeeefff
bggghhh
bggghhh
"
plotlist <- list(a = row1, b = row2, c = col1, d = col2, e= plot1, f=plot2, g=plot3, h=plot4)
wrap_plots(plotlist, guides = 'collect', design = layoutplot)
Created on 2020-02-22 by the reprex package (v0.3.0)

I know it's late to reply, but for future searchers (including future me): The ggpubr::annotate_figure function is likely best here to reduce cross-package issues.
Reproducing:
library(ggplot2)
library(ggpubr)
plot1<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot2<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot3<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plot4<- ggplot() + geom_point(aes(x=1, y=1, col="a"))
plotlist<- list(plot1, plot2, plot3, plot4)
Here is where you add it in:
commonplot <- ggarrange(plotlist = plotlist, ncol = 2, nrow = 2,
common.legend = TRUE, legend="bottom")
annotate_figure(commonplot,
top = "Column 1 Title Column 2 Title",
left = "Row 2 Title Row 1 Title")
You can either assign the ggarrange object as an object, or you can pipe it down to annotate_figure.
The documentation shows more functionality as well, like adding right and bottom labels and a common title.

Related

Expand margins of ggplot

Apologies for the simplistic question, but I'm having trouble adjusting the size (width) of this plot to include all the data so that it doesn't look so squished. I've tried adjusting the margins and the width in png(), but nothing seems to work.
png("file_name.png", units = "in", width = 10, height = 5, res = 300)
ggplot(pred, aes(x = Longitude, y = Latitude)) +
geom_raster(aes(fill = Fitted)) +
facet_wrap(~ CYR) +
scale_fill_viridis(option = 'plasma',
na.value = 'transparent') +
coord_quickmap() +
theme(legend.position = 'top')
# theme(plot.margin=grid::unit(c(0,20,0,20), "mm"))
dev.off()
Do you need to use coord_quickmap() for some reason? Removing it 'fixes' the plot dimensions, e.g. using the palmerpenguins dataset:
library(ggplot2)
library(palmerpenguins)
p1 <- ggplot(penguins, aes(x = sex,
y = bill_length_mm,
fill = bill_depth_mm)) +
geom_raster() +
scale_fill_viridis_c(option = 'plasma',
na.value = 'transparent') +
facet_wrap(~interaction(island, species, year)) +
theme(legend.position = 'top') +
coord_quickmap()
p1
#> Warning: Raster pixels are placed at uneven horizontal intervals and will be shifted
#> ℹ Consider using `geom_tile()` instead.
#> Warning: Removed 2 rows containing missing values (`geom_raster()`).
p2 <- ggplot(penguins, aes(x = sex,
y = bill_length_mm,
fill = bill_depth_mm)) +
geom_raster() +
scale_fill_viridis_c(option = 'plasma',
na.value = 'transparent') +
facet_wrap(~interaction(island, species, year)) +
theme(legend.position = 'top') #+
# coord_quickmap()
p2
#> Warning: Raster pixels are placed at uneven horizontal intervals and will be shifted
#> ℹ Consider using `geom_tile()` instead.
#> Removed 2 rows containing missing values (`geom_raster()`).
Created on 2023-02-13 with reprex v2.0.2

ggplot greek letter in label within for loop indices

I need to add the theta greek letter in the x-axis label of this plot(s):
var=c("a", "b", "c")
df=data.frame(x=c(1:20),y=c(41:60))
df_plot=list()
for (i in 1:length(var)) {
df_plot[[i]]=ggplot()+
geom_line(data=df, aes(x=x, y=y))+
xlab(paste("theta ", var[i]))
}
How can I do it?
If I use expression() I get the letter but not the index i.
Using bquote you could do:
Note: Instead of using a for loop I switched to lapply (and would suggest to so) as sooner or later you will run in issues related to tidy evaluation when using a for loop with ggplot. And there are plenty of questions on SO related to that. (:
var <- c("a", "b", "c")
df <- data.frame(x = c(1:20), y = c(41:60))
library(ggplot2)
lapply(var, function(x) {
ggplot() +
geom_line(data = df, aes(x = x, y = y)) +
xlab(bquote(theta*.(x)))
})
#> [[1]]
#>
#> [[2]]
#>
#> [[3]]

In ggplot2/stat_summary, how to add the `median` value as label to plot (as geom_text())

In ggplot2/stat_summary, how to add the median value as label to plot ? Thanks!
library(ggplot2)
d <- ggplot(mtcars, aes(cyl, mpg)) + geom_point()
d + stat_summary(fun = "median", colour = "red", size = 2, geom = "point")
One potential option is to use after_stat() to get the labels, i.e.
library(ggplot2)
d <- ggplot(mtcars, aes(cyl, mpg)) +
geom_point()
d + stat_summary(fun = "median", colour = "red", size = 4,
geom = "text", aes(label = after_stat(y)),
position = position_nudge(x = 0.25))
Created on 2022-05-16 by the reprex package (v2.0.1)

Rendering `%` using element_markdown()

How can I keep the % symbol in the title?
library(ggtext)
library(ggplot2)
ggplot(mtcars, aes(cyl, mpg)) +
geom_col() +
ggtitle("%") +
theme(plot.title = element_markdown())
Created on 2022-01-28 by the reprex package (v2.0.1)
You can just add a space before and the character will display correctly. Although there is a space, the formatting of the title will ignore this:
ggplot(mtcars, aes(cyl, mpg)) +
geom_col() +
ggtitle(" %") +
theme(plot.title = element_markdown())

How to include a legend to a ggplot2?

Given this data here:
p <- ggplot(mpg, aes(displ, cty)) + geom_point() + facet_grid(drv ~ cyl)
g <- ggplot_gtable(ggplot_build(p))
strip_both <- which(grepl('strip-', g$layout$name))
fills <- c("red","green","blue","yellow","red","green","blue","yellow")
k <- 1
for (i in strip_both) {
j <- which(grepl('rect', g$grobs[[i]]$grobs[[1]]$childrenOrder))
g$grobs[[i]]$grobs[[1]]$children[[j]]$gp$fill <- fills[k]
k <- k+1
}
grid.draw(g)
I want to add a legend for the colors of the facets:
as shown here
One option to achieve your desired result would be with an auxiliary geom_point layer which draws nothing but is only used to map a variable with your desired four categories on the fill aes. Doing so will automatically add a fill legend for which we could set your desired colors using scale_fill_manual. Additionally I switched the key_glyph for the point layer to draw_key_rectto mimic your desired style for the legend keys and added na.rm to silent the warning about removed NAs:
library(ggplot2)
library(grid)
p <- ggplot(mpg, aes(displ, cty)) + geom_point() + facet_grid(drv ~ cyl) +
geom_point(data = data.frame(x = NA_real_, y = NA_real_, fill = c("AB", "D", "FF", "v")),
aes(x = x, y = y, fill = fill), na.rm = TRUE, key_glyph = "rect") +
scale_fill_manual(values = c("AB" = "red", D = "yellow", FF = "blue", v = "green"), name = NULL) +
theme(legend.position = "bottom")
g <- ggplot_gtable(ggplot_build(p))
strip_both <- which(grepl('strip-', g$layout$name))
fills <- c("red","green","blue","yellow","red","green","blue","yellow")
k <- 1
for (i in strip_both) {
j <- which(grepl('rect', g$grobs[[i]]$grobs[[1]]$childrenOrder))
g$grobs[[i]]$grobs[[1]]$children[[j]]$gp$fill <- fills[k]
k <- k+1
}
grid.draw(g)