3

I am trying to create a stacked barplot for one response over time (Year) across 3 different sites that I've separated into different facets (facet_wrap). I would like different colours per facet, and I thought the easiest way of achieving this would be to create a new variable ('Col_Var'), but keeping the facet per site. This gives me almost exactly what I'm after.

enter image description here

But I would like a simpler legend whereby all of the darker colours (i.e., 3 boxes) are placed next to the 'Type A' label, and the 3 lighter colour boxes are places next to 'Type B' (my labels are ideally much longer than this so the legend becomes very chaotic). In other words, can I place multiple boxes / symbols next to 1 label in a ggplot legend? Some example code below, any help or advice much appreciated, many thanks.

Plot_df <- data.frame(Site = rep(c("Site A","Site B","Site C"),each =10), 
                      Type = rep(c("Type A","Type B"),times =15), 
                      Year = rep(rep(seq(2010,2014,1),each=2),times=3),
                      Value = rnorm(30, mean=50, sd=10))
Plot_df$Col_Var <- as.factor(paste(Plot_df$Site,Plot_df$Type))

Stacked_Plot_Colours <- "#027E5D" "#89EFC7" "#6F2D01" "#F5773A" "#3A3663" "#8F8ACD"

 Stacked_Plot <- ggplot(Plot_df) +
  geom_bar(aes(x = as.factor(Year), y = Value, fill = Col_Var),position = "stack",stat = 
"identity") +
  facet_wrap(~ Site,ncol=1) +  scale_fill_manual(values=Stacked_Plot_Colours)+
  theme(legend.position = "top",legend.title = element_blank(),
        panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        panel.background = element_blank(), axis.line = element_line(colour = "black"))
Stacked_Plot

1 Answer 1

3

For your legend one option would be to replace the first two labels per row by an empty string and do some cleaning for the last label:

library(ggplot2)

ggplot(Plot_df) +
  geom_bar(aes(x = as.factor(Year), y = Value, fill = Col_Var),
    position = "stack", stat =
      "identity"
  ) +
  facet_wrap(~Site, ncol = 1) +
  scale_fill_manual(
    labels = \(x) {
      x[!seq_along(x) %in% 5:6] <- ""
      gsub("^Site\\s.*?\\s", "", x)
    },
    values = Stacked_Plot_Colours
  ) +
  theme(
    legend.position = "top", legend.title = element_blank(),
    panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
    panel.background = element_blank(), axis.line = element_line(colour = "black")
  )

enter image description here

UPDATE If you want to put the legend in one row you could reorder the categories or keys using the breaks argument. However, doing so also requires to account for the reordered breaks when replacing the "undesired" labels by the empty string:

scale_fill_manual(
  breaks = \(x) {
    x[c(1, 3, 5, 2, 4, 6)]
  },
  labels = \(x) {
    x[!seq_along(x) %% 3 == 0] <- ""
    gsub("^Site\\s.*?\\s", "", x)
  },
  values = Stacked_Plot_Colours,
  guide = guide_legend(nrow = 1)
)

enter image description here

2
  • This is brilliant thanks! Any idea how to change the legend so its one 1 row? I tried using '+guides(fill = guide_legend(nrow=1))' but it doesn't work as the colours are then jumbled up. Commented Jan 25 at 15:31
  • See my update to have only one row.
    – stefan
    Commented Jan 25 at 15:54

Not the answer you're looking for? Browse other questions tagged or ask your own question.