'Data objects not found in embedded vegan:cca. Scoping issue?

I try to embed cca (and also capscale) from package vegan (version 2.5-7, R 4.1.2) in another function to test an analysis pipeline with some data transformation and then varying model formulas. The used data matrices (e.g. bio and env) can have different names and are normally not visible in the global work space. The error that I get is:

Error in eval(match.call()$data, environment(formula), enclos = .GlobalEnv) : 
object 'env' not found

that looks like a scoping issue. Looking around, it seems that vegan had some problems with scoping in the past that are said to be fixed, so I wonder if I overlooked something. Any workaround is also welcome, e.g. environment manipulation.

library("vegan")

## create some example data
set.seed(123)
bio <- matrix(sample(0:10, 50, replace = TRUE), nrow = 10)
env <- data.frame(
  x = sample(1:10, 10),
  y = 1:10 + rnorm(10),
  z = rnorm(10)
)
cca(bio ~ x + y, data = env) # works

## enclose cca with some other stuff in a function
foo <- function(model, bio, env) {
  ## do preparatory data transformation
  fm <- cca(model, data = env)
  print(fm)
  ## do something else
}

model <- formula(bio ~ x + y) # works
foo(model, bio=bio, env=env)

## now rename data to test scoping
bio2 <- bio
env2 <- env
rm(bio, env)

foo(model, bio = bio2, env = env2) # error
# Error in eval(match.call()$data, environment(formula), enclos = .GlobalEnv) :
# object 'env' not found


Solution 1:[1]

Yes, looks to be a scoping issue. I think the key is to update the formula's environment inside the function:

foo <- function(model, bio, env) {
  # update model environment
  environment(model) = environment()
  ## do preparatory data transformation
  fm <- cca(model, data = env)
  print(fm)
  ## do something else
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Marc in the box