Search code examples
rggplot2cowplot

Fixing position of legend


Here is my data and corresponding ggplot

library(ggplot2)
library(ggnewscale)
library(cowplot)
library(ggalluvial)
library(patchwork)

data = 
structure(list(grp1 = c("X", "X", "X", "X", "Y", "Y", "Y", "Y"
), grp2 = c("A", "B", "C", "D", "A", "B", "C", "D"), val = c(1, 
2, 3, 4, 3, 4, 5, 6)), row.names = c(NA, -8L), class = "data.frame")

col_define = c('red', 'orange', 'blue', 'lightblue')
names(col_define) = c('A', 'B', 'C', 'D')

p <- ggplot(data, aes(x = grp1, group = grp2, y = val)) +
  geom_col(aes(fill = grp2)) +
  scale_fill_manual(values = col_define, breaks = c("A", "B"), name = "1") +
  new_scale_fill() +
  geom_col(aes(fill = grp2)) +
  scale_fill_manual(values = col_define, breaks = c("C", "D"), name = "2") +
  #guides(fill=guide_legend(order = 1, ncol = 2)) + 
  theme(legend.position="top", legend.direction = 'vertical')

p_legend <- cowplot::get_legend(p)

ggplot(data,
       aes(x = grp1, stratum = grp2, alluvium = grp2,
           y = val,
           fill = grp2)) +
  geom_flow(aes(fill = grp2), alpha = .3) +
  geom_stratum(aes(color = grp2), alpha = .9) +
  scale_fill_manual(values = col_define, breaks = names(col_define), aesthetics = c("color", "fill")) +
  guides(color = "none", fill = "none") +
  p_legend +
  theme(legend.position="top") +
  plot_layout(widths = c(50, 1))

I want to place the legend of the final plot at the top centred position within the plot window (i.e. light grey area). I tried with different inputs e.g. theme(legend.position="top"), however this does not seem to work.

Is there any way to fix the legend position at the top centred position within the plot window for above plot?

Note:

This plot is from the accepted answer of my earlier post available in

Grouping legend of ggplot for stacked bar chart


Solution

  • One option to add the legend to your plot inside the plot panel would be to use patchwork::inset_element.

    Note 1: I removed the legend.box.margin and set the legend.box.background fill to "white" but feel free to adjust that to your liking.

    Note 2: I wrapped the legend plot inside cowplot::ggdraw to remove the white margin around the legend.

    p <- ggplot(data, aes(x = grp1, group = grp2, y = val)) +
      geom_col(aes(fill = grp2)) +
      scale_fill_manual(values = col_define, breaks = c("A", "B"), name = "1") +
      new_scale_fill() +
      geom_col(aes(fill = grp2)) +
      scale_fill_manual(values = col_define, breaks = c("C", "D"), name = "2") +
      theme(legend.position="top", legend.direction = 'vertical', 
            legend.box.margin = margin(), 
            legend.box.background = element_rect(fill = "white", color = NA))
    
    p_legend <- cowplot::get_legend(p)
    
    p_main <- ggplot(data, aes(x = grp1, stratum = grp2, alluvium = grp2,
               y = val,
               fill = grp2)) +
      geom_flow(aes(fill = grp2), alpha = .3) +
      geom_stratum(aes(color = grp2), alpha = .9) +
      scale_fill_manual(values = col_define, breaks = names(col_define), aesthetics = c("color", "fill")) +
      guides(color = "none", fill = "none")
    
    p_main + 
      inset_element(ggdraw(p_legend), right = .6, top = 1, left = .4, bottom = .9, clip = TRUE)
    

    enter image description here