tidyverse / ggplot2

An implementation of the Grammar of Graphics in R
https://ggplot2.tidyverse.org
Other
6.48k stars 2.02k forks source link

Theme option to align the legend to the plot instead of the panel #5959

Closed sambtalcott closed 3 months ago

sambtalcott commented 3 months ago

I often use the plot.title.position = "plot" argument to theme() to get my plot's title to align to the plot rather than the panel. This is especially helpful when the y-axis labels are long.

I sometimes want to add a horizontal legend to the top of charts like this. However, there is no current way to align the legend to the plot in the same way as the title. You can either left-align to the panel, which leaves a gap that looks weird compared to the nicely aligned title/subtitle:

diamonds |> 
  dplyr::count(cut, color) |> 
  ggplot(aes(n, cut, fill = color)) + 
  geom_col(position = "fill") + 
  labs(title = "Diamonds by Color and Cut",
       subtitle = "An example chart",
       fill = NULL, y = NULL, x = NULL) + 
  guides(fill = guide_legend(reverse = TRUE, nrow = 1)) + 
  ggthemes::theme_hc() + 
  theme(plot.title.position = "plot",
        legend.direction = "horizontal",
        legend.position = "top",
        legend.justification = "left")

image

Or you can create manual space in the subtitle and tweak the position of the legend just right to get it into place:

diamonds |> 
  dplyr::count(cut, color) |> 
  ggplot(aes(n, cut, fill = color)) + 
  geom_col(position = "fill") + 
  labs(title = "Diamonds by Color and Cut",
       subtitle = "An example chart\n\n",
       fill = NULL, y = NULL, x = NULL) + 
  guides(fill = guide_legend(reverse = TRUE, nrow = 1)) + 
  ggthemes::theme_hc() + 
  theme(plot.title.position = "plot",
        legend.direction = "horizontal",
        legend.position = c(-0.18, 1.1),
        legend.justification = "left")

image

The second option achieves the look I want, but it requires trial-and-error to get the right numbers for legend.position, and any change to the size of the output messes up the alignment.

I would like to be able to specify a plot.legend.position similar to plot.title.position that would align the legend to the plot instead of the panel:

theme(plot.title.position = "plot",
      plot.legend.position = "plot",
      legend.direction = "horizontal",
      legend.position = "top",
      legend.justification = "left")
teunbrand commented 3 months ago

I'm closing this as a duplicate of #4020. This was introduced in 3.5.0 as legend.location = "plot". You might like to combine this with legend.margin = margin(l = 0)

library(tidyverse)

diamonds |> 
  dplyr::count(cut, color) |> 
  ggplot(aes(n, cut, fill = color)) + 
  geom_col(position = "fill") + 
  labs(title = "Diamonds by Color and Cut",
       subtitle = "An example chart",
       fill = NULL, y = NULL, x = NULL) + 
  guides(fill = guide_legend(reverse = TRUE, nrow = 1)) + 
  ggthemes::theme_hc() + 
  theme(plot.title.position = "plot",
        legend.direction = "horizontal",
        legend.position = "top",
        legend.justification = "left", 
        legend.location = "plot")

Created on 2024-06-27 with reprex v2.1.0

sambtalcott commented 3 months ago

Thank you! Didn't realize this had already been implemented.