Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R, change ggplot legend names with scale_linetype_manual

Tags:

plot

r

ggplot2

I have a dataframe which looks like this:

> df
    Year mpft       value   type index
1   1996    2 0.033827219  solid   2.1
2   1997    2 0.133278701  solid   2.1
3   1998    2 0.261428650  solid   2.1
4   1999    2 0.394702438  solid   2.1
5   1996    3 0.019079686  solid   3.1
6   1997    3 0.074332942  solid   3.1
7   1998    3 0.149042964  solid   3.1
8   1999    3 0.227812452  solid   3.1
9   1996    4 0.009909126  solid   4.1
10  1997    4 0.026231721  solid   4.1
11  1998    4 0.052912805  solid   4.1
12  1999    4 0.086256016  solid   4.1
13  1996   17 0.017256492  solid  17.1
14  1997   17 0.079446280  solid  17.1
15  1998   17 0.166014538  solid  17.1
16  1999   17 0.316175339  solid  17.1
17  1996   18 0.080072523  solid  18.1
18  1997   18 0.313289644  solid  18.1
19  1998   18 0.629398957  solid  18.1
20  1999   18 1.024946245  solid  18.1
110 1996    2 0.031634282 dashed   2.2
21  1997    2 0.139244701 dashed   2.2
31  1998    2 0.273270126 dashed   2.2
41  1999    2 0.412409808 dashed   2.2
51  1996    3 0.019430502 dashed   3.2
61  1997    3 0.079252516 dashed   3.2
71  1998    3 0.161607337 dashed   3.2
81  1999    3 0.252595611 dashed   3.2
91  1996    4 0.009976637 dashed   4.2
101 1997    4 0.027057403 dashed   4.2
111 1998    4 0.055755671 dashed   4.2
121 1999    4 0.093064641 dashed   4.2
171 1996   18 0.061041422 dashed  18.2
181 1997   18 0.245554619 dashed  18.2
191 1998   18 0.490633135 dashed  18.2
201 1999   18 0.758070060 dashed  18.2

I am trying to plot the data and have the right legend, so far I have initially tried with

ggplot(df,aes(x=Year,y=value, colour = factor(mpft),linetype=type)) +
      geom_line(aes(group = index), size = 1.4) +
      #scale_linetype_manual(name= "Run Type", values = unique(df$type), labels = run.type) +
      scale_color_manual(name = "PFT",
                         values = setNames(mycol[unique(df$mpft)], unique(df$mpft)),
                         labels = setNames(mynam[unique(df$mpft)], unique(df$mpft)))

Which gives me

enter image description here

I have tried adding a scale_linetype_manual with

ggplot(df,aes(x=Year,y=value, colour = factor(mpft),linetype=type)) +
      geom_line(aes(group = index), size = 1.4) +
      scale_linetype_manual(name= "Run Type", values = unique(df$type), labels = run.type) +
      scale_color_manual(name = "PFT",
                         values = setNames(mycol[unique(df$mpft)], unique(df$mpft)),
                         labels = setNames(mynam[unique(df$mpft)], unique(df$mpft)))

with

> run.type
[1] "current" "origED3"

But I get

enter image description here

which has the right names for the legend but has a different linetype. What am I missing?

EDIT

The dput of my dataframe is

> dput(df)
structure(list(Year = c(1996, 1997, 1998, 1999, 1996, 1997, 1998, 
1999, 1996, 1997, 1998, 1999, 1996, 1997, 1998, 1999, 1996, 1997, 
1998, 1999, 1996, 1997, 1998, 1999, 1996, 1997, 1998, 1999, 1996, 
1997, 1998, 1999, 1996, 1997, 1998, 1999), mpft = c(2L, 2L, 2L, 
2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 17L, 17L, 17L, 17L, 18L, 
18L, 18L, 18L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 
18L, 18L, 18L, 18L), value = c(0.0338272191848643, 0.133278701149992, 
0.261428650232716, 0.394702437670559, 0.0190796862689925, 0.0743329421068756, 
0.149042964352043, 0.227812451937011, 0.00990912614900737, 0.0262317206863519, 
0.0529128049802722, 0.0862560162908444, 0.017256491619149, 0.0794462797803606, 
0.166014537897384, 0.31617533869767, 0.0800725232220131, 0.31328964372358, 
0.629398957462415, 1.02494624459608, 0.0316342818911836, 0.139244700529005, 
0.273270126484303, 0.412409807917143, 0.0194305022713642, 0.0792525159706922, 
0.161607337403947, 0.252595610607411, 0.00997663742883768, 0.0270574028188436, 
0.0557556714277292, 0.0930646413413941, 0.0610414215913856, 0.245554619318541, 
0.490633135315979, 0.758070059865948), type = structure(c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L), .Label = c("solid", "dashed"), class = "factor"), 
    index = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 
    3L, 3L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 7L, 
    7L, 7L, 7L, 8L, 8L, 8L, 8L, 9L, 9L, 9L, 9L), .Label = c("2.1", 
    "3.1", "4.1", "17.1", "18.1", "2.2", "3.2", "4.2", "18.2"
    ), class = "factor")), .Names = c("Year", "mpft", "value", 
"type", "index"), row.names = c("1", "2", "3", "4", "5", "6", 
"7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", 
"18", "19", "20", "110", "21", "31", "41", "51", "61", "71", 
"81", "91", "101", "111", "121", "171", "181", "191", "201"), class = "data.frame")

EDIT

Not a very elegant solution but substituting "dashed" with "22" and then using:

ggplot(df,aes(x=Year,y=value, colour = factor(mpft),linetype=type)) +
      geom_line(aes(group = index), size = 1.4) +
      scale_linetype_manual(name= "Run Type", values = unique(as.character(df$type)), labels = run.type) +
      scale_color_manual(name = "PFT",
                         values = setNames(mycol[unique(df$mpft)], unique(df$mpft)),
                         labels = setNames(mynam[unique(df$mpft)], unique(df$mpft)))

I am able to get it right

enter image description here

like image 202
Manfredo Avatar asked May 11 '18 13:05

Manfredo


2 Answers

Interesting question, and one I haven't come across on SO before.

Short answer

The difference is because the linetype in your first version isn't "dashed" at all.

Long answer

In your first version, without specifying anything for the linetype aesthetic, ggplot defaults to scale_linetype_discrete(), and the current code for that is:

scale_linetype <- function(..., na.value = "blank") {
  discrete_scale("linetype", "linetype_d", linetype_pal(),
    na.value = na.value, ...)
}

Hence, scale_linetype_discrete() gets its linetype values from the linetype_pal function, courtesy of the scales package (at least, that's the only place I found it):

> scales::linetype_pal()(2)
[1] "solid" "22"  

When you specified the linetype aesthetic mapping in the second version, using scale_linetype_manual(), the corresponding current code is:

scale_linetype_manual <- function(..., values) {
  manual_scale("linetype", values, ...)
}

Thus when you explicitly ask for c("solid", "dashed") as the two linetype values in your plot, ggplot uses them. When you don't, the default values are c("solid", "22"), and "22" corresponds to a different, more tightly spaced pattern than "dashed"'s pattern.

Demonstration below, using built-in data:

df.sample <- diamonds %>% 
  filter(cut %in% c("Fair", "Good")) %>%
  group_by(cut, clarity) %>% 
  summarise(price = mean(price / carat)) %>%
  ungroup() 

p <- ggplot(df.sample,
            aes(x = clarity, y = price, group = cut,
                linetype = cut)) +
  geom_line(size = 1) +
  guides(linetype = guide_legend(keywidth = 3, keyheight = 1)) +
  theme(legend.position = c(1, 0), legend.justification = c(1, 0))

library(gridExtra)
grid.arrange(p + 
               labs(title = "Default scale",
                    subtitle = c("values = linetype_pal()(2)")),
             p + scale_linetype_manual(values = c("solid", "dashed")) +
               labs(title = "Manual scale",
                    subtitle = "values = c('solid', 'dashed')"),
             p + scale_linetype_manual(values = c("solid", "22")) +
               labs(title = "Manual scale",
                    subtitle = "values = c('solid', '22')"),
             nrow = 1)

The third plot mimics the behaviour of the default scale.

plot

like image 109
Z.Lin Avatar answered Oct 11 '22 07:10

Z.Lin


you're just not able to see the linetype difference - if you make the legend wider it's visible:

ggplot(df,aes(x=Year,y=value, colour = factor(mpft),linetype=type)) +
  geom_line(aes(group = index), size = 1.4) +
  scale_linetype_manual(name= "Run Type", values = unique(df$type), labels = run.type) +
  guides(linetype = guide_legend(keywidth = 3, keyheight = 1)) 
like image 43
John Walker Avatar answered Oct 11 '22 08:10

John Walker