# Program Name: tsfecg05# Prep Environmentlibrary(envsetup)library(tern)library(dplyr)library(rtables)library(junco)# Define script level parameters:tblid <-"TSFECG05"fileid <- tblidtitles <-get_titles_from_file(input_path ='../../_data/', tblid)string_map <- default_str_mappopfl <-"SAFFL"trtvar <-"TRT01A"ctrl_grp <-"Placebo"ad_domain <-"adeg"selvisit <-c("Month 1","Month 3","Month 6","Month 9","Month 12","Month 15","Month 18","Month 24")selvisit <-c("Month 1", "Month 3")catvar <-c("CRIT1", "CRIT2")# initial read of dataadeg_complete <- pharmaverseadamjnj::adeg## check parameters that have CRIT1,CRIT2 defined in datalevels_data <-unique(adeg_complete %>%select(PARAMCD, PARAM, CRIT1, CRIT2))# restrict to theseselparamcd <-as.character(unique( levels_data %>%filter(!(is.na(CRIT1) |is.na(CRIT2))) %>%pull(PARAMCD)))## if the option TRTEMFL needs to be added to the TLFtrtemfl <-TRUE# Mapping for CRIT1/2xlabel_map <- levels_data %>% tidyr::pivot_longer(cols =c("CRIT1", "CRIT2"),names_to ="var",values_to ="label" ) %>%filter(!is.na(label)) %>%mutate(label =as.character(label),var =paste0(var, "FL"),value ="Y" )#### Note: this is not in line with the markedly abnormal file## for both EGHRMN & PRAG: crit1 and crit2 are reversed## crit1 and crit2 on data are consistent with the order specified in the shell : low/high# Process Data:adsl <- pharmaverseadamjnj::adsl %>%filter(.data[[popfl]] =="Y") %>%select(USUBJID, all_of(c(trtvar, popfl)))adsl$colspan_trt <-factor(ifelse(adsl[[trtvar]] == ctrl_grp, " ", "Active Study Agent"),levels =c("Active Study Agent", " "))adsl$rrisk_header <-"Risk Difference (%) (95% CI)"adsl$rrisk_label <-paste(adsl[[trtvar]], paste("vs", ctrl_grp))adeg <- adeg_complete %>%filter(PARAMCD %in% selparamcd) %>%select( USUBJID, PARAM, PARAMCD, AVISIT, AVAL, CRIT1, CRIT1FL, CRIT2, CRIT2FL,starts_with("ANL") &ends_with("FL"), ONTRTFL, TRTEMFL, APOBLFL ) %>%inner_join(., adsl)# filter data### alert on trtemfl, do not apply it as a filter, as this would lead to incorrect denominatorsadeg_crit_any <-unique( adeg %>%# synthetic data is missing the ANL04FL variable, however, this wouldn't be sufficient either, unless it flags both CRIT1 and CRIT2filter(ONTRTFL =="Y") %>%mutate(AVISIT =factor("On-treatment")) %>%select(-c(AVAL, ANL01FL, ANL02FL, ANL03FL)))### note: this does not necesarily leads to one record per parameter per subject### if ANL04FL is available, we still can end up with more than one record### a subject can have crit1fl=Y at one visit, and crit2fl=Y at another visit, and crit1fl=N&crit2fl=N at another### as long as the analysis function deals with multiple records per subject correctly, this is not an issuecheck_dup_sub <- adeg_crit_any %>%group_by(USUBJID, PARAMCD, AVISIT) %>%mutate(n_rec =n()) %>%filter(n_rec >1)# Over time is also restricted to on treatment valueadeg_crit_overtime <- adeg %>%filter(ANL02FL =="Y"& AVISIT %in% selvisit & ONTRTFL =="Y") %>%select(-c(AVAL, ANL01FL, ANL02FL, ANL03FL))adeg_crit_comb <-rbind(adeg_crit_any, adeg_crit_overtime) %>%mutate(AVISIT =factor(as.character(AVISIT),levels =c("On-treatment", levels(adeg_crit_overtime$AVISIT)) ) ) %>%inner_join(., adsl)#### DO NOT USE TRTEMFL = Y in filter, as this will remove subjects from both numerator and denominator#### instead : set "CRIT2FL","CRIT1FL" to a non-reportable value (ie N) and keep in datasetif (trtemfl) { adeg_crit_comb <- adeg_crit_comb %>%mutate(CRIT1FL =case_when(is.na(TRTEMFL) | TRTEMFL !="Y"~"N",TRUE~ CRIT1FL ),CRIT2FL =case_when(is.na(TRTEMFL) | TRTEMFL !="Y"~"N",TRUE~ CRIT2FL ) )}adeg_crit_comb <- adeg_crit_comb %>%mutate(CRIT1FL =factor(CRIT1FL, levels =c("Y", "N")),CRIT2FL =factor(CRIT2FL, levels =c("Y", "N")) )colspan_trt_map <-create_colspan_map( adsl,non_active_grp = ctrl_grp,non_active_grp_span_lbl =" ",active_grp_span_lbl ="Active Study Agent",colspan_var ="colspan_trt",trt_var = trtvar)# Define layout and build table:extra_args_rr1 <-list(method ="wald", denom ="n_df", .stats =c("n_df"))extra_args_rr2 <-list(method ="wald",denom ="n_df",.stats =c("count_unique_fraction"))lyt <-basic_table(show_colcounts =TRUE, colcount_format ="N=xx") %>%split_cols_by("colspan_trt",split_fun =trim_levels_to_map(map = colspan_trt_map) ) %>%split_cols_by( trtvar# , split_fun = add_combo_levels(combodf) ) %>%# re-enable the below if relative risk columns are wanted# split_cols_by("rrisk_header", nested = FALSE) %>%# split_cols_by(trtvar, labels_var = "rrisk_label",# split_fun = remove_split_levels(ctrl_grp)) %>%#split_rows_by("PARAM",split_label ="Parameter",label_pos ="topleft",split_fun = drop_split_levels ) %>%split_rows_by("AVISIT",split_label ="Study Visit",label_pos ="topleft",section_div =" ",split_fun = drop_split_levels ) %>%analyze(c("CRIT1"), a_freq_j,extra_args = extra_args_rr1,show_labels ="hidden",indent_mod =0L ) %>%# denominators are varying per test, no need to show as N is shown in line above# revise order to first present low then highanalyze(c("CRIT2FL", "CRIT1FL"), a_freq_j,extra_args =append( extra_args_rr2,list(val =c("Y"),label_map = xlabel_map ) ),show_labels ="hidden",indent_mod =1L ) %>%append_topleft(" Criteria, n (%)")result <-build_table(lyt, adeg_crit_comb, alt_counts_df = adsl)# Add titles and footnotes:result <-set_titles(result, titles)# Convert to tbl file and output tablett_to_tlgrtf(string_map = string_map, tt = result, file = fileid)
TSFECG05:Subjects With ECG Values Outside Specified Limits Based on On-treatment Value and Over Time; Safety Analysis Set (Study jjcs - core)
Parameter
Active Study Agent
Study Visit
Xanomeline High Dose
Xanomeline Low Dose
Placebo
Criteria, n (%)
N=53
N=73
N=59
ECG Mean Heart Rate (beats/min)
On-treatment
N
53
71
58
>100
53 (100.0%)
67 (100.0%)
57 (100.0%)
<50
25 (100.0%)
22 (100.0%)
24 (100.0%)
Month 1
N
53
71
58
>100
36 (100.0%)
57 (100.0%)
45 (100.0%)
<50
11 (100.0%)
6 (100.0%)
8 (100.0%)
Month 3
N
53
53
56
>100
42 (100.0%)
43 (100.0%)
45 (100.0%)
<50
7 (100.0%)
7 (100.0%)
3 (100.0%)
PR Interval, Aggregate (msec)
On-treatment
N
53
71
58
>200
53 (100.0%)
67 (100.0%)
54 (100.0%)
<120
34 (100.0%)
43 (100.0%)
47 (100.0%)
Month 1
N
53
71
58
>200
39 (100.0%)
46 (100.0%)
35 (100.0%)
<120
6 (100.0%)
17 (100.0%)
13 (100.0%)
Month 3
N
53
53
56
>200
34 (100.0%)
33 (100.0%)
33 (100.0%)
<120
9 (100.0%)
10 (100.0%)
14 (100.0%)
Note: On-treatment is defined as treatment-emergentECG values obtained after the first dose and within [30 days] following treatment discontinuation. [Treatment-emergent values are those that worsened from baseline.]
Note: Specified limits are defined in the Statistical Analysis Plan. N is the number of subjects with at least 1 postbaseline value for the specified ECG parameter.