criteria_fun <-function(tr) !is(tr, "ContentRow") &&all_zero_or_na(tr)lyt <-basic_table(show_colcounts =TRUE) %>%split_cols_by("ACTARMCD") %>%split_cols_by("SEX") %>%analyze_num_patients(vars ="USUBJID",.stats =c("unique"),.labels =c(unique ="Total number of patients with at least one adverse event") ) %>%split_rows_by("SMQ",child_labels ="visible",nested =FALSE,split_fun =trim_levels_in_group("AEDECOD", drop_outlevs =FALSE),label_pos ="topleft",split_label ="Standardized MedDRA Query" ) %>%summarize_num_patients(var ="USUBJID",.stats =c("unique", "nonunique"),.labels =c(unique ="Total number of patients with at least one adverse event",nonunique ="Total number of events" ) ) %>%count_occurrences(vars ="AEDECOD", drop =FALSE) %>%append_varlabels(adae_smq_1, "AEDECOD", indent =1L)result <-build_table(lyt = lyt,df = adae_smq_1,alt_counts_df = adsl) %>%sort_at_path(path =c("SMQ"), scorefun = cont_n_allcols) %>%sort_at_path(path =c("SMQ", "*", "AEDECOD"), scorefun = score_occurrences, na.pos ="last") %>%trim_rows(criteria = criteria_fun)result
ARM A ARM B ARM C
Standardized MedDRA Query F M F M F M
Dictionary-Derived Term (N=79) (N=55) (N=82) (N=52) (N=70) (N=62)
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
Total number of patients with at least one adverse event 47 (59.5%) 25 (45.5%) 51 (62.2%) 28 (53.8%) 42 (60.0%) 33 (53.2%)
C.1.1.1.3/B.2.2.3.1 AESI(BROAD)
Total number of patients with at least one adverse event 47 (59.5%) 25 (45.5%) 51 (62.2%) 28 (53.8%) 42 (60.0%) 33 (53.2%)
Total number of events 79 40 95 44 81 60
dcd B.2.2.3.1 30 (38.0%) 18 (32.7%) 32 (39.0%) 22 (42.3%) 26 (37.1%) 25 (40.3%)
dcd C.1.1.1.3 30 (38.0%) 13 (23.6%) 36 (43.9%) 10 (19.2%) 27 (38.6%) 16 (25.8%)
Experimental use!
WebR is a tool allowing you to run R code in the web browser. Modify the code below and click run to see the results. Alternatively, copy the code and click here to open WebR in a new tab.
criteria_fun <-function(tr) {!is(tr, "ContentRow") &&all_zero_or_na(tr) &&!grepl("Total number of", obj_label(tr))}lyt <-basic_table(show_colcounts =TRUE) %>%split_cols_by("ACTARMCD") %>%split_cols_by("SEX") %>%analyze_num_patients(vars ="USUBJID",.stats =c("unique"),.labels =c(unique ="Total number of patients with at least one adverse event") ) %>%split_rows_by("SMQ",child_labels ="visible",nested =FALSE,split_fun =trim_levels_in_group("AEDECOD", drop_outlevs =FALSE),label_pos ="topleft",split_label ="Standardized MedDRA Query" ) %>%analyze_num_patients(vars ="USUBJID",.stats =c("unique", "nonunique"),.labels =c(unique ="Total number of patients with at least one adverse event",nonunique ="Total number of events" ),show_labels ="hidden" ) %>%count_occurrences(vars ="AEDECOD", drop =FALSE) %>%append_varlabels(adae_smq_all, "AEDECOD", indent =1L)score_ae_pts <-function(tt) { count_vals <-cell_values(tree_children(tt)[["USUBJID"]])[[1]]sum(matrix(unlist(count_vals), nrow =length(count_vals), byrow =TRUE)[, 1])}result <-build_table(lyt = lyt,df = adae_smq_all,alt_counts_df = adsl) %>%sort_at_path(path =c("SMQ"), scorefun = score_ae_pts) %>%sort_at_path(path =c("SMQ", "*", "AEDECOD"), scorefun = score_occurrences, na.pos ="last") %>%trim_rows(criteria = criteria_fun)result
ARM A ARM B ARM C
Standardized MedDRA Query F M F M F M
Dictionary-Derived Term (N=79) (N=55) (N=82) (N=52) (N=70) (N=62)
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
Total number of patients with at least one adverse event 59 (74.7%) 36 (65.5%) 68 (82.9%) 35 (67.3%) 61 (87.1%) 47 (75.8%)
D.2.1.5.3/A.1.1.1.1 AESI
Total number of patients with at least one adverse event 45 (57.0%) 29 (52.7%) 54 (65.9%) 26 (50.0%) 50 (71.4%) 37 (59.7%)
Total number of events 78 48 91 43 88 74
dcd D.2.1.5.3 26 (32.9%) 21 (38.2%) 40 (48.8%) 18 (34.6%) 34 (48.6%) 23 (37.1%)
dcd A.1.1.1.1 34 (43.0%) 16 (29.1%) 31 (37.8%) 14 (26.9%) 33 (47.1%) 30 (48.4%)
C.1.1.1.3/B.2.2.3.1 AESI(BROAD)
Total number of patients with at least one adverse event 47 (59.5%) 25 (45.5%) 51 (62.2%) 28 (53.8%) 42 (60.0%) 33 (53.2%)
Total number of events 79 40 95 44 81 60
dcd B.2.2.3.1 30 (38.0%) 18 (32.7%) 32 (39.0%) 22 (42.3%) 26 (37.1%) 25 (40.3%)
dcd C.1.1.1.3 30 (38.0%) 13 (23.6%) 36 (43.9%) 10 (19.2%) 27 (38.6%) 16 (25.8%)
non observed SMQ02NAM level(BROAD)
Total number of patients with at least one adverse event 0 0 0 0 0 0
Total number of events 0 0 0 0 0 0
Experimental use!
WebR is a tool allowing you to run R code in the web browser. Modify the code below and click run to see the results. Alternatively, copy the code and click here to open WebR in a new tab.
criteria_fun <-function(tr) !is(tr, "ContentRow") &&all_zero_or_na(tr)lyt <-basic_table(show_colcounts =TRUE) %>%split_cols_by("ACTARMCD") %>%split_cols_by("AGE65") %>%analyze_num_patients(vars ="USUBJID",.stats =c("unique"),.labels =c(unique ="Total number of patients with at least one adverse event") ) %>%split_rows_by("SMQ",child_labels ="visible",nested =FALSE,split_fun =trim_levels_in_group("AEDECOD", drop_outlevs =FALSE),label_pos ="topleft",split_label ="Standardized MedDRA Query" ) %>%summarize_num_patients(var ="USUBJID",.stats =c("unique", "nonunique"),.labels =c(unique ="Total number of patients with at least one adverse event",nonunique ="Total number of events" ) ) %>%count_occurrences(vars ="AEDECOD", drop =FALSE) %>%append_varlabels(adae_smq_1, "AEDECOD", indent =1L)result <-build_table(lyt = lyt,df = adae_smq_1,alt_counts_df = adsl) %>%sort_at_path(path =c("SMQ"), scorefun = cont_n_allcols) %>%sort_at_path(path =c("SMQ", "*", "AEDECOD"), scorefun = score_occurrences, na.pos ="last") %>%trim_rows(criteria = criteria_fun)result
ARM A ARM B ARM C
Standardized MedDRA Query < 65 >= 65 < 65 >= 65 < 65 >= 65
Dictionary-Derived Term (N=134) (N=0) (N=134) (N=0) (N=131) (N=1)
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
Total number of patients with at least one adverse event 72 (53.7%) 0 79 (59.0%) 0 75 (57.3%) 0
C.1.1.1.3/B.2.2.3.1 AESI(BROAD)
Total number of patients with at least one adverse event 72 (53.7%) 0 79 (59.0%) 0 75 (57.3%) 0
Total number of events 119 0 139 0 141 0
dcd B.2.2.3.1 48 (35.8%) 0 54 (40.3%) 0 51 (38.9%) 0
dcd C.1.1.1.3 43 (32.1%) 0 46 (34.3%) 0 43 (32.8%) 0
Experimental use!
WebR is a tool allowing you to run R code in the web browser. Modify the code below and click run to see the results. Alternatively, copy the code and click here to open WebR in a new tab.
Code
library(dplyr)library(tern)library(stringr)adsl <- random.cdisc.data::cadsladae <- random.cdisc.data::cadaeadsl_labels <-var_labels(adsl)adae_labels <-var_labels(adae)adsl <- adsl %>%mutate(AGE65 =case_when( AGE >=65~">= 65",TRUE~"< 65" ),AGE65 =factor( AGE65,levels =c("< 65", ">= 65") ) )adae <- adae %>%mutate(AGE65 =case_when( AGE >=65~">= 65",TRUE~"< 65" ),AGE65 =factor( AGE65,levels =c("< 65", ">= 65") ) )# Ensure character variables are converted to factors and empty strings and NAs are explicit missing# levels. For details, refer to Teal and Study Data article.adsl <-df_explicit_na(adsl)adae <-df_explicit_na(adae)# Simulate a random AAG dataset.aag <-data.frame(NAMVAR =c("SMQ01NAM", "SMQ01NAM", "SMQ02NAM", "CQ01NAM", "CQ01NAM"),SRCVAR =rep("AEDECOD", 5),GRPTYPE =c("SMQ", "SMQ", "SMQ", "CUSTOM", "CUSTOM"),REFID =c(1, 1, 2, 3, 3),REFNAME =c(rep("C.1.1.1.3/B.2.2.3.1 AESI", 2), "non observed SMQ02NAM level", rep("D.2.1.5.3/A.1.1.1.1 AESI", 2)),SCOPE =c("BROAD", "BROAD", "BROAD", "", ""),REFTERM =c("C.1.1.1.3", "B.2.2.3.1", "Z.9.9.9.9", "D.2.1.5.3", "A.1.1.1.1"),stringsAsFactors =FALSE)# Create summary AAG dataset (used for labelling).# Note it's important to incorporate SCOPE into the basket names for SMQs so as to# match the flags present in ADAE.aag_summary <- aag %>%select(NAMVAR, REFNAME, SCOPE) %>%unique() %>%mutate(REFNAME_SCOPE =ifelse(SCOPE =="", REFNAME, paste0(REFNAME, "(", SCOPE, ")")) ) %>%rename(basket = NAMVAR, basket_name = REFNAME_SCOPE) %>%select(basket, basket_name)# Make a summary of the full ADAE based on AAG by using h_stack_by_baskets helper functionadae_smq_all <-h_stack_by_baskets(df = adae,aag_summary = aag_summary,keys =c("STUDYID", "USUBJID", "ACTARMCD", "AEDECOD", "SEX", "AGE65"))# Post-process adae_smq_all to keep only certain baskets of interest for variant 1# Not need to drop baskets for variant 2 as all baskets will be considered.baskets_to_drop_variant <- aag_summary$basket_name[!aag_summary$basket %in%c("SMQ01NAM")]# Adjust the analysis dataset based on basket subset for variant 1.adae_smq_1 <- adae_smq_all %>%filter(!adae_smq_all$SMQ %in% baskets_to_drop_variant) %>%mutate(SMQ = tern::fct_discard(SMQ, discard = baskets_to_drop_variant) )
shinylive allow you to modify to run shiny application entirely in the web browser. Modify the code below and click re-run the app to see the results. The performance is slighly worse and some of the features (e.g. downloading) might not work at all.