rggplot2legend

ggplot legend: combining fill, color and shape and showing only selected variables


I am trying to make a plot that combines bars with points (of different colors and shapes). Therefore, I need to combine fill, color and shape in the same legend. I am close to my desired result, however I cannot get the shape legend to show up correctly in combination with the others (see the blue dot for "Top 2016", which should instead be a triangle). How to achieve this? (Bonus question: I would like to not have the grey shading behind the dots in the legend).

Moreover, I would like to remove the "Middle 2021" category from showing up in the legend. How to do this too?

Minimal working example code:

library(ggplot2)
library(data.table)

dt <- structure(list(country = c("AA", "BB", "CC", "AA", "BB", "CC", "AA", "BB",
                                 "CC", "AA", "BB", "CC", "AA", "BB", "CC", "AA",
                                 "BB", "CC", "AA", "BB", "CC", "AA", "BB", "CC"),
                     variable = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L,
                                            4L, 4L, 4L, 5L, 5L, 5L, 6L, 6L, 6L,
                                            7L, 7L, 7L, 8L, 8L, 8L),
                                          levels = c("low_2021", "middle_2021", 
                                                     "intermediate_2021", "advanced_2021",
                                                     "low_2016", "middle_2016",
                                                     "intermediate_2016", "advanced_2016"),
                                          class = "factor"),
                     value = c(25, 17, 19, 67, 75, 70, 75, 83, 81, 8, 8, 11, 19,
                               13, 14, 70, 76, 75, 81, 87, 86, 11, 11, 11)),
                row.names = c(NA, -24L),
                class = c("data.table", "data.frame"))

ggplot(mapping = aes(x=value,
                          y=country
                          )
            ) +
  geom_bar(data=dt[variable%in%c("low_2021",
                                 "middle_2021",
                                 "advanced_2021")],
           aes(fill=variable),
           stat="identity"
  ) +
  geom_point(data=dt[variable%in%c("intermediate_2016",
                                   "advanced_2016")],
             aes(color=variable,
                 shape=variable
                 )
             )+
  labs(x=NULL,
       y=NULL) +
  scale_fill_manual(breaks = c("advanced_2021",
                               "middle_2021",
                               "low_2021",
                               "advanced_2016",
                               "intermediate_2016"),
                    labels = c("Top 2021",
                               "Middle 2021",
                               "Low 2021",
                               "Top 2016",
                               "Low 2016"),
                    values = c("#8ED973",
                               "#D9D9D9",
                               "#F1A983",
                               "blue",
                               "red"),
                    aesthetics = c("fill", "color")
                    ) +
  guides(fill=guide_legend(ncol=2),
         shape="none") +
  theme(legend.position = "bottom",
        legend.title = element_blank())

enter image description here


Solution

  • I think its easier to split your data, geom() and aes() differently. The example was setting fill and color at the same time, with scale_fill_manual(...,aesthetics = c("fill", "color"), making ajustements harder in my opinion

    filter( dt , variable %in% c("low_2021",  "middle_2021",    "advanced_2021")) %>% 
      ggplot(aes(x = value, y = country,fill = variable)) +
      geom_bar(        stat="identity"
      )+
      labs(x=NULL,
           y=NULL) +
      scale_fill_manual(limits = c("advanced_2021",
                                   "low_2021"
      ),
      labels = c("Top 2021",
                 "Low 2021"
      ),
      values = c("#8ED973",
                 "#F1A983"
      ), na.value="#D9D9D9",
      aesthetics = c("fill")
      ) +
      geom_point(data =filter(dt, variable %in%c("intermediate_2016",
                                                 "advanced_2016")),
                 aes(col = variable, shape = variable), 
                 size = 2)+
      scale_color_manual(limits = c("advanced_2016",
                                    "intermediate_2016"),
                         labels = c("Top 2016","Low 2021"),
                         values = c("blue","red") 
      )+
      scale_shape_manual(limits = c("advanced_2016",
                                    "intermediate_2016"),
                         labels = c("Top 2016","Low 2021"),
                         values = c( 17,19) 
      )+
      guides(fill=guide_legend(ncol=1)  ,
             color=guide_legend(ncol=1)
      ) +
      theme(legend.position = "bottom",
            legend.title = element_blank(),
            legend.key = element_blank()
      )
    

    ggplot of the example