Search code examples
rggplot2geom-barlegend-propertiesgeom-point

How can I show legend of multiple layers (geom_point and geom_bar)?


I have two data sets that I want to combine into one plot, one as a barplot (2 groups) and one as a point-line plot (1 group). I've managed to combine the plots and show the legend for the barplot, but whenever I try to show the legend for the points/line it doesn't work.

Here is an excerpt of my data sets (translated):

bargroup <- data.frame('Year' = as.numeric(rep(2001:2004, each = 2)),
                     'Group' = as.factor(rep(c('State', 'Country'), 4)),
                     'Share' = as.numeric(c(0.42, 0.41, 0.4, 0.4, 0.42, 0.4, 0.42, 0.38)))

plgroup <- data.frame('Year' = as.numeric(2001:2004),
                             'Group' = as.factor(rep('State', 4)),
                             'Value' = as.numeric(c(4.95, 5.31, 5.29, 4.96)))

Here's my current code:

ggplot() +
geom_bar(data = bargroup, aes(x = Year, y = Share, fill = Group, group = Group),
           stat = 'identity', position = position_dodge2(preserve = 'single')) +
  geom_point(data = plgroup, aes(y = Value*0.1, x = Year), size = 4, color = '#875DA3') +
  geom_line(data = plgroup, aes(y = Value*0.1, x = Year), size = 1, color = '#875DA3') +
  labs(x = 'Year') +
  scale_y_continuous(name = 'Share groups', labels = scales::percent,
                     sec.axis = sec_axis(~.*10, name = 'Cost')) +
  scale_fill_manual(labels = c('Share State', 'Share Country'), 
                    values = c('#659B7A', '#8CD7F0')) +
  scale_color_manual(labels = c('Total Cost'), 
                values = c('#875DA3')) +
  theme_minimal() +
  theme(legend.title = element_blank(),
        legend.position = 'bottom',
        plot.title = element_blank(),
        panel.grid.minor = element_blank(),
        axis.title.x = element_text(size = 18),
        axis.title.y = element_text(size = 18),
        axis.text = element_text(size = 16),
        legend.text = element_text(size = 18)) +
  guides(fill = guide_legend(nrow = 2, byrow = T))
dev.off()

This is the graph I get:

Graph 1

As you can see, the point/line group is not displayed in the legend. I then tried removing the argument scale_color_manual() and adjusting the geom_point() and geom_line() arguments like so:

  geom_point(data = plgroup, aes(y = Value*0.1, x = Year, color = Group), 
             size = 4, color = '#875DA3', show.legend = T)
  geom_line(data = plgroup, aes(y = Value*0.1, x = Year, color = Group),
            size = 1, color = '#875DA3', show.legend = T)

The graph I got from this was:

Graph 2

I got that same graph when I combined the two data sets using the melt() function.

I also tried just making 3 groups out of it and not showing the point/line group. That showed all 3 groups but unfortunately the point/line group was now - obviously - labeled with a square instead of its point/line symbol (in the legend).

Does anyone have any idea how I can adjust my code to show the point/line group as a single bullet point next to or below the other two groups? Preferably also with the option to pick the label name ('Total Cost').

Thank you so much in advance!


Solution

  • Rule of thumb: everything within aes() will produce a legend. So put size out of aes() AND color into aes():

    ggplot() +
      geom_bar(data = bargroup, aes(x = Year, y = Share, fill = Group, group = Group),
               stat = 'identity', position = position_dodge2(preserve = 'single')) +
      geom_point(data = plgroup, aes(y = Value*0.1, x = Year, color = '#875DA3'),size = 4) +
      geom_line(data = plgroup, aes(y = Value*0.1, x = Year, color = '#875DA3'),size = 1) +
      labs(x = 'Year') +
      scale_y_continuous(name = 'Share groups', labels = scales::percent,
                         sec.axis = sec_axis(~.*10, name = 'Cost')) +
      scale_fill_manual(labels = c('Share State', 'Share Country'), 
                        values = c('#659B7A', '#8CD7F0')) +
      scale_color_manual(labels = c('Total Cost'), 
                         values = c('#875DA3')) +
      theme_minimal() +
      theme(legend.title = element_blank(),
            legend.position = 'bottom',
            plot.title = element_blank(),
            panel.grid.minor = element_blank(),
            axis.title.x = element_text(size = 18),
            axis.title.y = element_text(size = 18),
            axis.text = element_text(size = 16),
            legend.text = element_text(size = 18)) +
      guides(fill = guide_legend(nrow = 2, byrow = T))
    

    enter image description here

    Changing the order of legend:

    guides(fill = guide_legend(nrow = 2, byrow = T, order=1))
    

    enter image description here