Wrapping a function around another function

It made sense to me that this should work, but it doesn't seeem...

I can I create a wrapper function that is able to have its own defaults, but draw on a base function??

Any help super appreciated

library(palmerpenguins)
library(tidyverse)

plot_base <- function(data, x, y)  {
  x <- enquo(x)
  y <- enquo(y)
  
  penguins |> 
    ggplot() +
    geom_point(aes(!!x, !!y))
}

plot_wrap <- function(data, x, y) {
  
  plot_base(data = data, 
            x = x, 
            y = y)
}

plot_wrap(penguins, body_mass_g, species)
#> Error in `geom_point()`:
#> ! Problem while computing aesthetics.
#> ℹ Error occurred in the 1st layer.
#> Caused by error:
#> ! object 'body_mass_g' not found
#> Backtrace:
#>      ▆
#>   1. ├─base::tryCatch(...)
#>   2. │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#>   3. │   ├─base (local) tryCatchOne(...)
#>   4. │   │ └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#>   5. │   └─base (local) tryCatchList(expr, names[-nh], parentenv, handlers[-nh])
#>   6. │     └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#>   7. │       └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#>   8. ├─base::withCallingHandlers(...)
#>   9. ├─base::saveRDS(...)
#>  10. ├─base::do.call(...)
#>  11. ├─base (local) `<fn>`(...)
#>  12. ├─global `<fn>`(input = base::quote("peppy-flea_reprex.R"))
#>  13. │ └─rmarkdown::render(input, quiet = TRUE, envir = globalenv(), encoding = "UTF-8")
#>  14. │   └─knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
#>  15. │     └─knitr:::process_file(text, output)
#>  16. │       ├─knitr:::handle_error(...)
#>  17. │       │ └─base::withCallingHandlers(...)
#>  18. │       ├─base::withCallingHandlers(...)
#>  19. │       ├─knitr:::process_group(group)
#>  20. │       └─knitr:::process_group.block(group)
#>  21. │         └─knitr:::call_block(x)
#>  22. │           └─knitr:::block_exec(params)
#>  23. │             └─knitr:::eng_r(options)
#>  24. │               ├─knitr:::in_input_dir(...)
#>  25. │               │ └─knitr:::in_dir(input_dir(), expr)
#>  26. │               └─knitr (local) evaluate(...)
#>  27. │                 └─evaluate::evaluate(...)
#>  28. │                   └─evaluate:::evaluate_call(...)
#>  29. │                     ├─evaluate (local) handle(...)
#>  30. │                     │ └─base::try(f, silent = TRUE)
#>  31. │                     │   └─base::tryCatch(...)
#>  32. │                     │     └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#>  33. │                     │       └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#>  34. │                     │         └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#>  35. │                     ├─base::withCallingHandlers(...)
#>  36. │                     ├─base::withVisible(value_fun(ev$value, ev$visible))
#>  37. │                     └─knitr (local) value_fun(ev$value, ev$visible)
#>  38. │                       └─knitr (local) fun(x, options = options)
#>  39. │                         ├─base::withVisible(knit_print(x, ...))
#>  40. │                         ├─knitr::knit_print(x, ...)
#>  41. │                         └─knitr:::knit_print.default(x, ...)
#>  42. │                           └─evaluate (local) normal_print(x)
#>  43. │                             ├─base::print(x)
#>  44. │                             └─ggplot2:::print.ggplot(x)
#>  45. │                               ├─ggplot2::ggplot_build(x)
#>  46. │                               └─ggplot2:::ggplot_build.ggplot(x)
#>  47. │                                 └─ggplot2:::by_layer(...)
#>  48. │                                   ├─rlang::try_fetch(...)
#>  49. │                                   │ ├─base::tryCatch(...)
#>  50. │                                   │ │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
#>  51. │                                   │ │   └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
#>  52. │                                   │ │     └─base (local) doTryCatch(return(expr), name, parentenv, handler)
#>  53. │                                   │ └─base::withCallingHandlers(...)
#>  54. │                                   └─ggplot2 (local) f(l = layers[[i]], d = data[[i]])
#>  55. │                                     └─l$compute_aesthetics(d, plot)
#>  56. │                                       └─ggplot2 (local) compute_aesthetics(..., self = self)
#>  57. │                                         └─base::lapply(aesthetics, eval_tidy, data = data, env = env)
#>  58. │                                           └─rlang (local) FUN(X[[i]], ...)
#>  59. └─base::.handleSimpleError(...)
#>  60.   └─rlang (local) h(simpleError(msg, call))
#>  61.     └─handlers[[1L]](cnd)
#>  62.       └─cli::cli_abort(...)
#>  63.         └─rlang::abort(...)

Created on 2023-12-06 with reprex v2.0.2

This seems to work.

library(palmerpenguins)
library(tidyverse)
plot_base <- function(data, x, y)  {
  
  penguins |> 
    ggplot() +
    geom_point(aes({{x}}, {{y}}))
}

plot_wrap <- function(data, x, y) {
  
  plot_base(data = data, 
            x = {{x}}, 
            y = {{y}})
}

plot_wrap(penguins, body_mass_g, species)
#> Warning: Removed 2 rows containing missing values (`geom_point()`).

Created on 2023-12-06 with reprex v2.0.2

1 Like

Thanks @FJCC that seems to be the solution!

Can't quite get my head around why it requires the braces, but oh well..

The double braces are the embrace-operator that combines enquo and !! in one step. See the help in the rlang package for ?`embrace-operator`.
The following code also works.

library(palmerpenguins)
library(tidyverse)
plot_base <- function(data, x, y)  {
  x <- enquo(x)
  y <- enquo(y)
  penguins |> 
    ggplot() +
    geom_point(aes(!!x, !!y))
}

plot_wrap <- function(data, x, y) {
  x <- enquo(x)
  y <- enquo(y)
  plot_base(data = data, 
            x = !!x, 
            y = !!y)
}

plot_wrap(penguins, body_mass_g, species)
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.