Search code examples
rdplyrrlangr-highchartertidyeval

Problem programming with dplyr--column which is definitely a vector being picked up as a formula


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"))

Solution

  • {{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