Skip to contents

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 serves as the gateway to create an initial qenv object:

library(teal.code)

# can be created without any code/environment
empty_qenv <- new_qenv()
print(empty_qenv)
## <environment: 0x5616a4aa92b0> [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: 0x5616a2fd7808> [L]
## Parent: <environment: package:teal.code>
## Bindings:
##  x: <dbl> [L]

For enhanced reproducibility, it’s crucial to provide the code used to generate objects when creating a qenv with objects inside the environment. This responsibility falls upon the user.

qenv basic usage

The eval_code() function executes code within a qenv environment, yielding a new qenv object as the output.

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: 0x5616a2fd7808> [L]
## Parent: <environment: package:teal.code>
## Bindings:
##  x: <dbl> [L]
# q2 contains x, y and z
print(q2)
## <environment: 0x5616a3964c78> [L]
## Parent: <environment: package:magrittr>
## Bindings:
##  x: <dbl> [L]
##  y: <dbl> [L]
##  z: <dbl> [L]

To extract objects from a qenv, use [[; this is particularly useful for displaying them in a shiny app. You can retrieve the code used to generate the qenv using the get_code() function.

print(q2[["y"]])
## [1] 10
cat(paste(get_code(q2), collapse = "\n"))
## x <- 5
## y <- x * 2
## z <- y * 2

Combining qenv objects

Given a pair of qenv objects, you may be able to “join” them, creating a new qenv object encompassing the union of both environments, along with the requisite code for reproduction:

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: 0x5616a4581680>
## Parent: <environment: package:magrittr>
## Bindings:
##  x: <dbl>
##  y: <dbl>
##  z: <dbl>

The feasibility of joining qenv objects hinges on the contents of the environments and the code’s order. Refer to the function documentation for further details..

Warnings and messages in qenv objects

In cases where warnings or messages arise while evaluating code within a qenv environment, these are captured and stored within the qenv object. Access these messages and warnings using the @ operator.

q_message <- eval_code(new_qenv(), quote(message("this is a message")))
q_message@messages
## [1] "> this is a message\n"
q_warning <- eval_code(new_qenv(), quote(warning("and this is a warning")))
q_warning@warnings
## [1] "> and this is a warning\n"

If a particular line of code doesn’t trigger any warnings or messages, the corresponding message/warning value will be an empty string.

q_message@warnings
## [1] ""
q_warning@messages
## [1] ""

Additionally, a helper function, get_warnings(), is available to generate a formatted string comprising the warnings and the code responsible for generating them. It returns NULL when no warnings are present.

Utilizing qenv inside shiny applications

These functions can be seamlessly integrated into shiny applications to produce reproducible outputs. In the example below, the rcode section showcases the code employed for generating the output.

When employing a qenv to evaluate code, should an error occur, an object of type qenv.error is generated. This object can be utilized wherever a qenv object is used, alleviating the need for code alterations to handle these errors. Select the error_option in the example below to witness 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 versatile qenv object can seamlessly integrate into teal modules. Explore the teal vignette Creating Custom Modules for detailed guidance.