2

Consider this example. I want to create a custom label for my panels by joining two columns into a string.

The panels created through faceting are ordered alphabetically, but actually, I want them to be ordered by src, so SRC01 should come first, then SRC02, etc.

library(tidyverse)

tibble::tibble(
  src = rep(c("SRC03", "SRC04", "SRC01", "SRC02"), 2),
  data = runif(8)
) %>% 
  mutate(
    foo = case_when(src %in% c("SRC01", "SRC02") ~ "foo", TRUE ~ "bar"),
    label = paste(foo, src)
  ) %>% 
  ggplot(aes(x = data)) +
  geom_density() +
  facet_wrap(~label)

Created on 2019-05-22 by the reprex package (v0.3.0)

I know that this order depends on the order of underlying factor levels, but this question shows how to manually specify the levels, which I do not want (there are many more SRC values and I don't want to type all of them…).

I found a solution using fct_reorder, in which I could specify:

mutate(label = fct_reorder(label, src, .fun = identity))

But this only works when there is one line per src/label combination. If I add data (i.e., more than one data point per combination), it fails with:

Error: `fun` must return a single value per group

What would be the most succinct way to achieve what I need?

slhck
  • 36,575
  • 28
  • 148
  • 201

1 Answers1

2

You can use the numeric part of src, and then use reorder():

tibble::tibble(
  src = rep(c("SRC03", "SRC04", "SRC01", "SRC02"), 2),
  data = runif(8)
) %>% 
  mutate(
    foo = case_when(src %in% c("SRC01", "SRC02") ~ "foo", TRUE ~ "bar"),
    label = paste(foo, src)
  ) %>% 
  mutate(label_order = as.numeric(str_extract(src, "\\d+"))) %>% 
# use str_extract() to find the "01" inside "SRC01", turn it to numeric.
  ggplot(aes(x = data)) +
  geom_density() +
  facet_wrap(~reorder(label, label_order)) 
# user reorder to change the ordering based on the numbers

enter image description here


A note about str_extract(), it works on your example because:

str_extract("SRC01", "\\d+") gives "01", then transformed to 1. But:

str_extract("2SRC01", "\\d+") would return 2, which wouldn't be ideal possibly.

Luckly there are tons of way to use regex to extract what you may need.

RLave
  • 8,144
  • 3
  • 21
  • 37
  • That works, thanks! Do you think though that a solution working with the natural alphanumeric order of `src` values is possible? Ideally I'd like to have `label` already be a factor that is correctly ordered and not resort to `reorder` in the plot. – slhck May 22 '19 at 09:59
  • `reorder` could be added inside `mutate`, like: `.. %>% mutate(label = reorder(label, label_order)) %>%.. ` – RLave May 22 '19 at 10:12