Search code examples
rdplyrpipemutate

Reference the current state of a piped object in R pipe subfunction


I want to convert a column into a factor, and order the levels based on a different column. This works fine if I'm using the original object for the levels, e.g. below, the input object (iris) is unchanged at the point of the factor operation, so I can just reference the environment-level iris and not the current pipe state:

iris |> 
  mutate(Species = factor(Species,
                          levels = iris |>
                            arrange(Petal.Width) |>
                            pull(Species) |>
                            unique())) |> 
  moreOperations |> 
  ggplot +

BUT, if I modify the input object (e.g. filter), I then want to reference that object in the factor, not top-level iris. I've tried ., .data, and embracing the relevant code block {iris ... unique())}, but none work. Is there a solution for what ?iris? should be in the example below? Thanks!

iris |> 
      filter(Species %in% c("setosa", "versicolor")) |>
      mutate(Species = factor(Species,
                              levels = ?iris? |>
                                arrange(Petal.Width) |>
                                pull(Species) |>
                                unique())) |>

This solution proposes:

iris |>
  filter(Species %in% c("setosa", "versicolor")) |>
  {. ->> tmp} |> 
  mutate(Species = factor(Species,
                          levels = tmp |>
                            arrange(Petal.Width) |>
                            pull(Species) |>
                            unique()))

But returns

Error in {: function '{' not supported in RHS call of a pipe (:3:3)


Solution

  • You could use cur_data from dplyr:

    library(dplyr)
    
    iris |>
      filter(Species %in% c("setosa", "versicolor")) |>
      mutate(Species = factor(Species,
                              levels = cur_data() |>
                                arrange(Petal.Width) |>
                                pull(Species) |>
                            unique()))
    

    Or even an anonymous function

    iris |>
      filter(Species %in% c("setosa", "versicolor")) |>
      (\(x) mutate(x, Species = factor(Species,
                                       levels = x |>
                                         arrange(Petal.Width) |>
                                         pull(Species) |>
                                         unique())))()
    

    This solution uses magrittr pipes (%>%), which works fine. The base R pipe |> doesn't support the { syntax.

    iris %>% 
      filter(Species %in% c("setosa", "versicolor")) %>% 
      {. ->> tmp} %>%
      mutate(Species = factor(Species, 
                              levels = tmp %>%
                                arrange(Petal.Width) %>%
                                pull(Species) %>%
                                unique()))