Search code examples
rggplot2linelegend

Add manual ggplot legend for combinations of features


How do I add a manual legend with labels for each of the following lines:

lty=1, lwd=2, color='black', label='Litigating'
lty=2, lwd=2, color='black', label='Non-litigating'
lty=1, lwd=1, color='gray', label='Reference'

Here is an ugly mockup to convey the idea. The exact position of the labels is not important. I just want one icon for each line.

enter image description here

Here is one approach I tried to make this, but the legend is exploded by feature, yielding six icons instead of three:

# Make a data.frame with 10 points and the aesthetics associated wit each
D_legend = data.frame(
  x = 1:10,
  y = rnorm(10),
  lwd = factor(c(2,2,2,2,2,2,1,1,1,1)),
  lty = factor(c(1,1,1,2,2,2,1,1,1,1)),
  color=c(rep('black', 6), rep('gray', 4))
)

# Plot it. I want a nice legend here!
ggplot(D_legend, aes(x=x, y=y, lty=lty, lwd=lwd, color=color)) + 
  geom_line() + 
  theme(legend.position="top")

enter image description here


Solution

  • Let's simply create an interaction variable that determines the kind of line:

    D_legend$type <- droplevels(with(D_legend, interaction(lty, lwd, color)))
    # Giving better names
    levels(D_legend$type) <- c("Litigating", "Non-litigating", "Reference")
    

    Now we may deal with each of the three aesthetics separately:

    ggplot(D_legend, aes(x = x, y = y, lty = type, lwd = type, color = type)) + 
      geom_line() + theme(legend.key.width = unit(2, "cm")) +
      scale_linetype_manual(
        NULL, 
        values = c("Litigating" = 1, "Non-litigating" = 2, "Reference" = 1)
      ) +
      scale_size_manual(
        NULL, 
        values = c("Litigating" = 2, "Non-litigating" = 2, "Reference" = 1)
      ) +
      scale_color_manual(
        NULL, 
        values = c("Litigating" = "black", "Non-litigating" = "black", "Reference" = "gray")
      )
    

    enter image description here

    I increased legend.key.width as otherwise it wasn't visible that the second line type is dashed. If you want the legend to have a name, then replace type by it and in this way you can also drop all the NULL.