Search code examples
tidyeval

How to do a fct_drop within a function (using tidy eval)?


Using the diamonds dataset...

Trying to create a function that will allow me to plot either cut or color on the x-axis...

...but first I want to filter the selected column to show only a certain number of levels.

I've got the filter working but the levels are still present... and they will show up in the chart. I need to do a fct_drop() on the selected column

Please see the code below for a reproducible example:

library(tidyverse)

diamonds <- diamonds %>% 
    mutate(cut = factor(cut),
         color = factor(color))

reduce_for_plot <- function(data, column, how_many_levels) {

  column2 <- enquo(column)
  of_interest <- unique(data[[deparse(substitute(column))]])[1:how_many_levels]

  data %>%
    filter(!! column2 %in% of_interest)

  # here is where I then do some kind of mutate... to fct_drop the selected column  

  # this line seems to work
  # value_to_put_in <- fct_drop(data[[deparse(substitute(column))]])

  # but this line doesn't  
  # data <- data %>% 
    # mutate(!! column = value_to_put_in)
}

diamonds %>% 
  reduce_for_plot(color, 1)

Solution

  • You were almost there! The problem in your code is that R doesn't allow ! on the LHS of =. So you need to use the fake operator := instead.

    reduce_for_plot <- function(data, column, how_many_levels) {
      col_expr <- enquo(column)
      col_name <- rlang::as_name(col_expr)
    
      of_interest <- unique(data[[col_name]])[1:how_many_levels]
    
      data <- data %>%
        filter(!!col_expr %in% of_interest)
    
      value_to_put_in <- fct_drop(data[[col_name]][of_interest])
    
      data %>%
        mutate(!!col_name := value_to_put_in)
    }
    

    As you can see I have replaced all deparse(substitute(column)) by as_name(enquo(column)). However you can avoid these entirely by doing the computations in data context, which I think yields nicer code:

    reduce_for_plot <- function(data, column, how_many_levels) {
      column <- enquo(column)
    
      data %>%
        filter(!!column %in% unique(!!column)[1:how_many_levels]) %>%
        mutate(!!column := fct_drop(!!column))
    }