`qenv`
NEST coreDev
2022-11-03
qenv.Rmd
Introduction to qenv
A qenv
is an R object which contains code and an
environment and can be used to create reproducible outputs.
Initialization
The new_qenv()
function is used to create an initial
qenv
object:
library(teal.code)
# can be created without any code/environment
empty_qenv <- new_qenv()
print(empty_qenv)
## <environment: 0x55ffbef76340> [L]
## Parent: <environment: package:teal.code>
# or can be created with objects inside the environment
my_qenv <- new_qenv(env = list2env(list(x = 5)), code = "x <- 5")
print(my_qenv)
## <environment: 0x55ffb959c0d0> [L]
## Parent: <environment: package:teal.code>
## Bindings:
## • x: <dbl> [L]
If the qenv
is created with objects inside the
environment then to ensure reproducibility the code used to generate
those objects should be provided. It is the users responsibility to
ensure this is the case.
qenv
basic usage
The eval_code()
function can be used to run code inside
a qenv
environment returning a new qenv
object.
library(magrittr)
q2 <- eval_code(my_qenv, "y <- x * 2") %>% eval_code("z <- y * 2")
# my_qenv still contains only x
print(my_qenv)
## <environment: 0x55ffb959c0d0> [L]
## Parent: <environment: package:teal.code>
## Bindings:
## • x: <dbl> [L]
# q2 contains x, y and z
print(q2)
## <environment: 0x55ffbd99f9b8> [L]
## Parent: <environment: package:magrittr>
## Bindings:
## • x: <dbl> [L]
## • y: <dbl> [L]
## • z: <dbl> [L]
Objects can be extracted from a qenv
using
[[
for example in order for them to be displayed in a shiny
app. The code used to generate the qenv
is obtained using
the get_code()
function.
print(q2[["y"]])
## [1] 10
## x <- 5
## y <- x * 2
## z <- y * 2
Joining qenv
objects
Given a pair of qenv
objects it might be possible to
“join” them together creating a new qenv
object containing
the union of both environments together with the code needed to
reproduce it:
common_q <- eval_code(new_qenv(), quote(x <- 1))
x_q <- eval_code(common_q, quote(y <- 5))
y_q <- eval_code(common_q, quote(z <- 5))
join_q <- join(x_q, y_q)
print(join_q)
## <environment: 0x55ffbe3891c8>
## Parent: <environment: package:magrittr>
## Bindings:
## • x: <dbl>
## • y: <dbl>
## • z: <dbl>
Dependent on the contents of the environments and order of code it
may not be possible to join qenv
objects. See the function
documentation for more details.
Warnings and messages in qenv
objects
If warnings or messages are thrown when evaluating code in a
qenv
environment, they are captured and stored in the
qenv
object. These messages and warnings can be accessed
with the @
operator.
## [1] "> this is a message\n"
## [1] "> and this is a warning\n"
If no warning or message occurs on a particular line of code, the corresponding message/warning value will be an empty string.
q_message@warnings
## [1] ""
q_warning@messages
## [1] ""
A helper function get_warnings()
is also available to
produce a formatted string containing the warnings and the code used to
produce them - it returns NULL when there are no warnings.
Using qenv
inside shiny
applications
The functions above can be combined into a shiny
application generating reproducible outputs. In the example below the
rcode
is used to show the code used to generate the output.
When using a qenv
to evaluate code, if an error occurs then
an object of type qenv.error
is created. This object can be
used in all the same places a qenv
object is used and means
you do not need to change your code to handle these errors - select
error_option
in the example below to see qenv
error handling in action.
library(shiny)
library(magrittr)
# create an initial qenv with the data in
data_q <- new_qenv() %>% eval_code("iris_data <- iris")
ui <- fluidPage(
radioButtons(
"option", "Choose a column to plot:",
c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "error_option")
),
verbatimTextOutput("rcode"),
plotOutput("plot")
)
server <- function(input, output, session) {
# create a qenv containing the reproducible output
output_q <- reactive({
req(input$option)
eval_code(
data_q,
bquote(p <- hist(iris_data[, .(input$option)]))
)
})
# display output
output$plot <- renderPlot(output_q()[["p"]])
# display code
output$rcode <- renderText(get_code(output_q()))
}
if (interactive()) {
shinyApp(ui, server)
}
qenv
and teal
applications
The qenv
object can easily be incorporated into
teal
modules. See the teal
vignette Creating
Custom Modules for further details.