rggplot2legend

How to avoid overlapping of legend types in ggplot2


Here is my data in dput format:

structure(list(group = c("Females", "Females", "Females", "Females", 
"Females", "Males", "Males", "Males", "Males", "Males"), x = c("age1", 
"age2", "age3", "age4", "age5", "age1", "age2", "age3", "age4", 
"age5"), Number = c(15.39484, 26.75518, 60.356684, 96.35884, 
125.212368, 15.717276, 23.479224, 41.24258, 56.911816, 66.10272
), Rate = c(12.81679, 22.41374, 49.219, 82.78327, 120.2018, 12.42771, 
19.17676, 33.32468, 48.22219, 62.51091)), class = "data.frame", row.names = c(NA, 
-10L))

I plotted bar chart with superimposed line chart by sex. Here is my code:

library(tidyverse)
p1 <- ggplot(data) +
         geom_bar(aes(x = x, y = Number, fill = group), 
                  stat="identity", position = position_dodge(width = 0.9)) +
         geom_line(aes(x = x, y = Rate, group = group, color = group)) +
         scale_fill_manual(values = c("#fab79c", "#9fadd5")) +
         scale_color_manual(values = c("#b20738", "#00549e"))

This is the resulting plot: enter image description here

It can be seen that the legend for bar chart and line chart are superimposed. I want legend for these two geoms to be separated as below:

enter image description here

I found a similar stackoverflow post here, which suggests converting data from wide to long format. I tried with the code below:

data2 <- data %>% 
            pivot_longer(cols = Number:Rate, 
                         names_to = "outcome", 
                         values_to = "val")

p2 <- ggplot() +
         geom_bar(data = data2 %>% filter(outcome == "Number"), 
                 aes(x = x, y = val, fill = group), 
                     stat = "identity", position = position_dodge(width = 0.9)) +
         geom_line(data = data2 %>% filter(outcome == "Rate"), 
                   aes(x = x, y = val, group = group, color = group)) +
         scale_fill_manual(values = c("#fab79c", "#9fadd5")) +
         scale_color_manual(values = c("#b20738", "#00549e")) 

However, the legends are still superimposed.

I would like to ask if there is any approach to separate the legends? Thank you.


Solution

  • Just add a column "group2" specifying the group you want to color your lines:

    data <- structure(list(group = c("Females", "Females", "Females", "Females", 
                             "Females", "Males", "Males", "Males", "Males", "Males"), x = c("age1", 
                                                                                            "age2", "age3", "age4", "age5", "age1", "age2", "age3", "age4", 
                                                                                            "age5"), Number = c(15.39484, 26.75518, 60.356684, 96.35884, 
                                                                                                                125.212368, 15.717276, 23.479224, 41.24258, 56.911816, 66.10272
                                                                                            ), Rate = c(12.81679, 22.41374, 49.219, 82.78327, 120.2018, 12.42771, 
                                                                                                        19.17676, 33.32468, 48.22219, 62.51091)), class = "data.frame", row.names = c(NA, 
                                                                                                                                                                                      -10L))
    
    data$group2 <- c(rep('Females (number of deaths)', 5), rep('Males (number of deaths)', 5))
    
    library(ggplot2)
    p1 <- ggplot(data) +
      geom_bar(aes(x = x, y = Number, fill = group), 
               stat="identity", position = position_dodge(width = 0.9)) +
      geom_line(aes(x = x, y = Rate, group = group2, color = group2)) +
      scale_fill_manual(values = c("#fab79c", "#9fadd5")) +
      scale_color_manual(values = c("#b20738", "#00549e"))
    
    > data
         group    x    Number      Rate                     group2
    1  Females age1  15.39484  12.81679 Females (number of deaths)
    2  Females age2  26.75518  22.41374 Females (number of deaths)
    3  Females age3  60.35668  49.21900 Females (number of deaths)
    4  Females age4  96.35884  82.78327 Females (number of deaths)
    5  Females age5 125.21237 120.20180 Females (number of deaths)
    6    Males age1  15.71728  12.42771   Males (number of deaths)
    7    Males age2  23.47922  19.17676   Males (number of deaths)
    8    Males age3  41.24258  33.32468   Males (number of deaths)
    9    Males age4  56.91182  48.22219   Males (number of deaths)
    10   Males age5  66.10272  62.51091   Males (number of deaths)
    
    > p1
    

    newplot

    Now removing legend's names and spacing between them.

    p1 <- ggplot(data) +
      geom_bar(aes(x = x, y = Number, fill = group), 
               stat="identity", position = position_dodge(width = 0.9)) +
      geom_line(aes(x = x, y = Rate, group = group2, color = group2)) +
      scale_fill_manual(values = c("#fab79c", "#9fadd5")) +
      scale_color_manual(values = c("#b20738", "#00549e")) +
      theme(legend.title = element_blank(),
            legend.margin = margin(-8,0,-8,0))
    
    > p1
    

    plot2

    You just have to play a little bit with the margin function to achieve what you want.