Skip to content

Conversation

@chlebowa
Copy link
Owner

@chlebowa chlebowa commented Apr 19, 2024

Allows app developers to pass card functions to modules as arguments.

Demonstration

Example app demonstrating use of locally defined card function:

example app
rm(list = ls())

library(teal)
devtools::load_all("./teal.modules.general")
library(teal.widgets)

local_card_function <- function(comment, label) {
  card <- teal::report_card_template(
    title = "Distribution Plot",
    label = label,
    with_filter = FALSE,
    filter_panel_api = filter_panel_api
  )
  card$append_text("Dummy Card", "header2")
  card$append_text(paste(
    "This report card was generated by a card function",
    "defined in the global environment."
  ))
  if (!comment == "") {
    card$append_text("Comment", "header3")
    card$append_text(comment)
  }
  card
}

data <- teal_data() |> within({
  iris <- iris
  mtcars <- mtcars
  faithful <- faithful
})
datanames(data) <- c("iris", "mtcars", "faithful")
filter <- teal_slices(
  teal_slice("iris", "Petal.Length", selected = c(1, 5.1)),
  teal_slice("iris", "Species", selected = c("setosa", "virginica")),
  teal_slice("mtcars", "cyl", selected = 6L),
  teal_slice("faithful", "waiting", selected = c(76, 82)),
  module_specific = TRUE,
  mapping = list(
    # "Distribution Module" = "iris Petal.Length",
    "Example" = "faithful waiting",
    "global_filters" = "iris Species"
  )
)
app <- init(
  data = data,
  modules = modules(
    tm_g_distribution(
      label = "Default card function",
      dist_var = data_extract_spec(
        dataname = "iris",
        select = select_spec(variable_choices("iris"), "Petal.Length")
      ),
      ggplot2_args = ggplot2_args(
        labs = list(subtitle = "Plot generated by Distribution Module")
      )
    ),
    tm_g_distribution(
      label = "Local card function",
      dist_var = data_extract_spec(
        dataname = "iris",
        select = select_spec(variable_choices("iris"), "Petal.Length")
      ),
      ggplot2_args = ggplot2_args(
        labs = list(subtitle = "Plot generated by Distribution Module")
      ),
      card_function = local_card_function
    ),
    example_module("Example")
  ),
  filter = filter
)

runApp(app, launch.browser = TRUE)

Also works with card function defined in another package (not shown).

Rationale

Currently each module has a hard-coded card function so the module developer has full control over what is added to the report. Neither the app user, nor the app developer has any influence on this.

Being able to redefine the card function is a valid use case.

Scoping Consideration

Current card functions are defined within the module server functions because they rely heavily on bindings that exist in the execution environment of the server function. In order for a function defined elsewhere to be able to access those bindings, a function is introduced, hydrate_function. hydrate_function changes the enclosing environment of a function (here, a card function) to bring another frame into scope. It can also add other bindings to the funciton's enclosure.

Implementation

  • Card functions from all modules that support reporting are isolated as separate, unexported functions. The naming convention is <module_name>_card_function.
  • All modules that support reporting receive a card_function formal argument. If not provided, falls back to the corresponding card function for the module.
  • Within modules, the card function, whether one provided in the call or the fallback value, is passed through hydrate_function to extend its scope to include the module server function's execution environment. This call is identical in all modules:
    card_function <- hydrate_function(card_function, with_filter, filter_panel_api).

NOTE

This is a proof of concept, changes have only been made to tm_g_distribution.

Progress

  • tm_a_pca.R
  • tm_a_regression.R
  • tm_data_table.R
  • tm_g_association.R
  • tm_g_bivariate.R
  • tm_g_distribution.R
  • tm_g_response.R
  • tm_g_scatterplot.R
  • tm_g_scatterplotmatrix.R
  • tm_missing_data.R
  • tm_outliers.R
  • tm_t_crosstable.R
  • tm_variable_browser.R

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants