5

I'm writing a function to reproduce several charts that will all have similar formatting (and other stuff) using highcharter. I want to be able select different columns of the data set should the names change or if I want to be doing something different and I'm embracing those arguments with {{ }}. But then I get this weird error:

Error: Problem with `mutate()` input `x`.
x Input `x` must be a vector, not a `formula` object.
i Input `x` is `~Year`.

Here's my (minimal reproducible) code:

library(dplyr)
library(highcharter)

plot_high_chart <- function(.data,
                            chart_type = "column",
                            x_value = Year,
                            y_value = total,
                            group_value = service) {
  .data %>% 
  hchart(chart_type, hcaes(x = {{x_value}}, y = {{y_value}}, group = {{group_value}}))
}

data %>% plot_high_chart()

and here's the dput result for the data:

structure(list(Year = c(2016, 2017, 2017, 2018, 2018, 2018), 
    service = structure(c(10L, 3L, 9L, 5L, 7L, 9L), .Label = c("Defense Logistics Agency", 
    "Chemical and Biological Defense Program", "Defense Information Systems Agency", 
    "United States Special Operations Command", "Office of the Secretary Of Defense", 
    "Missile Defense Agency", "Defense Advanced Research Projects Agency", 
    "Navy", "Army", "Air Force"), class = "factor"), total = c(9.435, 
    0, 10.442, 9.969, 73.759, 8.855)), row.names = c(NA, -6L), groups = structure(list(
    Year = c(2016, 2017, 2018), .rows = structure(list(1L, 2:3, 
        4:6), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), row.names = c(NA, 3L), class = c("tbl_df", 
"tbl", "data.frame"), .drop = TRUE), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"))
Artem Sokolov
  • 13,196
  • 4
  • 43
  • 74
Ben G
  • 4,148
  • 2
  • 22
  • 42

1 Answers1

3

{{a}} is shorthand for !!enquo(a), which captures the expression provided to a as well as the context where this expression should be evaluated. In your case, the context is the data frame, which is already being provided to the function. So, a better rlang verb to use here is ensym(a), which captures the symbol name provided to a instead:

plot_high_chart <- function(.data,
                            chart_type = "column",
                            x_value = "Year",             # <-- Note: strings
                            y_value = "total",            
                            group_value = "service") {
  .data %>%
      hchart(chart_type, hcaes(x = !!rlang::ensym(x_value),    # <- ensym instead of {{
                               y = !!rlang::ensym(y_value),
                               group = !!rlang::ensym(group_value)))
}

As a bonus, the function will now work with symbols AND with strings:

data %>%
   plot_high_chart(x_value= "Year", y_value= "total", group_value= "service")    # Works
data %>% 
   plot_high_chart(x_value= Year, y_value= total, group_value= service)     # Also Works
Artem Sokolov
  • 13,196
  • 4
  • 43
  • 74
  • Perfect, thanks. As you can see here (https://stackoverflow.com/questions/57960245/what-is-the-difference-between-ensym-and-enquo-when-programming-with-dplyr) I've been tripped up by enquo/ensym differences in the past. Still don't really understand why enquo didn't work here. – Ben G Oct 16 '20 at 18:17
  • @BenG Some of it depends on how `hcaes` handles its arguments. `quo()` and `enquo()` return objects that can be interpreted as formulas (e.g., try `class(rlang::quo(x))` to convince yourself). It's possible that `hcaes` is getting hung up on the `formula` class? – Artem Sokolov Oct 16 '20 at 18:45
  • BUT ... why would it be interpreted as a formula? – Ben G Oct 16 '20 at 20:22
  • @BenG: Because [here](https://github.com/jbkunst/highcharter/blob/d47a7792577588d0891dfd87a14a60914371e8c3/R/highcharts-api-add.R#L412) the mapping produced by `hcaes` gets converted to character. Try doing `as.character(hcaes( !!quo(x), !!quo(y) ))` and then `as.character(hcaes( !!sym("x"), !!sym("y") ))` to see the difference. I think quosures internally store expressions as formulas, which is why casting them to character leads to `~x` instead of `x`. – Artem Sokolov Oct 16 '20 at 22:01
  • That makes sense. Thanks – Ben G Oct 17 '20 at 23:18
  • I think `{{` should ideally work. Perhaps worth filing a bug report with hchart? – Lionel Henry Oct 19 '20 at 06:41
  • 1
    @LionelHenry https://github.com/jbkunst/highcharter/issues/681 – Artem Sokolov Oct 19 '20 at 15:58
  • 1
    @ArtemSokolov Thanks so much for this. Embracing works with highchartr `data_to_boxplot` so I'd thought it was reasonable for it to work with `hcaes` as well. Seems that hchart still hasn't addressed this six months later. – bcarothers Apr 29 '21 at 17:07