Lukas D. Sauer
Lukas D. Sauer

Reputation: 513

Using tidy selection together with the survival package - "Error: promise already under evaluation"

I am writing an R function that allows the user to specify an individual time variable when creating a survival::survfit object. The survival package has a "string-free" syntax, which means that the name of the time variable (in my case "dtime") does not need any quotation marks:

survival::survfit(formula = survival::Surv(dtime, death) ~ 1, rotterdam)

Hence, I figured that I could use tidy evaluation for my purpose. Here is my code:

# My function
get_survfit <- function(.data, .time){
  return(survival::survfit(formula = survival::Surv({{ .time }}, status) ~ 1, .data))
}

# Application example
library(survival)
data(cancer)
rotterdam
colnames(rotterdam)[which(names(rotterdam) == "death")] = "status"
get_survfit(.data=rotterdam, .time=dtime)

However, I always get the following errors:

Error in in survival::Surv({ : object 'dtime' not found

and when looking into 'dtime' in the debugger, I get:

Error during wrapup : promise already under evaluation: recursive default argument reference or earlier problems?

How can I fix this and still obtain my feature?

Upvotes: 1

Views: 112

Answers (2)

Lukas D. Sauer
Lukas D. Sauer

Reputation: 513

Building on Lionel Henry's answer and inspired by another question I asked, I would like to add that it is also possible to achieve the same result with enquo and get_expr:

get_survfit <- function(.data, .time){
  .time = rlang::enquo(.time)
  .time = rlang::get_expr(.time)
  
  rlang::inject(
    return(survival::survfit(formula = survival::Surv(!!.time, status) ~ 1, .data))
  )
}

Upvotes: 0

Lionel Henry
Lionel Henry

Reputation: 6803

survfit() is not a tidy eval function so you're using {{ out of context. See https://rlang.r-lib.org/reference/topic-inject-out-of-context.html.

Instead you'll need to use inject() to enable injection from the outside. Since survfit() is not a tidy eval function it won't support quosures, which {{ creates. So you'll need to use !! instead, together with ensym().

get_survfit <- function(data, time) {
  time <- ensym(time)

  inject(
    survival::survfit(formula = survival::Surv(!!time, status) ~ 1, data)
  )
}

ensym() ensures that simple variable names are passed, and defuses them. !! injects the variable in the formula.

Upvotes: 1

Related Questions