Search code examples
rtidyrtidyevalr-glue

Passing variables into the names_glue parameter of tidyr::pivot_wider


Here's some silly data that we pivot wider, using two names:

library(tidyr)

df <- data.frame(
    food = c('banana','banana','banana','banana','cheese','cheese','cheese','cheese'),
    binary = c(rep(c('yes','no'), 4)),
    car = c('toyota','subaru','mazda','skoda','toyota','subaru','mazda','skoda'),
    fun = c(2,4,3,6,2,4,2,3))

df %>%
    pivot_wider(
        id_cols = food,
        names_from = c(car, binary),
        values_from = fun)

If we want to change the format of the new variable names, e.g., from toyota_yes to yes_toyota, we use the names_glue argument:

df %>%
    pivot_wider(
        id_cols = food,
        names_from = c(car, binary),
        names_glue = "{binary}_{car}",
        values_from = fun)

The issue I'm facing is finding the correct syntax to pass variable names to the names_glue parameter. It's easy to pass variables to names_from, e.g.:

var1 <- 'car'
var2 <- 'binary'
df %>%
    pivot_wider(
        id_cols = food,
        names_from = c(var1, var2),
        values_from = fun)

But we can't directly do that with names_glue:

df %>%
    pivot_wider(
        id_cols = food,
        names_from = c(var1, var2),
        names_glue = "{var1}_{var2}",
        values_from = fun)

Error: Column names car_binary, car_binary, and car_binary must not be duplicated.

Presumably it's evaluating the variable and just passing the resulting string (i.e., 'car' or 'binary') into the glue function. I have played around with some things I would normally use for tidy evaluation (!!sym(...), etc.) but haven't got anything to work. Desired output is the following, using variables for the names_glue parameter:

# A tibble: 2 x 5
  food   yes_toyota no_subaru yes_mazda no_skoda
  <fct>       <dbl>     <dbl>     <dbl>    <dbl>
1 banana          2         4         3        6
2 cheese          2         4         2        3

Here is the commit that added the names_glue parameter to pivot_wider -- although I can't really figure out how to troubleshoot with this.


Solution

  • You can use sprtinf/paste0 to construct the string :

    library(tidyr)
    df %>%
      pivot_wider(
        id_cols = food,
        names_from = c(var1, var2),
        names_glue = sprintf('{%s}_{%s}', var2, var1),
        values_from = fun)
    
    #  food   yes_toyota no_subaru yes_mazda no_skoda
    #  <chr>       <dbl>     <dbl>     <dbl>    <dbl>
    #1 banana          2         4         3        6
    #2 cheese          2         4         2        3