Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question]: About passing external variables to modules #1221

Open
3 tasks done
pzhang-cims opened this issue Sep 5, 2024 · 9 comments
Open
3 tasks done

[Question]: About passing external variables to modules #1221

pzhang-cims opened this issue Sep 5, 2024 · 9 comments
Assignees
Labels
core question Further information is requested sme

Comments

@pzhang-cims
Copy link

What is your question?

Hi there,

Thanks for the effort of developing teal.modules.clinical. I have a general question that how to pass external variables into the modules.

For example, consider a module using following code

    tm_t_summary(
      label = "ADSL", 
      dataname = "ADSL",
      arm_var = choices_selected(
        choices= variable_choices("ADSL",c('TRT01A', 'TRT01P'))
        selected = variable_choices("ADSL",'TRT01P')
      ),
      summarize_vars = choices_selected(
        variable_choices("ADSL")
      ),
      useNA = "ifany"
    )

In this case, we fix the variables of 'TRT01A', and 'TRT01P' as choices and 'TRT01P' as selected. We are wondering, if there is a way that, we can pass variable from external file, or server environment that, say, a variable called arm_selected = c('TRT01A','TRT01P') and we will have choices= variable_choices("ADSL", arm_selected). I have tried multiple ways:

  1. By creating a module server for teal_data_module. But, if we define `arm_selected' inside of it, we cannot call it in to the module
  2. By defining `arm_selected' within a teal_data(), similarly it cannot pass to the module.

Would you please advise if this use case is plausible in teal.modules.clinical?

Code of Conduct

  • I agree to follow this project's Code of Conduct.

Contribution Guidelines

  • I agree to follow this project's Contribution Guidelines.

Security Policy

  • I agree to follow this project's Security Policy.
@pzhang-cims pzhang-cims added the question Further information is requested label Sep 5, 2024
@pzhang-cims
Copy link
Author

We tried the approach from https://insightsengineering.github.io/teal.modules.clinical/latest-tag/reference/tm_t_events_summary.html. But this seems not work for a data from teal_data_module()

@Melkiades Melkiades added the sme label Sep 10, 2024
@pzhang-cims
Copy link
Author

I would like to answer for myself that which is a temporary solution:

  1. In your teal data module, if you have any external variables, you can put it into global environment, e.g.

list2env(var_select, envir = .GlobalEnv) to global environment

  1. then in variable_choices(), with subsect function, using the variable name in globalenv()

e.g.
choices=variable_choices("ADSL",subset = function(data){globalenv()$base_var$trt_option}),

@pzhang-cims
Copy link
Author

pzhang-cims commented Sep 10, 2024

If only one variable is allowed by variable_choices, then one can go to the module by using

tmp<-tm_t_events(....)
set value for tmp$ui_args$hlt$select$selected, tmp$server_args$hlt$select$selected by global variables.

@Melkiades Melkiades added the core label Sep 30, 2024
@Melkiades
Copy link
Contributor

I would like to answer for myself that which is a temporary solution:

  1. In your teal data module, if you have any external variables, you can put it into global environment, e.g.

list2env(var_select, envir = .GlobalEnv) to global environment

  1. then in variable_choices(), with subsect function, using the variable name in globalenv()

e.g. choices=variable_choices("ADSL",subset = function(data){globalenv()$base_var$trt_option}),

I am happy this "hack" works :) but I am sure someone from the core team can help you best. I am not sure if the data can be changed within {teal.data} as you mentioned above. Any suggestions? @donyunardi @vedhav

@pzhang-cims
Copy link
Author

pzhang-cims commented Sep 30, 2024

Thank you @Melkiades for catching this up! I understand that {teal} is developed for study-level purpose. Developer can deploy one app to one sever for study. From our side, we want to see if one hosted server can work for different studies. It's good to see we have a function teal_data_module() to allow data upload. We might want to see if external files can be uploaded (e.g., mapping file), so that a server can be generalized for multiple studies, given limited server

@donyunardi
Copy link
Contributor

donyunardi commented Sep 30, 2024

Functional subset is the proper way to do this when using teal_data_module, but unfortunately, we have a bug on this functionality.

We'll planning to tackle this soon, in the meantime, I think your temporary solution (surfacing the object globally) sounds plausible. 👍🏼

@pzhang-cims
Copy link
Author

@donyunardi thank you for keeping us updated and good to know it's on the track. If possible let me know when such updates reflect on CRAN so that we can adapt accordingly. Can't wait to see that.

@m7pr
Copy link
Contributor

m7pr commented Oct 7, 2024

Hey @pzhang-cims , the bug that @donyunardi mentioned was only in teal.goshawk package.
In teal.modules.clinical there was no bug.

arm_var dependent on data

If you want to create arm_var that is dependent on the data and gets resolved once the data is loaded, you can use variable_choices with subset parameter, that takes function (with data) parameter as an input. Checkout below options.

CDISC example
ADSL <- tmc_ex_adsl
ADSL$EOSDY[1] <- NA_integer_


arm_var_delayed <- 
  choices_selected(
    choices = variable_choices("ADSL", subset = function(data) {
      grep('^ARM', names(data), value = TRUE)
    }),
    selected = "ARM"
  )

app <- init(
  data = cdisc_data(
    ADSL = ADSL,
    code = "
      ADSL <- tmc_ex_adsl
      ADSL$EOSDY[1] <- NA_integer_
    "
  ),
  modules = modules(
    tm_t_summary(
      label = "Demographic Table",
      dataname = "ADSL",
      arm_var = arm_var_delayed,
      add_total = TRUE,
      summarize_vars = choices_selected(
        c("SEX", "RACE", "BMRKR2", "EOSDY", "DCSREAS", "AGE"),
        c("SEX", "RACE")
      ),
      useNA = "ifany"
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
`teal_data` example
library(teal.data)
data <- within(
  teal_data(), {
  ADSL <- teal.modules.clinical::tmc_ex_adsl
  ADSL$EOSDY[1] <- NA_integer_
})
  
datanames(data) <- "ADSL"
join_keys(data) <- teal.data::default_cdisc_join_keys["ADSL"]


arm_var_delayed <- 
  choices_selected(
    choices = variable_choices("ADSL", function(data) {
      grep('^ARM', names(data), value = TRUE)
    }),
    selected = "ARM"
  )

app <- init(
  data = data,
  modules = modules(
    tm_t_summary(
      label = "Demographic Table",
      dataname = "ADSL",
      arm_var = arm_var_delayed,
      add_total = TRUE,
      summarize_vars = choices_selected(
        c("SEX", "RACE", "BMRKR2", "EOSDY", "DCSREAS", "AGE"),
        c("SEX", "RACE")
      ),
      useNA = "ifany"
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
`teal_data_module`
library(teal.data)


tdm <- teal_data_module(
  ui = function(id) {
    ns <- NS(id)
    actionButton(ns("submit"), label = "Load data")
  },
  server = function(id) {
    moduleServer(id, function(input, output, session) {
      eventReactive(input$submit, {
        data <- within(
          teal_data(),
          {
            ADSL <- teal.modules.clinical::tmc_ex_adsl
            ADSL$EOSDY[1] <- NA_integer_
          }
        )
        datanames(data) <- "ADSL"
        join_keys(data) <- teal.data::default_cdisc_join_keys["ADSL"]
        
        data
      })
    })
  }
)


arm_var_delayed <- 
  choices_selected(
    choices = variable_choices("ADSL", function(data) {
      grep('^ARM', names(data), value = TRUE)
    }),
    selected = "ARM"
  )

app <- init(
  data = tdm,
  modules = modules(
    tm_t_summary(
      label = "Demographic Table",
      dataname = "ADSL",
      arm_var = arm_var_delayed,
      add_total = TRUE,
      summarize_vars = choices_selected(
        c("SEX", "RACE", "BMRKR2", "EOSDY", "DCSREAS", "AGE"),
        c("SEX", "RACE")
      ),
      useNA = "ifany"
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}

arm_var dependent on a variable from an external file

If you want to pass a variable from external file, just load it to your .Global environment

External file
# external file saved as `extra_parameters.R`
arm_var <- 
  choices_selected(
    choices = variable_choices("ADSL", c("ARM", "ARMCD")),
    selected = "ARM"
  )
Data creation
library(teal.data)
data <- within(
  teal_data(), {
    ADSL <- teal.modules.clinical::tmc_ex_adsl
    ADSL$EOSDY[1] <- NA_integer_
  })

datanames(data) <- "ADSL"
join_keys(data) <- teal.data::default_cdisc_join_keys["ADSL"]

source('extra_parameters.R')

app <- init(
  data = data,
  modules = modules(
    tm_t_summary(
      label = "Demographic Table",
      dataname = "ADSL",
      arm_var = arm_var,
      add_total = TRUE,
      summarize_vars = choices_selected(
        c("SEX", "RACE", "BMRKR2", "EOSDY", "DCSREAS", "AGE"),
        c("SEX", "RACE")
      ),
      useNA = "ifany"
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}

arm_var dependent on a variable from the server

When it comes to passing variables from server, I think you're trick to assign variables to the global environment is fine.

There is also a way to update specific UI inputs with shinyWidgets::update* functions in your server code.

Lastly, you could always assign an attribute to your data, in your server code, and this attribute could be used in variable_choices(subset = function(data) attr(data, 'attribute_name)' to get the value.

Summary

Let me know if you need any more help in here

@m7pr m7pr self-assigned this Oct 7, 2024
@pzhang-cims
Copy link
Author

@m7pr, thank you so much for the detailed explanation. In you 3 options, I believe I know the first one, and the second one is similar to what I applied right now. The third one seems interesting and resolve the issue from another angle. Let me try it recently and reflect my experience later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core question Further information is requested sme
Projects
None yet
Development

No branches or pull requests

4 participants