I am interested in creating a figure using ggplot2
similar to the one drafted here. I have created the top section using ggplot
and facet_wrap
but have yet to find a way to add a tiled legend to the bottom of the figure. Listed below is code for a fake dataset and my attempt so far, which produces this.
data1 <- data.frame(lower = c(0, 2, 1, 0, 4,
3, 2, 2, 3, 0),
upper = c(7, 6, 9, 10, 9,
10, 6, 5, 6, 10),
point = c(3.5, 4, 5, 5, 6.5,
6.5, 4, 3.5, 4.5, 5),
variable = c("Var 1", "Var 1", "Var 1", "Var 1", "Var 1",
"Var 2", "Var 2", "Var 2", "Var 2", "Var 2"),
specification = c("Study 1A", "Study 1B", "Study 1C", "Study 2A", "Study 2B",
"Study 1A", "Study 1B", "Study 1C", "Study 2A", "Study 2B"),
treatment_size = c(1, 2, 3, 1, 4,
1, 2, 3, 1, 4),
treatment_info = c("No", "Yes", "Yes", "No", "Yes",
"No", "Yes", "Yes", "No", "Yes"))
rect <- data.frame(xmin = c("Study 1A",
"Study 1A"),
xmax = c("Study 2B",
"Study 2B"),
ymin = c(data1$lower[3],
data1$lower[6]),
ymax = c(data1$upper[3],
data1$upper[6]),
alpha = c(0.1, 0.1),
fill = c("blue", "blue"))
plot <- ggplot(data1, aes(x=specification, y=point)) +
geom_errorbar(width=0.1, aes(ymin=lower, ymax=upper)) +
geom_point(shape=21, size=0.5, fill="black") +
ylab("Effect") +
xlab("") +
theme(axis.text.x=element_text(angle=90, vjust=0.5, hjust=1)) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
alpha = 0.1, fill = "blue",
data = transform(rect, variable = c("Var 1", "Var 2")),
inherit.aes = FALSE)
plot + facet_wrap(vars(variable), ncol = 1)
One option to achieve or at least come close to your desired result would be to create the legend as a second ggplot
which could then be glued to your main plot using patchwork
. Basically this involves some data wrangling as first step and more or less styling via theme options to achieve the table look.
Note: I also adjusted the main plot slightly to achieve the look as in the image you added as an example of your desired result.
library(dplyr)
library(tidyr)
library(ggplot2)
library(patchwork)
plot <- ggplot(data1, aes(x = specification, y = point)) +
geom_errorbar(width = 0.1, aes(ymin = lower, ymax = upper)) +
geom_point(shape = 21, size = 0.5, fill = "black") +
ylab("Effect") +
xlab("") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = ymin, ymax = ymax),
alpha = 0.1, fill = "blue",
data = transform(rect, variable = c("Var 1", "Var 2")),
inherit.aes = FALSE
)
pmain <- plot +
facet_wrap(vars(variable), ncol = 1) +
theme_void() +
theme(strip.background.x = element_rect(fill = "grey95", color = NA),
strip.text.x = element_text(margin = margin(t = 5, b = 5))
)
data2 <- data1 |>
distinct(specification, treatment_size, treatment_info) |>
mutate(across(everything(), as.character)) |>
pivot_longer(-specification, names_prefix = "^treatment_") |>
mutate(fill = if_else(value %in% c("Yes", "No"), value, "grey"),
label = if_else(value %in% c("Yes", "No"), NA_character_, value))
ptable <- ggplot(data2, aes(specification, name)) +
geom_tile(aes(fill = fill), width = .975, height = .975, color = "black") +
geom_text(aes(label = label)) +
scale_fill_manual(values = c(Yes = "green", No = "red", grey = "grey95")) +
scale_y_discrete(limits = c("size","info"), labels = c("Size", "Info"), expand = c(0, 0.5)) +
scale_x_discrete(position = "top", expand = c(0, 0.5)) +
theme_void() +
guides(fill = "none") +
theme(axis.text.x = element_text(margin = margin(t = 5, b = 5)),
axis.text.y = element_text(margin = margin(l = 5, r = 5))) +
coord_fixed(ratio = .5)
pmain / ptable