biomiha
biomiha

Reputation: 1422

Arranging ggplot legend by groups

Is there a way of arranging the ggplot legend by groups?

If I try:

library(tidyverse)
mtcars_tbl <- mtcars %>% 
  rownames_to_column(var = "make_model") %>%
  as_tibble %>% 
  mutate(point_col = case_when(cyl == 4 ~ "#009E73",
                               cyl == 6 ~ "#0072B2",
                               cyl == 8 ~ "#D55E00"))
cols_tbl <- mtcars_tbl %>% 
  select(make_model, point_col) %>% 
  deframe

mtcars_tbl %>%
  ggplot(aes(x = hp, y = qsec, col = make_model)) +
  geom_point() +
  scale_colour_manual(values = cols_tbl) +
  theme(legend.position = "bottom")

The make_model comes out arranged alphabetically. I can specify the number of rows or columns or even change make_model to factor but what I'd like is the way they are arranged in the picture below (importantly I want to have an uneven number of items).

enter image description here

Upvotes: 1

Views: 1107

Answers (1)

stefan
stefan

Reputation: 124148

One option to achieve your desired result would be to make use of the ggnewscale package which allows for multiple color scales. One drawback of this approach is that it requires plotting your data via multiple geom layers too. In my approach below I first split the data as well as the color vectors by groups. To get the order of the groups right it's best make use of the order argument of guide_legend. Additionally I make use of the title.theme argument to "remove" the duplicated legend titles. Finally I use theme options to align the guides vertically and to the left.

library(tidyverse)
library(ggnewscale)

mtcars_tbl <- mtcars %>% 
  rownames_to_column(var = "make_model") %>%
  as_tibble %>% 
  mutate(point_col = case_when(cyl == 4 ~ "#009E73",
                               cyl == 6 ~ "#0072B2",
                               cyl == 8 ~ "#D55E00"))
cols_tbl <- mtcars_tbl %>% 
  select(make_model, point_col) %>% 
  deframe()

mtcars_tbl <- split(mtcars_tbl, mtcars_tbl$cyl)
cols_tbl <- lapply(mtcars_tbl, function(x) x %>% select(make_model, point_col) %>% deframe())

ggplot(mapping = aes(x = hp, y = qsec)) +
  geom_point(data = mtcars_tbl$`4`, aes(col = make_model)) +
  scale_colour_manual(values = cols_tbl$`4`, 
                      guide = guide_legend(order = 1, title.theme = element_text(color = NA))) +
  new_scale_color() +
  geom_point(data = mtcars_tbl$`6`, aes(col = make_model)) +
  scale_colour_manual(values = cols_tbl$`6`,
                      guide = guide_legend(order = 2, title.theme = element_text(color = "black"))) +
  new_scale_color()+
  geom_point(data = mtcars_tbl$`8`, aes(col = make_model)) +
  scale_colour_manual(values = cols_tbl$`8`,
                      guide = guide_legend(order = 3, title.theme = element_text(color = NA))) +
  theme(legend.position = "bottom", 
        legend.box = "vertical",
        legend.box.just = "left")

Upvotes: 1

Related Questions