jakes
jakes

Reputation: 2085

Add a legend to a plot with 2 y axis

I've got a data:

ex <- structure(list(subgroups = c("Monday", "Tuesday", "Wednesday", 
"Thursday", "Friday", "Saturday", "Sunday"), y_right = c(113.42, 
95.3, 94.81, 145.21, 94.71, 161.08, 123.1), y_left = c(634, 453, 
479, 633, 365, 616, 472)), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -7L))

and a plot generated by the code:

ggplot(ex) + 
  geom_bar(aes(factor(subgroups, levels = c('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 
                                        'Saturday', 'Sunday')),
           y_left), fill = rgb(16/255, 72/255, 128/255), stat = 'identity') +
  geom_line(aes(factor(subgroups, levels = c('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 
                                         'Saturday', 'Sunday')),
            y_right * 4), colour = rgb(237/255, 165/255, 6/255), group = 1) + 
  geom_point(aes(factor(subgroups, levels = c('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 
                                          'Saturday', 'Sunday')),
             y_right * 4), color = rgb(237/255, 165/255, 6/255), size = 3) +
  theme_bw() +
  labs(x = 'weekday') +
  scale_y_continuous(sec.axis = sec_axis(~. / 4, name = 'y_right'))

that looks like below: enter image description here

I need to add a legend above a plot that would reflect which axis refers to which geom, i.e. something like this: enter image description here

How it can be done?

Upvotes: 1

Views: 1047

Answers (2)

kath
kath

Reputation: 7724

Without reshaping the data you can do the following:

ex$subgroups <- factor(ex$subgroups, levels = c('Monday', 'Tuesday', 'Wednesday', 'Thursday', 
                                                'Friday', 'Saturday', 'Sunday'))

ggplot(ex, aes(x = subgroups)) + 
  geom_bar(aes(y = y_left, fill = "y_left"), stat = 'identity') +
  geom_line(aes(y = y_right * 4, colour = "y_right"), group = 1) + 
  geom_point(aes(y = y_right * 4, colour = "y_right"), size = 3) +
  scale_fill_manual("", values = rgb(16/255, 72/255, 128/255)) +
  scale_color_manual("", values = rgb(237/255, 165/255, 6/255)) +
  theme_bw() +
  labs(x = 'weekday') +
  scale_y_continuous(sec.axis = sec_axis(~. / 4, name = 'y_right'))

enter image description here

Upvotes: 1

Roman
Roman

Reputation: 17648

You can try a tidyverse

library(tidyverse)
ex %>% 
  mutate(y_right = y_right *4) %>% 
  mutate(subgroups = factor(subgroups,
                      levels = c('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 
                                 'Saturday', 'Sunday'))) %>% 
  gather(k, v, - subgroups) %>% 
  ggplot(aes(subgroups, v)) + 
    geom_col(data = . %>% filter(k == "y_left"), aes(fill = k)) + 
    geom_point(data= . %>% filter(k == "y_right"), aes(color= k)) + 
    geom_line(data= . %>% filter(k == "y_right"), aes(color= k, group = k))  +
    scale_color_manual("", values =rgb(237/255, 165/255, 6/255)) + 
    scale_fill_manual("", values=rgb(16/255, 72/255, 128/255))+
    scale_y_continuous("y_left", sec.axis = sec_axis(~. / 4, name = 'y_right')) +
    theme(legend.spacing.y = unit(0,"pt"),
          legend.margin =  margin(t = 0, r = 0, b = 0, l = 0, unit = "pt"))

enter image description here

The idea is to give ggplot all data which is transformed from wide to long. Then individually subset the data.frame for the bars and points/lines, respectively. Lastly, change color and fill parameteres as well as legend position.

Upvotes: 3

Related Questions