Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move ggplot legend into title area

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:

Two sets of bar charts.  On the left, they are grey and showing hp.  On the right, they are red and blue and showing drat and wt respectively.  The area to the right of the title on the red/blue chart is manually highlighted in yellow.

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?

like image 541
Margaret Avatar asked Nov 01 '25 02:11

Margaret


2 Answers

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

like image 194
M-- Avatar answered Nov 02 '25 20:11

M--


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

enter image description here

like image 32
zx8754 Avatar answered Nov 02 '25 20:11

zx8754



Donate For Us

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