pheymanss
pheymanss

Reputation: 152

Passing column names as dot-dot-dot for non-standard evaluation on qplot()

I thought of a lovely use case for map + ... for a purrr workshop: splitting a data.frame into a list of data.frames and then plot them individually through a qplot(...) call.

groups_of_plots <- function(data, group, ...){
  table_list <- split(data, data[[group]])

  plots <- purrr::map(.x = table_list, 
                      .f = ~ggplot2::qplot(data = .x, ...))
  return(plots)
}

But when I call the function as I normally would with a direct call, I get this error, which seems to be an issue with non-standard evaluation of x as an aesthetic parameter for qplot (making it a fixed parameter in the function definition makes it work, but of course renders the function basically useless)

groups_of_plots(data = iris, 
                group = 'Species', 
                x = Sepal.Length)

error/rlang_error>
    Unknown input: data.frame
Backtrace:
    1. (function (x, ...) ...
    2. ggplot2:::print.ggplot(x)
    4. ggplot2:::ggplot_build.ggplot(x)
    5. ggplot2:::by_layer(function(l, d) l$compute_aesthetics(d, plot))
    6. ggplot2:::f(l = layers[[i]], d = data[[i]])
    7. l$compute_aesthetics(d, plot)
    8. ggplot2:::f(..., self = self)
    9. ggplot2:::is_calculated_aes(aesthetics)
    10. base::vapply(aesthetics, is_calculated, logical(1), USE.NAMES = FALSE)
    11. ggplot2:::FUN(X[[i]], ...)  

I really want to stick to qplot, not only for simplicity but also because in my opinion it is a very good example of an instance where you do not want to nor can specify all possible parameters explicitly in your function definition, but as far as I can tell it only supports passing the aesthetic as non-standard evaluation and this is complicating things quite a bit.

Upvotes: 2

Views: 59

Answers (1)

MrFlick
MrFlick

Reputation: 206401

The problem is that the ~ shortcut for functions with map repurposes the ... symbols which interferes with parameter placement. A possible work around is

groups_of_plots <- function(data, group, ...){
  table_list <- split(data, data[[group]])
    
  plots <- purrr::map(.x = table_list, 
                      .f = function(.x, ...) ggplot2::qplot(data = .x, ...), ...)
  return(plots)
}

Here we create the function that has the ... values and we pass them along to the inner function, and we also have to pass them along to the map() function as well so they can be passed through to the inner function.

Upvotes: 2

Related Questions