Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to add legend to plot with multiple lines using ggplot

So, this is the data that I have:

x <- seq(-5, 5, length=1000)
y1 <- dnorm(x, 0, 0.2)
y2 <- dnorm(x, 0, 1)

data1 <- data.frame(x, y1, y2)

I generate a graph with an example of the distribution of two variables, and I generate the graph like so:

p <- data1 %>% ggplot()
p + geom_line(aes(x, y1), linetype = 2) + geom_line(aes(x, y2)) + geom_line(aes(x, y= 0)) + 
  geom_text(aes(x = 0, y = -0.05, label = "Party A"), nudge_x = 0.5) + 
  geom_text(aes(x = 0, y = -0.05, label = "Party B"), nudge_x = - 0.5) +
  xlab("Ideological scale: Left to Right") +  
  ylab("Prabability") 

I am trying to add the legend showing that the dashed line is the distribution of party A and the solid line is the distribution of party B. How can I add the legend?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

ggplot2 really prefers "long data". I’ll use tidyr::pivot_longer here (as well as dplyr for some massaging) to convert from wide to long, but it can also easily be done with data.table or (with a touch more work) base R.

A quick demo of wide-to-long:

library(tidyr)
library(dplyr)
pivot_longer(data1, -x, names_to = "y", values_to = "val") |>
  mutate(lbl = if_else(y == "y1", "Party A", "Party B"))
# # A tibble: 2,000 × 4
#        x y           val lbl    
#    <dbl> <chr>     <dbl> <chr>  
#  1 -5    y1    3.83e-136 Party A
#  2 -5    y2    1.49e-  6 Party B
#  3 -4.99 y1    1.34e-135 Party A
#  4 -4.99 y2    1.56e-  6 Party B
#  5 -4.98 y1    4.65e-135 Party A
#  6 -4.98 y2    1.64e-  6 Party B
#  7 -4.97 y1    1.62e-134 Party A
#  8 -4.97 y2    1.73e-  6 Party B
#  9 -4.96 y1    5.59e-134 Party A
# 10 -4.96 y2    1.81e-  6 Party B
# # ℹ 1,990 more rows
# # ℹ Use `print(n = ...)` to see more rows

This allows us to have simpler geom_* calls, typically down to a single. I’ll also infer that we can replace your geom_line(aes(x, y=0)) to geom_hline, in order to add the horizontal line.

library(ggplot2)
pivot_longer(data1, -x, names_to = "y", values_to = "val") |>
  mutate(lbl = if_else(y == "y1", "Party A", "Party B")) |>
  ggplot(aes(x, val)) +
  geom_line(aes(group = y, linetype = lbl)) +
  geom_hline(yintercept = 0) +
  geom_text(
    aes(label = lbl),
    data = ~ filter(., val > max(val)/2, .by = y) %>% slice_head(n = 1, by = lbl),
    hjust = 1.2
  ) +
  scale_linetype_manual(values = c("Party A"=2, "Party B"=1))

ggplot2 with labels and legend

I also add the label programmatically by updating the data= inside the geom_text call, using the ~-style "function" expression.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading