Problem
Using targets
package in r
, we make functions and targets obejcts in _targets.R
file. In a function, I want to calculate something not just based on the input obejects but also based on the objects in the global environment. However, seems that it doesn't work in this way.
What I have done
I will give two example, showing how we write code without and with targets
package. The first one runs without problem, but the second code doesn't work due to the problem I mentioned above.
The first example. Let's start from a empty project folder. I make a new R script, and this is how we do generally without using targets
package.
# a function to sum 2 values then minus 1
fun_sum_1 <- function(x, y) {
res <- sum(x, y) - 1
return(res)
}
my_x <- 2
my_y <- 3
my_res <- fun_sum_1(my_x, my_y)
my_res
# [1] 4
Then I do almost the same thing using targets
package. Firstly, make a new R script and name it "_targets.R". Write the following code in this _targets.R
and save the file.
library(targets)
# a function to sum 2 values then minus 1
fun_sum_1 <- function(x, y) {
res <- sum(x, y) - 1
return(res)
}
# targets list
list(
tar_target(my_x, 2),
tar_target(my_y, 3),
tar_target(my_res, fun_sum_2(my_x, my_y))
)
Then we run the _targets.R
in console pannel with the following code.
library(targets)
tar_make()
You will see the progress of the runing. The difference between this and general practice above is that there is not "my_x" or "my_y" or "my_res" or "fun_sum_1" showing up in the environment pannel. Then we load the results to our global environment by runing the following code in the console pannel.
tar_load(my_res)
my_res
# [1] 4
And if we run tar_visnetwork()
, we can see a flowchart of the target obejcts.
Then we go to the second example, the example with problem. First, we write code as usual.
# clean the global environment first
rm(list = ls())
# a function to sum 2 values and 1 existing value of global environment then minus 1
# it differs from fun_sum_2 that it doesn't only rely on input obejects
# but also the "my_z" in the global environment
fun_sum_2 <- function(x, y) {
res <- sum(x, y, my_z) - 1
return(res)
}
my_x <- 2
my_y <- 3
my_z <- 4
my_res <- fun_sum_2(my_x, my_y)
my_res
# [1] 8
Now we try to make this using targets
package. We revise the _targets.R
into the code below, and save the file.
library(targets)
# a function to sum 2 values then minus 1
fun_sum_2 <- function(x, y) {
res <- sum(x, y, my_z) - 1
return(res)
}
# targets list
list(
tar_target(my_x, 2),
tar_target(my_y, 3),
tar_target(my_z, 4),
tar_target(my_res, fun_sum_2(my_x, my_y))
)
Then we run the following code in console pannel. But then error happens.
library(targets)
tar_make()
# ✔ skip target my_x
# ✔ skip target my_y
# ✔ skip target my_z
# • start target my_res
# ✖ error target my_res
# • end pipeline [0.095 seconds]
# Error:
# ! Error running targets::tar_make()
# Error messages: targets::tar_meta(fields = error, complete_only = TRUE)
# Debugging guide: https://books.ropensci.org/targets/debugging.html
# How to ask for help: https://books.ropensci.org/targets/help.html
# Last error: object 'my_z' not found
Though I make a my_z
in the targets list, but seems that fun_sum_2
can't read it. Of course, I can make my_z
an input into the fun_sum_2
function, which will solve the problem. However, what if I have a function relying on many objects in the global environment?
I wonder how can I solve this problem without making my_z
one of the inputs for the fun_sum_2
function.