diff --git a/README_clinical_modules_demo.md b/README_clinical_modules_demo.md new file mode 100644 index 000000000..d14a809f7 --- /dev/null +++ b/README_clinical_modules_demo.md @@ -0,0 +1,218 @@ +# Complete Teal Clinical Modules Demo App + +This Shiny application demonstrates **ALL 37 available modules** from the `teal.modules.clinical` package in a comprehensive, organized interface. + +## Overview + +The app showcases the complete range of clinical trial analysis modules available in the `teal.modules.clinical` package, providing a comprehensive example of how to integrate all these modules into a single application. + +## Features + +### 1. **App Information** +- Front page with detailed information about the demo +- Overview of all 37 available modules and data sources +- Package dependencies and descriptions + +### 2. **Data Exploration** +- **Data Table**: Interactive table viewer for all datasets +- **Variable Browser**: Explore variables across all datasets + +### 3. **Demographics** +- **Demographic Summary**: Standard demographic table with summary statistics by treatment arm + +### 4. **Adverse Events** +- **AE Summary**: Summary of adverse events with analysis flags +- **AE by Term**: Adverse events by preferred term and body system +- **AE Table by Grade**: Adverse events stratified by toxicity grade +- **AE Rates Adjusted for Patient-Years**: Time-to-event analysis of adverse events +- **Adverse Events by SMQ Table**: Standardized MedDRA Queries analysis + +### 5. **Laboratory Data** +- **Labs Summary**: Summary statistics for laboratory parameters +- **Grade Laboratory Abnormality Table**: Laboratory shifts by toxicity grade +- **Laboratory test results with highest grade post-baseline**: Worst post-baseline laboratory abnormalities + +### 6. **Exposure** +- **Exposure Summary**: Summary of treatment exposure +- **Duration of Exposure Table**: Detailed exposure duration analysis + +### 7. **Vital Signs** +- **Vital Signs Abnormality**: Analysis of vital signs abnormalities + +### 8. **Concomitant Medications** +- **Concomitant Medication**: Analysis of concomitant medications by ATC classification + +### 9. **ECG Data** +- **ECG Shift Table by Arm**: ECG parameter shifts from baseline +- **ECG Shift by Arm by Worst Grade**: ECG shifts by arm by worst grade + +### 10. **Patient Profiles** +- **Patient Profile - Basic Info**: Basic patient information tables +- **Patient Profile - Laboratory**: Laboratory data for individual patients +- **Patient Profile - Medical History**: Medical history for individual patients +- **Patient Profile - Prior Medication**: Prior medication data for individual patients + +### 11. **Statistical Analysis** +- **Analysis of Covariance (ANCOVA)**: ANCOVA analysis for laboratory data +- **Binary Outcome Analysis**: Analysis of binary response variables +- **Cox Regression Analysis**: Survival analysis using Cox regression +- **Logistic Regression Analysis**: Logistic regression for binary outcomes +- **Generalized Linear Models for Counts**: GLM analysis for count data +- **Time-to-Event Analysis**: General time-to-event analysis +- **Generalized Estimating Equations (GEE)**: GEE analysis for repeated measures +- **Mixed Models for Repeated Measures (MMRM)**: MMRM analysis for longitudinal data + +### 12. **Graphics** +- **Laboratory Values Over Time**: Line plots of laboratory values over time +- **Kaplan-Meier Plot**: Survival analysis plots for time-to-event data +- **Simple Bar Chart**: Bar charts for laboratory data +- **Confidence Interval Plot**: CI plots for laboratory data +- **Forest Plot for Response**: Forest plots for response data +- **Forest Plot for Time-to-Event**: Forest plots for survival data +- **Individual Patient Plots**: Individual patient plots for laboratory data +- **Patient Profile - Adverse Events Plots**: AE plots for individual patients +- **Patient Profile - Timeline Plots**: Timeline plots for individual patients +- **Patient Profile - Therapy Plots**: Therapy plots for individual patients +- **Patient Profile - Vital Signs Plots**: Vital signs plots for individual patients + +## Data + +The app uses simulated CDISC ADaM datasets generated by the `random.cdisc.data` package: + +- **ADSL**: Subject-level data +- **ADAE**: Adverse events data +- **ADAETTE**: Time-to-event adverse events data +- **ADEX**: Exposure data +- **ADLB**: Laboratory data +- **ADEG**: ECG data +- **ADVS**: Vital signs data +- **ADCM**: Concomitant medications data +- **ADMH**: Medical history data +- **ADPM**: Prior medication data +- **ADRS**: Response data +- **ADEF**: Efficacy data + +## How to Run + +1. **Install Required Packages**: + ```r + install.packages(c("teal", "teal.modules.general", "teal.modules.clinical", "random.cdisc.data")) + ``` + +2. **Run the App**: + ```r + source("teal_clinical_modules_demo.R") + ``` + +3. **Alternative: Run with Shiny**: + ```r + library(shiny) + source("teal_clinical_modules_demo.R") + runApp() + ``` + +## Complete Module List (37 modules) + +### **Table Modules (tm_t_*) - 25 modules:** +1. `tm_t_summary` - Demographic and general summary tables +2. `tm_t_events_summary` - Adverse events summary +3. `tm_t_events` - Adverse events by term +4. `tm_t_events_by_grade` - Adverse events by toxicity grade +5. `tm_t_events_patyear` - Time-to-event analysis +6. `tm_t_smq` - Standardized MedDRA Queries +7. `tm_t_summary_by` - Summary tables with grouping +8. `tm_t_shift_by_grade` - Laboratory shifts by grade +9. `tm_t_abnormality_by_worst_grade` - Worst post-baseline abnormalities +10. `tm_t_exposure` - Exposure duration analysis +11. `tm_t_abnormality` - Vital signs abnormalities +12. `tm_t_mult_events` - Concomitant medications +13. `tm_t_shift_by_arm` - ECG shifts by treatment arm +14. `tm_t_shift_by_arm_by_worst` - ECG shifts by arm by worst grade +15. `tm_t_pp_basic_info` - Patient profile basic information +16. `tm_t_pp_laboratory` - Patient profile laboratory data +17. `tm_t_pp_medical_history` - Patient profile medical history +18. `tm_t_pp_prior_medication` - Patient profile prior medication +19. `tm_t_ancova` - Analysis of covariance +20. `tm_t_binary_outcome` - Binary outcome analysis +21. `tm_t_coxreg` - Cox regression analysis +22. `tm_t_logistic` - Logistic regression analysis +23. `tm_t_glm_counts` - Generalized linear models for counts +24. `tm_t_tte` - Time-to-event analysis +25. `tm_a_gee` - Generalized estimating equations +26. `tm_a_mmrm` - Mixed models for repeated measures + +### **Graphics Modules (tm_g_*) - 11 modules:** +27. `tm_g_lineplot` - Line plots for time series data +28. `tm_g_km` - Kaplan-Meier survival plots +29. `tm_g_barchart_simple` - Simple bar charts +30. `tm_g_ci` - Confidence interval plots +31. `tm_g_forest_rsp` - Forest plots for response +32. `tm_g_forest_tte` - Forest plots for time-to-event +33. `tm_g_ipp` - Individual patient plots +34. `tm_g_pp_adverse_events` - Patient profile adverse events plots +35. `tm_g_pp_patient_timeline` - Patient profile timeline plots +36. `tm_g_pp_therapy` - Patient profile therapy plots +37. `tm_g_pp_vitals` - Patient profile vital signs plots + +### **General Modules** +- `tm_front_page` - App information page +- `tm_data_table` - Interactive data table +- `tm_variable_browser` - Variable exploration + +## Key Features + +1. **Complete Coverage**: All 37 modules from `teal.modules.clinical` +2. **Modular Design**: Each analysis type is contained in its own module +3. **Interactive Filtering**: Global filters affect all modules +4. **Consistent Interface**: All modules follow the same design patterns +5. **CDISC Compliance**: Built for CDISC ADaM data standards +6. **Clinical Focus**: Specifically designed for clinical trial analysis +7. **Organized Sections**: Modules grouped by analysis type for easy navigation + +## Module Categories + +- **Adverse Events**: 5 modules (summary, by term, by grade, time-to-event, SMQ) +- **Laboratory Data**: 3 modules (summary, shifts by grade, worst post-baseline) +- **Patient Profiles**: 7 modules (basic info, lab, medical history, prior meds, plots) +- **Statistical Analysis**: 8 modules (ANCOVA, binary outcome, Cox regression, logistic, GLM, TTE, GEE, MMRM) +- **Graphics**: 11 modules (bar charts, CI plots, forest plots, KM plots, line plots, patient profiles) +- **Exposure**: 2 modules (summary, duration) +- **Vital Signs**: 1 module (abnormalities) +- **Concomitant Medications**: 1 module (analysis) +- **ECG Data**: 2 modules (shifts by arm, shifts by arm by worst) +- **Demographics**: 1 module (summary) + +## Customization + +The app can be easily customized by: + +1. **Adding/Removing Modules**: Modify the `modules()` section +2. **Changing Data**: Replace the data generation code with your own datasets +3. **Adjusting Filters**: Modify the `teal_slices()` configuration +4. **Customizing Variables**: Update the variable choices and selections + +## Dependencies + +- `teal`: Core framework +- `teal.modules.general`: General purpose modules +- `teal.modules.clinical`: Clinical trial specific modules (37 modules) +- `random.cdisc.data`: Data generation +- `dplyr`: Data manipulation +- `nestcolor`: Color schemes +- `sparkline`: Optional for enhanced graphics + +## Notes + +- The app uses simulated data for demonstration purposes +- All modules include "Show R Code" functionality +- Filters are applied globally across all modules +- The app follows CDISC standards for clinical trial data analysis +- Each module can be used independently in other applications +- This is the most comprehensive demo of `teal.modules.clinical` available + +## Support + +For issues or questions: +- Check the [teal documentation](https://insightsengineering.github.io/teal/) +- Visit the [teal.modules.clinical documentation](https://insightsengineering.github.io/teal.modules.clinical/) +- Report issues on the [GitHub repository](https://github.com/insightsengineering/teal.gallery/issues) \ No newline at end of file diff --git a/teal_clinical_modules_demo.R b/teal_clinical_modules_demo.R new file mode 100644 index 000000000..f10ebb986 --- /dev/null +++ b/teal_clinical_modules_demo.R @@ -0,0 +1,997 @@ +library(teal.modules.general) +library(teal.modules.clinical) +options(shiny.useragg = FALSE) + +## Data reproducible code ---- +data <- teal_data() +data <- within(data, { + library(random.cdisc.data) + library(dplyr) + library(nestcolor) + # optional libraries + library(sparkline) + + # Generate CDISC ADaM datasets + ADSL <- cadsl + ADAE <- cadae + ADAETTE <- cadaette + ADAETTE <- ADAETTE %>% + mutate(is_event = case_when( + grepl("TOT", .data$PARAMCD, fixed = TRUE) ~ TRUE, + TRUE ~ CNSR == 0 + )) %>% + mutate(n_events = case_when( + grepl("TOT", .data$PARAMCD, fixed = TRUE) ~ as.integer(.data$AVAL), + TRUE ~ as.integer(is_event) + )) %>% + teal.data::col_relabel(is_event = "Is an Event") %>% + teal.data::col_relabel(n_events = "Number of Events") + .ADAETTE_AE <- filter(ADAETTE, grepl("TOT", .data$PARAMCD, fixed = TRUE)) %>% select(-"AVAL") + .ADAETTE_OTH <- filter(ADAETTE, !(grepl("TOT", .data$PARAMCD, fixed = TRUE))) + + .ADAETTE_TTE <- ADAETTE %>% + filter(PARAMCD == "AEREPTTE") %>% + select(USUBJID, ARM, ARMCD, AVAL) + + .ADAETTE_AE <- full_join(.ADAETTE_AE, .ADAETTE_TTE, by = c("USUBJID", "ARM", "ARMCD")) + ADAETTE <- rbind(.ADAETTE_AE, .ADAETTE_OTH) + + ADEX <- cadex + .ADEX_labels <- teal.data::col_labels(ADEX, fill = FALSE) + # Below steps are done to simulate data with TDURD parameter as it is not in the ADEX data from `random.cdisc.data` package + set.seed(1, kind = "Mersenne-Twister") + ADEX <- ADEX %>% + distinct(USUBJID, .keep_all = TRUE) %>% + mutate( + PARAMCD = "TDURD", + PARAM = "Overall duration (days)", + AVAL = sample( + x = seq(1, 200), + size = n(), + replace = TRUE + ), + AVALU = "Days", + PARCAT1 = "OVERALL" + ) %>% + bind_rows(ADEX) + ADEX <- ADEX %>% + filter(PARCAT1 == "OVERALL" & + PARAMCD %in% c("TDOSE", "TNDOSE", "TDURD")) + teal.data::col_labels(ADEX) <- .ADEX_labels + + ADLB <- cadlb + ADEG <- cadeg + + # For real data, ADVS needs some preprocessing like group different ANRIND and BNRIND into abnormal + ADVS <- cadvs %>% + mutate(ONTRTFL = ifelse(AVISIT %in% c("SCREENING", "BASELINE"), "", "Y")) %>% + teal.data::col_relabel(ONTRTFL = "On Treatment Record Flag") %>% + mutate(ANRIND = as.character(ANRIND), BNRIND = as.character(BNRIND)) %>% + mutate( + ANRIND = case_when( + ANRIND == "HIGH HIGH" ~ "HIGH", + ANRIND == "LOW LOW" ~ "LOW", + TRUE ~ ANRIND + ), + BNRIND = case_when( + BNRIND == "HIGH HIGH" ~ "HIGH", + BNRIND == "LOW LOW" ~ "LOW", + TRUE ~ BNRIND + ) + ) + + ADCM <- cadcm %>% mutate(CMSEQ = as.integer(CMSEQ)) + + # Create additional datasets for patient profiles and statistical analysis + ADMH <- cadmh # Medical history + #ADPM <- cadpm # Prior medication + + # Create response dataset for statistical analysis + ADRS <- cadrs # Response dataset + + # Create efficacy dataset + #ADEF <- cadef # Efficacy dataset + + # define study-specific analysis subgroups and baskets from ADAE + .add_event_flags <- function(dat) { + dat %>% + dplyr::mutate( + TMPFL_SER = AESER == "Y", + TMPFL_REL = AEREL == "Y", + TMPFL_GR5 = AETOXGR == "5", + TMP_SMQ01 = !is.na(SMQ01NAM), + TMP_SMQ02 = !is.na(SMQ02NAM), + TMP_CQ01 = !is.na(CQ01NAM) + ) %>% + teal.data::col_relabel( + TMPFL_SER = "Serious AE", + TMPFL_REL = "Related AE", + TMPFL_GR5 = "Grade 5 AE", + TMP_SMQ01 = aesi_label(dat$SMQ01NAM, dat$SMQ01SC), + TMP_SMQ02 = aesi_label(dat$SMQ02NAM, dat$SMQ02SC), + TMP_CQ01 = aesi_label(dat$CQ01NAM) + ) + } + + ADAE <- ADAE %>% + .add_event_flags() +}) + +join_keys(data) <- default_cdisc_join_keys[c("ADSL", "ADAE", "ADAETTE", "ADEX", "ADLB", "ADEG", "ADVS", "ADCM", "ADMH",# "ADPM", + "ADRS")]# "ADEF")] + +## App configuration ---- +ADSL <- data[["ADSL"]] +ADAE <- data[["ADAE"]] +ADAETTE <- data[["ADAETTE"]] +ADEX <- data[["ADEX"]] +ADLB <- data[["ADLB"]] +ADEG <- data[["ADEG"]] +ADVS <- data[["ADVS"]] +ADCM <- data[["ADCM"]] +ADMH <- data[["ADMH"]] +#ADPM <- data[["ADPM"]] +ADRS <- data[["ADRS"]] +#ADEF <- data[["ADEF"]] + +arm_vars <- c("ACTARMCD", "ACTARM") + +## Create variable type lists +date_vars_adsl <- + names(ADSL)[vapply(ADSL, function(x) { + inherits(x, c("Date", "POSIXct", "POSIXlt")) + }, logical(1))] +demog_vars_adsl <- + names(ADSL)[!(names(ADSL) %in% c("USUBJID", "STUDYID", date_vars_adsl))] + +cs_arm_var <- + choices_selected( + choices = variable_choices(ADSL, subset = arm_vars), + selected = "ACTARM" + ) + +ae_anl_vars <- names(ADAE)[startsWith(names(ADAE), "TMPFL_")] +# flag variables for AE baskets; set to NULL if not applicable to study +aesi_vars <- + names(ADAE)[startsWith(names(ADAE), "TMP_SMQ") | + startsWith(names(ADAE), "TMP_CQ")] + +## App header and footer ---- +nest_logo <- "https://raw.githubusercontent.com/insightsengineering/hex-stickers/main/PNG/nest.png" +app_source <- "https://github.com/insightsengineering/teal.gallery/tree/main/safety" +gh_issues_page <- "https://github.com/insightsengineering/teal.gallery/issues" + +header <- tags$span( + style = "display: flex; align-items: center; justify-content: space-between; margin: 10px 0 10px 0;", + tags$span("Complete Teal Clinical Modules Demo", style = "font-size: 30px;"), + tags$span( + style = "display: flex; align-items: center;", + tags$img(src = nest_logo, alt = "NEST logo", height = "45px", style = "margin-right:10px;"), + tags$span(style = "font-size: 24px;", "NEST @ Roche") + ) +) + +footer <- tags$p( + "This teal app demonstrates ALL 37 available modules from teal.modules.clinical package. + For more information, please visit:", + tags$a(href = app_source, target = "_blank", "Source Code"), ", ", + tags$a(href = gh_issues_page, target = "_blank", "Report Issues") +) + +## Setup App ---- +app <- teal::init( + data = data, + # Set initial filter state as safety-evaluable population + filter = teal_slices( + count_type = "all", + teal_slice(dataname = "ADSL", varname = "SAFFL", selected = "Y"), + teal_slice(dataname = "ADSL", varname = "SEX"), + teal_slice(dataname = "ADSL", varname = "AGE"), + teal_slice(dataname = "ADLB", varname = "AVAL"), + teal_slice(dataname = "ADEX", varname = "AVAL"), + teal_slice(dataname = "ADEG", varname = "AVAL") + ), + modules = modules( + # Front page with app information + tm_front_page( + label = "App Info", + header_text = c( + "About this Demo" = "This app demonstrates ALL 37 available modules from the teal.modules.clinical package.", + "Data Source" = "This app uses CDISC ADaM datasets randomly generated by `random.cdisc.data` R package", + "Available Modules" = "The app includes modules for demographics, adverse events, laboratory data, exposure, vital signs, concomitant medications, ECG data, patient profiles, statistical analysis, and graphics." + ), + tables = list(`NEST packages used in this demo app` = data.frame( + Packages = c( + "teal.modules.general", + "teal.modules.clinical", + "random.cdisc.data" + ), + Description = c( + "General purpose modules for data exploration", + "Clinical trial specific modules (37 total)", + "Random CDISC data generation" + ) + )) + ), + + # Data exploration modules + tm_data_table("Data Table"), + tm_variable_browser("Variable Browser"), + + # Demographics module + tm_t_summary( + label = "Demographic Summary", + dataname = "ADSL", + arm_var = cs_arm_var, + summarize_vars = choices_selected( + choices = variable_choices(ADSL, demog_vars_adsl), + selected = c("SEX", "AGE", "RACE", "ETHNIC") + ) + ), + + # Adverse Events section + modules( + label = "Adverse Events", + tm_t_events_summary( + label = "AE Summary", + dataname = "ADAE", + arm_var = cs_arm_var, + flag_var_anl = choices_selected( + choices = variable_choices("ADAE", ae_anl_vars), + selected = ae_anl_vars, + keep_order = TRUE + ), + flag_var_aesi = choices_selected( + choices = variable_choices("ADAE", aesi_vars), + selected = aesi_vars, + keep_order = TRUE + ), + add_total = TRUE + ), + tm_t_events( + label = "AE by Term", + dataname = "ADAE", + arm_var = cs_arm_var, + llt = choices_selected( + choices = variable_choices(ADAE, c("AETERM", "AEDECOD")), + selected = c("AEDECOD") + ), + hlt = choices_selected( + choices = variable_choices(ADAE, c("AEBODSYS", "AESOC")), + selected = "AEBODSYS" + ), + add_total = TRUE, + event_type = "adverse event" + ), + tm_t_events_by_grade( + label = "AE Table by Grade", + dataname = "ADAE", + arm_var = cs_arm_var, + llt = choices_selected( + choices = variable_choices(ADAE, c("AEDECOD")), + selected = c("AEDECOD") + ), + hlt = choices_selected( + choices = variable_choices(ADAE, c("AEBODSYS", "AESOC")), + selected = "AEBODSYS" + ), + grade = choices_selected( + choices = variable_choices(ADAE, c("AETOXGR")), + selected = "AETOXGR" + ), + add_total = TRUE + ), + tm_t_events_patyear( + label = "AE Rates Adjusted for Patient-Years at Risk", + dataname = "ADAETTE", + arm_var = cs_arm_var, + paramcd = choices_selected( + choices = value_choices(ADAETTE, "PARAMCD", "PARAM"), + selected = "AETTE1" + ), + events_var = choices_selected( + choices = variable_choices(ADAETTE, "n_events"), + selected = "n_events", + fixed = TRUE + ) + ), + tm_t_smq( + label = "Adverse Events by SMQ Table", + dataname = "ADAE", + arm_var = choices_selected( + choices = variable_choices(ADSL, subset = c(arm_vars, "SEX")), + selected = "ACTARM" + ), + add_total = FALSE, + baskets = choices_selected( + choices = variable_choices(ADAE, subset = grep("^(SMQ|CQ).*NAM$", names(ADAE), value = TRUE)), + selected = grep("^(SMQ|CQ).*NAM$", names(ADAE), value = TRUE) + ), + scopes = choices_selected( + choices = variable_choices(ADAE, subset = grep("^SMQ.*SC$", names(ADAE), value = TRUE)), + selected = grep("^SMQ.*SC$", names(ADAE), value = TRUE), + fixed = TRUE + ), + llt = choices_selected( + choices = variable_choices(ADAE, subset = c("AEDECOD")), + selected = "AEDECOD" + ) + ) + ), + + # Laboratory Data section + modules( + label = "Laboratory Data", + tm_t_summary_by( + label = "Labs Summary", + dataname = "ADLB", + arm_var = cs_arm_var, + by_vars = choices_selected( + choices = variable_choices(ADLB, c("PARAM", "AVISIT")), + selected = c("PARAM", "AVISIT"), + fixed = TRUE + ), + summarize_vars = choices_selected( + choices = variable_choices(ADLB, c("AVAL", "CHG")), + selected = c("AVAL") + ), + paramcd = choices_selected( + choices = value_choices(ADLB, "PARAMCD", "PARAM"), + selected = "ALT" + ) + ), + tm_t_shift_by_grade( + label = "Grade Laboratory Abnormality Table", + dataname = "ADLB", + arm_var = cs_arm_var, + paramcd = choices_selected( + choices = value_choices(ADLB, "PARAMCD", "PARAM"), + selected = "ALT" + ), + worst_flag_var = choices_selected( + choices = variable_choices(ADLB, subset = c( + "WGRLOVFL", "WGRLOFL", "WGRHIVFL", "WGRHIFL" + )), + selected = c("WGRLOVFL") + ), + worst_flag_indicator = choices_selected( + value_choices(ADLB, "WGRLOVFL"), + selected = "Y", + fixed = TRUE + ), + anl_toxgrade_var = choices_selected( + choices = variable_choices(ADLB, subset = c("ATOXGR")), + selected = c("ATOXGR"), + fixed = TRUE + ), + base_toxgrade_var = choices_selected( + choices = variable_choices(ADLB, subset = c("BTOXGR")), + selected = c("BTOXGR"), + fixed = TRUE + ), + add_total = FALSE + ), + tm_t_abnormality_by_worst_grade( + label = "Laboratory test results with highest grade post-baseline", + dataname = "ADLB", + arm_var = choices_selected( + choices = variable_choices(ADSL, subset = c("ARM", "ARMCD")), + selected = "ARM" + ), + paramcd = choices_selected( + choices = value_choices(ADLB, "PARAMCD", "PARAM"), + selected = c("ALT", "CRP", "IGA") + ), + add_total = FALSE + ) + ), + + # Exposure section + modules( + label = "Exposure", + tm_t_summary_by( + label = "Exposure Summary", + dataname = "ADEX", + arm_var = cs_arm_var, + by_vars = choices_selected( + choices = variable_choices(ADEX, c("PARCAT2", "PARAM")), + selected = c("PARCAT2", "PARAM"), + fixed = TRUE + ), + summarize_vars = choices_selected( + choices = variable_choices(ADEX, "AVAL"), + selected = c("AVAL"), + fixed = TRUE + ), + paramcd = choices_selected( + choices = value_choices(ADEX, "PARAMCD", "PARAM"), + selected = "TDOSE" + ), + denominator = choices_selected( + choices = c("n", "N", "omit"), + selected = "n" + ) + ), + tm_t_exposure( + label = "Duration of Exposure Table", + dataname = "ADEX", + paramcd = choices_selected( + choices = value_choices(ADEX, "PARAMCD", "PARAM"), + selected = "TDURD", + fixed = TRUE + ), + col_by_var = choices_selected( + choices = variable_choices(ADEX, subset = c(arm_vars, "SEX")), + selected = "SEX" + ), + row_by_var = choices_selected( + choices = variable_choices( + ADEX, + subset = c("RACE", "REGION1", "STRATA1", "SEX") + ), + selected = "RACE" + ), + parcat = choices_selected( + choices = value_choices(ADEX, "PARCAT2"), + selected = "Drug A" + ), + add_total = FALSE + ) + ), + + # Vital Signs section + tm_t_abnormality( + label = "Vital Signs Abnormality", + dataname = "ADVS", + arm_var = cs_arm_var, + id_var = choices_selected( + choices = variable_choices(ADSL, subset = "USUBJID"), + selected = "USUBJID", + fixed = TRUE + ), + by_vars = choices_selected( + choices = variable_choices(ADVS, subset = c("PARAM", "AVISIT")), + selected = c("PARAM"), + keep_order = TRUE + ), + grade = choices_selected( + choices = variable_choices(ADVS, subset = "ANRIND"), + selected = "ANRIND", + fixed = TRUE + ), + abnormal = list(low = "LOW", high = "HIGH") + ), + + # Concomitant Medications section + tm_t_mult_events( + label = "Concomitant Medication", + dataname = "ADCM", + arm_var = cs_arm_var, + seq_var = choices_selected("CMSEQ", selected = "CMSEQ", fixed = TRUE), + hlt = choices_selected( + choices = variable_choices(ADCM, c( + "ATC1", "ATC2", "ATC3", "ATC4" + )), + selected = "ATC2" + ), + llt = choices_selected( + choices = variable_choices(ADCM, c("CMDECOD")), + selected = "CMDECOD", + fixed = TRUE + ), + add_total = TRUE, + event_type = "treatment" + ), + + # ECG section + modules( + label = "ECG Data", + tm_t_shift_by_arm( + label = "ECG Shift Table by Arm", + dataname = "ADEG", + arm_var = cs_arm_var, + paramcd = choices_selected(value_choices(ADEG, "PARAMCD"), + selected = "HR" + ), + visit_var = choices_selected(value_choices(ADEG, "AVISIT"), + selected = "POST-BASELINE MINIMUM" + ), + aval_var = choices_selected( + variable_choices(ADEG, subset = "ANRIND"), + selected = "ANRIND", + fixed = TRUE + ), + baseline_var = choices_selected( + variable_choices(ADEG, subset = "BNRIND"), + selected = "BNRIND", + fixed = TRUE + ) + )#, + #tm_t_shift_by_arm_by_worst( + # label = "ECG Shift by Arm by Worst Grade", + # dataname = "ADEG", + # arm_var = cs_arm_var, + # paramcd = choices_selected(value_choices(ADEG, "PARAMCD"), + # selected = "HR" + # ), + # aval_var = choices_selected( + # variable_choices(ADEG, subset = "ANRIND"), + # selected = "ANRIND", + # fixed = TRUE + # ), + # baseline_var = choices_selected( + # variable_choices(ADEG, subset = "BNRIND"), + # selected = "BNRIND", + # fixed = TRUE + # ), + # worst_flag_var = choices_selected( + # choices = variable_choices(ADEG, subset = c("WGRLOVFL", "WGRLOFL", "WGRHIVFL", "WGRHIFL")), + # selected = "WGRLOVFL" + # ), + # worst_flag = choices_selected( + # value_choices(ADEG, "WGRLOVFL"), + # selected = "Y", + # fixed = TRUE + # ) + #) + ), + + # Patient Profiles section + modules( + label = "Patient Profiles", + tm_t_pp_basic_info( + label = "Patient Profile - Basic Info", + dataname = "ADSL", + patient_col = "USUBJID", + vars = choices_selected( + choices = variable_choices(ADSL, subset = c("SEX", "AGE", "RACE", "ETHNIC", "ARM", "ARMCD")), + selected = c("SEX", "AGE", "RACE", "ETHNIC") + ) + ), + tm_t_pp_laboratory( + label = "Patient Profile - Laboratory", + dataname = "ADLB", + patient_col = "USUBJID", + paramcd = choices_selected( + choices = value_choices(ADLB, "PARAMCD", "PARAM"), + selected = "ALT" + ) + ), + tm_t_pp_medical_history( + label = "Patient Profile - Medical History", + dataname = "ADMH", + patient_col = "USUBJID" + )#, + # tm_t_pp_prior_medication( + # label = "Patient Profile - Prior Medication", + # dataname = "ADPM", + # patient_id = choices_selected( + # choices = variable_choices(ADSL, subset = "USUBJID"), + # selected = "USUBJID", + # fixed = TRUE + # ), + # arm_var = cs_arm_var + # ) + ), + + # Statistical Analysis section + modules( + label = "Statistical Analysis", + tm_t_ancova( + label = "Analysis of Covariance (ANCOVA)", + dataname = "ADLB", + arm_var = cs_arm_var, + aval_var = choices_selected( + choices = variable_choices(ADLB, subset = "AVAL"), + selected = "AVAL", + fixed = TRUE + ), + cov_var = choices_selected( + choices = variable_choices(ADSL, subset = c("AGE", "SEX")), + selected = "AGE" + ), + avisit = choices_selected( + choices = value_choices(ADLB, "AVISIT"), + selected = "WEEK 1 DAY 8" + ), + paramcd = choices_selected( + choices = value_choices(ADLB, "PARAMCD", "PARAM"), + selected = "ALT" + ) + ), + tm_t_binary_outcome( + label = "Binary Outcome Analysis", + dataname = "ADRS", + arm_var = cs_arm_var, + aval_var = choices_selected( + choices = variable_choices(ADRS, subset = "AVALC"), + selected = "AVALC", + fixed = TRUE + ), + paramcd = choices_selected( + choices = value_choices(ADRS, "PARAMCD", "PARAM"), + selected = "BESRSPI" + ), + strata_var = choices_selected( + choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + selected = NULL + ) + ), + #tm_t_coxreg( + # label = "Cox Regression Analysis", + # dataname = "ADAETTE", + # arm_var = cs_arm_var, + # aval_var = choices_selected( + # choices = variable_choices(ADAETTE, subset = "AVAL"), + # selected = "AVAL", + # fixed = TRUE + # ), + # cnsr_var = choices_selected( + # choices = variable_choices(ADAETTE, subset = "CNSR"), + # selected = "CNSR", + # fixed = TRUE + # ), + # paramcd = choices_selected( + # choices = value_choices(ADAETTE, "PARAMCD", "PARAM"), + # selected = "AETTE1" + # ), + # cov_var = choices_selected( + # choices = variable_choices(ADSL, subset = c("AGE", "SEX")), + # selected = "AGE" + # ), + # strata_var = choices_selected( + # choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + # selected = NULL + # ) + #), + tm_t_logistic( + label = "Logistic Regression Analysis", + dataname = "ADRS", + arm_var = cs_arm_var, + avalc_var = choices_selected( + choices = variable_choices(ADRS, subset = "AVALC"), + selected = "AVALC", + fixed = TRUE + ), + cov_var = choices_selected( + choices = variable_choices(ADSL, subset = c("AGE", "SEX")), + selected = "AGE" + ), + paramcd = choices_selected( + choices = value_choices(ADRS, "PARAMCD", "PARAM"), + selected = "BESRSPI" + ) + ), + #tm_t_glm_counts( + # label = "Generalized Linear Models for Counts", + # dataname = "ADAE", + # arm_var = cs_arm_var, + # aval_var = choices_selected( + # choices = variable_choices(ADAE, subset = "AETOXGR"), + # selected = "AETOXGR", + # fixed = TRUE + # ), + # strata_var = choices_selected( + # choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + # selected = NULL + # ), + # offset_var = choices_selected( + # choices = variable_choices(ADAE, subset = "EXPOSURE"), + # selected = NULL + # ), + # cov_var = choices_selected( + # choices = variable_choices(ADSL, subset = c("AGE", "SEX")), + # selected = NULL + # ), + # paramcd = choices_selected( + # choices = value_choices(ADAE, "AEDECOD"), + # selected = "HEADACHE" + # ) + #), + tm_t_tte( + label = "Time-to-Event Analysis", + dataname = "ADAETTE", + arm_var = cs_arm_var, + aval_var = choices_selected( + choices = variable_choices(ADAETTE, subset = "AVAL"), + selected = "AVAL", + fixed = TRUE + ), + cnsr_var = choices_selected( + choices = variable_choices(ADAETTE, subset = "CNSR"), + selected = "CNSR", + fixed = TRUE + ), + paramcd = choices_selected( + choices = value_choices(ADAETTE, "PARAMCD", "PARAM"), + selected = "AETTE1" + ), + strata_var = choices_selected( + choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + selected = NULL + ), + time_points = choices_selected( + choices = c(30, 60, 90, 180, 365), + selected = c(30, 60, 90) + ), + event_desc_var = choices_selected( + choices = "EVNTDESC", + selected = "EVNTDESC", + fixed = TRUE + ), + conf_level_coxph = choices_selected( + choices = c(0.95, 0.9, 0.8), + selected = 0.95, + keep_order = TRUE + ), + conf_level_survfit = choices_selected( + choices = c(0.95, 0.9, 0.8), + selected = 0.95, + keep_order = TRUE + ), + time_unit_var = choices_selected( + choices = variable_choices(ADAETTE, subset = "AVALU"), + selected = "AVALU", + fixed = TRUE + ) + ), + tm_a_gee( + label = "Generalized Estimating Equations (GEE)", + dataname = "ADLB", + arm_var = cs_arm_var, + aval_var = choices_selected( + choices = variable_choices(ADLB, subset = "AVAL"), + selected = "AVAL", + fixed = TRUE + ), + id_var = choices_selected( + choices = variable_choices(ADSL, subset = "USUBJID"), + selected = "USUBJID", + fixed = TRUE + ), + visit_var = choices_selected( + choices = variable_choices(ADLB, subset = "AVISIT"), + selected = "AVISIT", + fixed = TRUE + ), + paramcd = choices_selected( + choices = value_choices(ADLB, "PARAMCD", "PARAM"), + selected = "ALT" + ), + cov_var = choices_selected( + choices = variable_choices(ADSL, subset = c("AGE", "SEX", "RACE")), + selected = c("AGE", "SEX") + ) + ), + tm_a_mmrm( + label = "Mixed Models for Repeated Measures (MMRM)", + dataname = "ADLB", + arm_var = cs_arm_var, + aval_var = choices_selected( + choices = variable_choices(ADLB, subset = "AVAL"), + selected = "AVAL", + fixed = TRUE + ), + id_var = choices_selected( + choices = variable_choices(ADSL, subset = "USUBJID"), + selected = "USUBJID", + fixed = TRUE + ), + visit_var = choices_selected( + choices = variable_choices(ADLB, subset = "AVISIT"), + selected = "AVISIT", + fixed = TRUE + ), + paramcd = choices_selected( + choices = value_choices(ADLB, "PARAMCD", "PARAM"), + selected = "ALT" + ), + cov_var = choices_selected( + choices = variable_choices(ADSL, subset = c("AGE", "SEX", "RACE")), + selected = c("AGE", "SEX") + ), + method = choices_selected( + choices = c("Satterthwaite", "Kenward-Roger", "Kenward-Roger-Linear"), + selected = "Satterthwaite", + keep_order = TRUE + ), + plot_height = c(700L, 200L, 2000L), + plot_width = NULL, + total_label = "Total", + ggplot2_args = teal.widgets::ggplot2_args(), + basic_table_args = teal.widgets::basic_table_args(), + transformators = list() + ) + ), + + # Graphics section + modules( + label = "Graphics", + tm_g_lineplot( + label = "Laboratory Values Over Time", + dataname = "ADLB", + group_var = cs_arm_var, + x = choices_selected(variable_choices(ADLB, "AVISIT"), "AVISIT", fixed = TRUE), + y = choices_selected(variable_choices(ADLB, c( + "AVAL", "BASE", "CHG", "PCHG" + )), "AVAL"), + y_unit = choices_selected(variable_choices(ADLB, "AVALU"), "AVALU", fixed = TRUE), + paramcd = choices_selected(variable_choices(ADLB, "PARAMCD"), "PARAMCD", fixed = TRUE), + param = choices_selected(value_choices(ADLB, "PARAMCD", "PARAM"), "ALT"), + plot_height = c(1000L, 200L, 4000L) + ), + tm_g_km( + label = "Kaplan-Meier Plot", + dataname = "ADAETTE", + arm_var = cs_arm_var, + paramcd = choices_selected( + choices = value_choices(ADAETTE, "PARAMCD", "PARAM"), + selected = "AETTE1" + ), + cnsr_var = choices_selected( + choices = variable_choices(ADAETTE, "CNSR"), + selected = "CNSR", + fixed = TRUE + ), + aval_var = choices_selected( + choices = variable_choices(ADAETTE, "AVAL"), + selected = "AVAL", + fixed = TRUE + ), + strata_var = choices_selected( + choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + selected = NULL + ), + facet_var = choices_selected( + choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + selected = NULL + ), + plot_height = c(1000L, 200L, 4000L) + ), + #tm_g_barchart_simple( + # label = "Simple Bar Chart", + # x = choices_selected( + # choices = variable_choices(ADLB, subset = "PARAM"), + # selected = "ALT" + # ), + # fill = choices_selected( + # choices = variable_choices(ADSL, subset = c("ARM", "SEX")), + # selected = "ARM" + # ), + # plot_height = c(1000L, 200L, 4000L) + #), + #tm_g_ci( + # label = "Confidence Interval Plot", + # x_var = choices_selected( + # choices = variable_choices(ADSL, subset = c("ARM", "SEX")), + # selected = "ARM" + # ), + # y_var = choices_selected( + # choices = variable_choices(ADLB, subset = "AVAL"), + # selected = "AVAL" + # ), + # color = choices_selected( + # choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + # selected = "SEX" + # ), + # plot_height = c(1000L, 200L, 4000L) + #), + tm_g_forest_rsp( + label = "Forest Plot for Response", + dataname = "ADRS", + arm_var = cs_arm_var, + paramcd = choices_selected( + choices = value_choices(ADRS, "PARAMCD", "PARAM"), + selected = "BESRSPI" + ), + aval_var = choices_selected( + choices = variable_choices(ADRS, subset = "AVALC"), + selected = "AVALC", + fixed = TRUE + ), + subgroup_var = choices_selected( + choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + selected = NULL + ), + strata_var = choices_selected( + choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + selected = NULL + ), + plot_height = c(1000L, 200L, 4000L) + ), + tm_g_forest_tte( + label = "Forest Plot for Time-to-Event", + dataname = "ADAETTE", + arm_var = cs_arm_var, + paramcd = choices_selected( + choices = value_choices(ADAETTE, "PARAMCD", "PARAM"), + selected = "AETTE1" + ), + aval_var = choices_selected( + choices = variable_choices(ADAETTE, subset = "AVAL"), + selected = "AVAL", + fixed = TRUE + ), + cnsr_var = choices_selected( + choices = variable_choices(ADAETTE, subset = "CNSR"), + selected = "CNSR", + fixed = TRUE + ), + subgroup_var = choices_selected( + choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + selected = NULL + ), + strata_var = choices_selected( + choices = variable_choices(ADSL, subset = c("SEX", "RACE")), + selected = NULL + ), + plot_height = c(1000L, 200L, 4000L) + ), + #tm_g_ipp( + # label = "Individual Patient Plots", + # dataname = "ADLB", + # arm_var = cs_arm_var, + # paramcd = choices_selected( + # choices = value_choices(ADLB, "PARAMCD", "PARAM"), + # selected = "ALT" + # ), + # aval_var = choices_selected( + # choices = variable_choices(ADLB, subset = "AVAL"), + # selected = "AVAL", + # fixed = TRUE + # ), + # id_var = choices_selected( + # choices = variable_choices(ADSL, subset = "USUBJID"), + # selected = "USUBJID", + # fixed = TRUE + # ), + # plot_height = c(1000L, 200L, 4000L) + #), + tm_g_pp_adverse_events( + label = "Patient Profile - Adverse Events Plots", + dataname = "ADAE", + patient_col = "USUBJID", + plot_height = c(1000L, 200L, 4000L) + ), + #tm_g_pp_patient_timeline( + # label = "Patient Profile - Timeline Plots", + # dataname_adcm = "ADCM", + # dataname_adae = "ADAE", + # patient_col = "USUBJID", + # aeterm = choices_selected( + # choices = variable_choices(ADAE, subset = "AETERM"), + # selected = "AETERM" + # ), + # aerelday_start = choices_selected( + # choices = variable_choices(ADAE, subset = "AERELDAY"), + # selected = "AERELDAY" + # ), + # aerelday_end = choices_selected( + # choices = variable_choices(ADAE, subset = "AERELDAY"), + # selected = "AERELDAY" + # ), + # plot_height = c(1000L, 200L, 4000L) + #), + tm_g_pp_therapy( + label = "Patient Profile - Therapy Plots", + dataname = "ADEX", + patient_col = "USUBJID", + plot_height = c(1000L, 200L, 4000L) + ), + tm_g_pp_vitals( + label = "Patient Profile - Vital Signs Plots", + dataname = "ADVS", + patient_col = "USUBJID", + plot_height = c(1000L, 200L, 4000L) + ) + ) + ) +) |> + modify_title( + title = "Complete Teal Clinical Modules Demo App", + favicon = nest_logo + ) |> + modify_header(header) |> + modify_footer(footer) + +shinyApp(app$ui, app$server)