rdplyrstringrtidyselect

Using tidyselect in a function with mutate and


I have data like this:

(test <- tribble(
  ~case, ~A.1_recipient, ~A.2_recipient, ~A.1_donor, ~A.2_donor,
  1, "HLA-A2", "HLA-A3", "HLA-A2", "HLA-A68",
  2, "A2", "HLA-A3", "A3", "A69",
  3, "A11", "A24", "HLA-A2", NA,
  4, "A66", NA, "A2", "A24"
  ))

I often use code to remove prefixes from the values:

(test_code <- test
  %>% mutate(A.1_recipient = str_replace(A.1_recipient, "HLA-", ""))
)

I also use tidyselect to apply the function to multiple columns:

(test_code <- test
  %>% mutate(across(A.1_recipient:A.2_donor, ~str_replace(., "HLA-", "")))
)

(test_code <- test
  %>% mutate(across(ends_with("recipient"), ~str_replace(., "HLA-", "")))
)

I would like to develop this into a function that would deal with either a single column input or tidyselect. Using this link (https://cran.r-project.org/web/packages/tidyselect/vignettes/tidyselect.html) I have tried the following function:

HLA_prefix_remove <- function(.data, ...) {
    # Remove any HLA and locus prefixes from typing results.
  expr <- rlang::expr(c(...))
  pos <- eval_select(expr, data = .data)
  .data <- .data %>% 
  mutate(.data[pos], ~str_replace(pos, "HLA-", "")) 
}

Which I try to run with the following code:

(test_function <- test
  %>% HLA_prefix_remove(A.1_recipient)
  )

However, I get the following error:

Error in `mutate()`:
! Problem while computing `..1 = .data[pos]`.
Caused by error in `.data[pos]`:
! `[` is not supported by the `.data` pronoun, use `[[` or $
  instead.
Backtrace:
  1. test %>% HLA_prefix_remove(A.1_recipient)
 10. rlang:::`[.rlang_data_pronoun`(.data, pos)
 Error in mutate(., .data[pos], ~str_replace(pos, "HLA-", "")) : 
Caused by error in `.data[pos]`:
! `[` is not supported by the `.data` pronoun, use `[[` or $
 instead.

Not sure how to write the function to properly pass the arguments through?


Solution

  • Use c(...) like this:

    library(dplyr)
    library(stringr)
    
    HLA_prefix_remove2 <- function(.data, ...) {
      .data %>% mutate(across(c(...), ~str_replace(., "HLA-", "")))
    }
    
    HLA_prefix_remove2(test, A.1_recipient:A.2_donor)
    HLA_prefix_remove2(test, ends_with("recipient"))
    HLA_prefix_remove2(test, c(A.1_recipient, A.2_recipient))
    HLA_prefix_remove2(test, A.1_recipient, A.2_recipient)
    

    If having a single second argument is ok then this would also work:

    HLA_prefix_remove3 <- function(.data, sel) {
      .data %>% mutate(across({{sel}}, ~str_replace(., "HLA-", "")))
    }
    
    HLA_prefix_remove3(test, A.1_recipient:A.2_donor)
    HLA_prefix_remove3(test, ends_with("recipient"))
    HLA_prefix_remove3(test, c(A.1_recipient, A.2_recipient))