Home > Mobile >  Adding a second legend for vertical lines in ggplot
Adding a second legend for vertical lines in ggplot

Time:12-14

I've created a time series plot using ggplot2 on a melted data frame, and as part of this I've used geom_vline to add vertical lines to the plot to represent 1 of 2 events happening at different points in time- either an opening or a closure. As I've got 6 vertical lines on the plot which all need to be labelled, using the annotate function makes the plot look bit messy. I was wondering if there is a way of adding a second legend onto the plot just for the vertical lines that I have added?

I've tried using scale_linetype_manual, but it doesn't seem to work

p<- data %>% 
  ggplot(aes(variable, value/100))  
  geom_line(aes(color = size, group = size), 
            size = 0.5, linetype="dashed")   
  geom_point(aes(color = size, group = size), 
             size = 2)   
  geom_vline(xintercept = c(1,9,11), linetype="dotted", 
             color = "red", size=1)  
  geom_vline(xintercept = c(5,14,17), linetype="dotted", 
             color = "blue", size=1)  
scale_linetype_manual(name = 'Events',
                        values = c('Closures' = 3,
                                   'Opening' = 3),
                        guide = guide_legend(override.aes = list(colour = c('red',
                                                                         'blue')))) 

CodePudding user response:

A good way to do this could be to use mapping= to create the second legend in the same plot for you. The key is to use a different aesthetic for the vertical lines vs. your other lines and points.

First, the example data and plot:

library(ggplot2)
library(dplyr)
library(tidyr)

set.seed(8675309)
df <- data.frame(x=rep(1:25, 4), y=rnorm(100, 10, 2), lineColor=rep(paste0("col",1:4), 25))

base_plot <-
df %>%
  ggplot(aes(x=x, y=y))  
  geom_line(aes(color=lineColor))  
  scale_color_brewer(palette="Greens")
base_plot

enter image description here

Now to add the vertical lines as OP has done in their question:

base_plot  
  geom_vline(xintercept = c(1,9,11), linetype="dotted", 
            color = "red", size=1)  
  geom_vline(xintercept = c(5,14,17), linetype="dotted", 
             color = "blue", size=1)

enter image description here

To add the legend, we will need to add another aesthetic in mapping=. When you use aes(), ggplot2 expects that mapping to contain the same number of observations as the dataset specified in data=. In this case, df has 100 observations, but we only need 6 lines. The simplest way around this would be to create a separate small dataset that's used for the vertical lines. This dataframe only needs to contain two columns: one for xintercept and the other that can be mapped to the linetype:

verticals <- data.frame(
  intercepts=c(1,9,11,5,14,17),
  Events=rep(c("Closure", "Opening"), each=3)
)

You can then use that in code with one geom_vline() call added to our base plot:

second_plot <- base_plot  
  geom_vline(
    data=verticals,
    mapping=aes(xintercept=intercepts, linetype=Events),
    size=0.8, color='blue',
    key_glyph="path"   # this makes the legend key horizontal lines, not vertical
  )
second_plot

enter image description here

While this answer does not use color to differentiate the vertical lines, it's the most in line with the Grammar of Graphics principles which ggplot2 is built upon. Color is already used to indicate the differences in your data otherwise, so you would want to separate out the vertical lines using a different aesthetic. I used some of these GG principles putting together this answer - sorry, the color palette is crap though lol. In this case, I used a sequential color scale for the lines of data, and a different color to separate out the vertical lines. I'm showing the vertical line size differently than the lines from df to differentiate more and use the linetype as the discriminatory aesthetic among the vertical lines.

You can use this general idea and apply the aesthetics as you see best for your own data.

CodePudding user response:

What about geom_label?

library(tidyverse)

data <- tribble(
  ~x, ~label,
  1, "first",
  1.5, "second",
  5, "third"
)

data %>%
  ggplot(aes(x = x, y = 1))  
  geom_vline(aes(xintercept = x))  
  geom_label(aes(label = label))

Created on 2021-12-13 by the reprex package (v2.0.1)

  • Related