I have a series of paired ggplot charts I am getting to render together using cowplot. However, while the legend is useful, it's getting in the way - the charts that need legends become a lot smaller than their equivalents so you can't compare them as easily. Here's a simple example of the kind of chart I'm creating:
library(dplyr)
library(tidyr)
library(stringr)
library(tibble)
library(ggplot2)
library(cowplot)
df <- mtcars %>%
rownames_to_column("model") %>%
filter(str_detect(model, 'Merc')) %>%
pivot_longer(cols = -model, names_to = 'metric') %>%
filter(metric %in% c("hp", "drat", "wt"))
p1 <- df %>%
filter(metric == "hp") %>%
ggplot(aes(x = metric, y = value)) +
geom_col() +
facet_grid(model~.) +
labs(title = "hp")
p2 <- df %>%
filter(!metric == "hp") %>%
ggplot(aes(x = metric, y = value, fill = metric)) +
geom_col() +
facet_grid(model~.) +
labs(title = "drat and wt") +
theme(legend.position = 'none')
plot_grid(p1, p2)
Which comes out looking like this:

I'd ideally like to drop the legend in the spot I've highlighted in yellow, since there's space, and it visually connects to the chart that needs it. But I have poked my way through assorted documentation for both ggplot2 and cowplot, but I haven't figured it out.
What am I missing?
We can use ggdraw(); just note that this is not exactly a robust solution and you need to tweak the position and size of the legend in the last draw_plot to get it right for your desired aspect ratio.
p1 <- df %>%
filter(metric == "hp") %>%
ggplot(aes(x = metric, y = value)) +
geom_col() +
facet_grid(model~.) +
labs(title = "hp")
p2 <- df %>%
filter(!metric == "hp") %>%
ggplot(aes(x = metric, y = value, fill = metric)) +
geom_col() +
facet_grid(model~.) +
labs(title = "drat and wt") +
theme(legend.position = "top",
legend.direction = "horizontal",
legend.margin = margin(0, 0, 0, 0),
legend.box.margin = margin(0, 0, 0, 0))
ggdraw() +
draw_plot(p1,
x = 0, y = 0, width = 0.5, height = 1) +
draw_plot(p2 + theme(legend.position = 'none'),
x = 0.5, y = 0, width = 0.5, height = 1) +
draw_plot(get_legend(p2),
x = 0.72, y = 0.943, width = 0.25, height = 0.07)

Created on 2025-07-22 with reprex v2.1.1
This is an alternative using ggtext, it does not directly answers your question of adding legend next to title, instead we will colour the text to replace the legend:
Add custom colours for fill:
p1 <- df %>%
filter(metric == "hp") %>%
ggplot(aes(x = metric, y = value, fill = metric)) +
geom_col() +
facet_grid(model~.) +
scale_fill_manual(
name = NULL,
values = c(hp = "#0072B2", drat = "#009E73", wt = "#D55E00"),
labels = c(
hp = "<i style='color:#0072B2'>I. hp</i>",
drat = "<i style='color:#009E73'>I. drat</i>",
wt = "<i style='color:#D55E00'>I. wt</i>")) +
theme(legend.position = "none")
p2 <- df %>%
filter(!metric == "hp") %>%
ggplot(aes(x = metric, y = value, fill = metric)) +
geom_col() +
facet_grid(model~.) +
scale_fill_manual(
name = NULL,
values = c(hp = "#0072B2", drat = "#009E73", wt = "#D55E00"),
labels = c(
hp = "<i style='color:#0072B2'>I. hp</i>",
drat = "<i style='color:#009E73'>I. drat</i>",
wt = "<i style='color:#D55E00'>I. wt</i>")) +
theme(legend.position = "none")
I prefer patchwork to combine plots:
library(patchwork)
(p1 | p2) +
plot_annotation(title = "My title:
<span style='color:#0072B2;'>hp</span>,
<span style='color:#009E73;'>drat</span>, and
<span style='color:#D55E00;'>wt</span>",
theme = theme(
plot.title = element_markdown(lineheight = 1.1),
legend.text = element_markdown(size = 11)
))

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With