# Program Name: tsflab03# Prep Environmentlibrary(envsetup)library(tern)library(dplyr)library(rtables)library(junco)# Define script level parameters:tblid <-"TSFLAB03"fileid <- tblidtitles <-get_titles_from_file(input_path ='../../_data/', tblid)string_map <- default_str_mappopfl <-"SAFFL"trtvar <-"TRT01A"ctrl_grp <-"Placebo"## if the option TRTEMFL needs to be added to the TLFtrtemfl <-TRUE## For analysis on SI units: use adlb dataset## For analysis on Conventional units: use adlbc dataset -- shell is in conventional unitsad_domain <-"ADLB"# Initial processing of data + check if table is valid for trial:adlb_complete <- pharmaverseadamjnj::adlb## parcat5 and 6 options :availparcat56 <-c("Investigations","Metabolism and nutritional disorders","Renal and urinary disorders","Blood and lymphatic system disorders")## resrict to someselparcat56 <- availparcat56[c(1, 2, 4)]## get allselparcat56 <- availparcat56lbtoxgrade_file <-file.path('../../_data', "lbtoxgrade.xlsx")lbtoxgrade_sheets <- readxl::excel_sheets(path = lbtoxgrade_file)### CTC5 or DAIDS21c : default CTC5lbtoxgrade_defs <- readxl::read_excel(lbtoxgrade_file, sheet ="CTC5")lbtoxgrade_defs <-unique( lbtoxgrade_defs %>%select(TOXTERM, TOXGRD, INDICATR)) %>%mutate(ATOXDSCLH = TOXTERM,ATOXGRLH =paste("Grade", TOXGRD) ) %>%rename(ATOXDIR = INDICATR) %>%select(ATOXDSCLH, ATOXGRLH, ATOXDIR)# Process Data:adsl <- pharmaverseadamjnj::adsl %>%filter(.data[[popfl]] =="Y") %>%select(USUBJID, all_of(c(popfl, trtvar)))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))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)adlb00 <- adlb_complete %>%select( USUBJID, AVISITN, AVISIT,starts_with("PAR"),starts_with("ATOX"),starts_with("ANL"), ONTRTFL, TRTEMFL, AVAL, APOBLFL, ABLFL, LVOTFL ) %>%inner_join(adsl) %>%mutate(ATOXGRL =as.character(ATOXGRL),ATOXGRH =as.character(ATOXGRH) ) %>%relocate( ., USUBJID, ANL04FL, ANL05FL, ONTRTFL, TRTEMFL, AVISIT, ATOXGRL, ATOXGRH, ATOXDSCL, ATOXDSCH, PARAMCD, AVISIT, AVAL, APOBLFL, ABLFL )# adlb00 <- adlb00 #%>%## APT comment on PARCAT6 :## HGB and WBC : Set to "Blood and lymphatic system disorders".## HGB and WBC parameter are in 2 categories, one for the high and another one for the low direction grading.## Anemia (HGB low) and Leukocytosis (WBC high) are in the category "Blood and lymphatic system disorders".## The grading in the opposite directions are categorized under "Investigations".## Therefor, both PARCAT5 and PARCAT6 are populated for HGB abd WBC.## Deal with what is needed at later level, when we have splitted low and high# mutate(PARCAT56 = coalesce(PARCAT6,PARCAT5)) %>%# mutate(PARCAT56 = factor(PARCAT56,levels=unique(c(levels(adlb_complete$PARCAT6),levels(adlb_complete$PARCAT5)))))# obj_label(adlb00$PARCAT56) <- "Combined PARCAT56"### important: previous actions lost the label of variablesadlb00 <-var_relabel_list(adlb00, var_labels(adlb_complete, fill = T))parcat <-unique( adlb00 %>%select(starts_with("PARCAT"), PARAMCD, PARAM, ATOXDSCL, ATOXDSCH) %>%filter(!(is.na(PARCAT5) &is.na(PARCAT6))))### data preparationif (all(selparcat56 !="")) { filtered_adlb <- adlb00 %>%filter((PARCAT5 %in% selparcat56) | (PARCAT6 %in% selparcat56))}### low grades : ATOXDSCL ATOXGRL ANL04FL### Note on Worst On-treatment### note: by filter ANL04FL/ANL05FL, this table is restricted to On-treatment values, per definition of ANL04FL/ANL05FL### therefor, no need to add ONTRTFL in filter### if derivation of ANL04FL/ANL05FL is not restricted to ONTRTFL records, adding ONTRTFL here will not give the correct answer either### as mixing worst with other period is not giving the proper selection !!!filtered_adlb_low <- filtered_adlb %>%filter(ANL04FL =="Y"&!is.na(ATOXDSCL) &!is.na(ATOXGRL)) %>%mutate(ATOXDSCLH = ATOXDSCL,ATOXGRLH = ATOXGRL,ATOXDIR ="LOW" ) %>%select(USUBJID, starts_with("PAR"), starts_with("ATOX"), TRTEMFL) %>%select(-c(ATOXGRL, ATOXGRH, ATOXDSCL, ATOXDSCH))### high grades: ATOXDSCH ATOXGRH ANL05FLfiltered_adlb_high <- filtered_adlb %>%filter(ANL05FL =="Y"&!is.na(ATOXDSCH) &!is.na(ATOXGRH)) %>%mutate(ATOXDSCLH = ATOXDSCH,ATOXGRLH = ATOXGRH,ATOXDIR ="HIGH" ) %>%select(USUBJID, starts_with("PAR"), starts_with("ATOX"), TRTEMFL) %>%select(-c(ATOXGRL, ATOXGRH, ATOXDSCL, ATOXDSCH))## combine Low and high into adlb_toxfiltered_adlb_tox <-bind_rows( filtered_adlb_low, filtered_adlb_high ) %>%select(-c(ATOXGR, ATOXGRN)) %>%inner_join(adsl)### correction of proper category (PARCAT56) for HGB (LOW) and WBC (HIGH)filtered_adlb_tox <- filtered_adlb_tox %>%mutate(PARCAT56 =case_when( PARAMCD =="HGB"& ATOXDIR =="LOW"~ PARCAT6, PARAMCD =="WBC"& ATOXDIR =="HIGH"~ PARCAT6,### fix on synthetic data !!!! PARAMCD =="WBC"& ATOXDIR =="LOW"~"Investigations",TRUE~ PARCAT5 ) ) %>%mutate(PARCAT56 =factor( PARCAT56,levels =unique(c("Blood and lymphatic system disorders",levels(adlb_complete$PARCAT5) )) ) )#### DO NOT USE TRTEMFL = Y in filter, as this will remove subjects from both numerator and denominator#### instead : set ATOXGRLH to a non-reportable value (ie Grade 0) and keep in datasetif (trtemfl) { filtered_adlb_tox <- filtered_adlb_tox %>%mutate(ATOXGRLH =case_when(is.na(TRTEMFL) | TRTEMFL !="Y"~"0",TRUE~ ATOXGRLH ) )}## convert some to factors -- lty will fail if these are not factorsfiltered_adlb_tox <- filtered_adlb_tox %>%mutate(ATOXGRLH =factor(paste("Grade", ATOXGRLH), levels =paste("Grade", 0:5)),ATOXDIR =factor(ATOXDIR, levels =c("LOW", "HIGH")) )filtered_adlb_tox <-unique( filtered_adlb_tox)check_non_unique_subject <- filtered_adlb_tox %>%group_by(USUBJID, PARAMCD, ATOXDSCLH) %>%summarize(n_subject =n()) %>%filter(n_subject >1)if (nrow(check_non_unique_subject)) {message("Please review your data selection process, subject has multiple records" )}params <-unique( filtered_adlb_tox %>%select(PARCAT56, PARAMCD, PARAM, ATOXDSCLH, ATOXDIR))all_params <-unique( adlb_complete %>%filter(!(is.na(PARCAT5) &is.na(PARCAT6))) %>%select(PARCAT5, PARCAT6, PARAMCD, PARAM, ATOXDSCL, ATOXDSCH))### add relevant extra vars to lbtoxgrade_defs, only restrict to those actually in triallbtoxgrade_defs <- lbtoxgrade_defs %>%inner_join( .,unique( filtered_adlb_tox %>%select(PARAMCD, PARAM, ATOXDIR, ATOXDSCLH, PARCAT5, PARCAT6, PARCAT56) ),relationship ="many-to-many" )### Define param_map to be used in layoutparam_map <- lbtoxgrade_defs %>%select(PARCAT56, PARAM, PARAMCD, ATOXDIR, ATOXDSCLH, ATOXGRLH) %>%### for proper sorting: add factor levels to PARAMCD, ATOXDIRmutate(PARAMCD =factor(PARAMCD, levels =levels(adlb00$PARAMCD)),ATOXDIR =factor(ATOXDIR, levels =c("LOW", "HIGH")) ) %>%# ### actual sorting# arrange(PARCAT56,PARAMCD,ATOXDIR,ATOXGRLH) %>%### actual sorting -- all alphabetic on outputarrange(PARCAT56, ATOXDSCLH) %>%### !!!! no factors are allowed in this split_fun map definitionmutate(PARCAT56 =as.character(PARCAT56),PARAMCD =as.character(PARAMCD),PARAM =as.character(PARAM),ATOXDIR =as.character(ATOXDIR),ATOXDSCLH =as.character(ATOXDSCLH) ) # %>%### !!!! do not remove Grade 0 here, as this would lead to incorrect N and % derivation### filter(ATOXGRLH != "Grade 0")### Grade 0 will be removed as a post-processing step# Define layout and build table:ref_path <-c("colspan_trt", " ", trtvar, ctrl_grp)extra_args_rr <-list(method ="wald",denom ="n_df",ref_path = ref_path,.stats =c("denom", "count_unique_fraction"))extra_args_rr2 <-list(method ="wald",denom ="n_df",ref_path = ref_path,.stats =c("denom", "count_unique_denom_fraction"))lyt0 <-basic_table(show_colcounts =TRUE, colcount_format ="N=xx") %>%### first columnssplit_cols_by("colspan_trt",split_fun =trim_levels_to_map(map = colspan_trt_map) ) %>%split_cols_by(trtvar) %>%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("PARCAT56",label_pos ="topleft",child_labels ="visible",split_label ="NCI-CTCAE Category",### trim_levels_to_map needs to be applied at ALL split_rows_by levelssplit_fun =trim_levels_to_map(param_map),section_div =" " ) %>%split_rows_by("ATOXDSCLH",label_pos ="topleft",child_labels ="visible",split_label ="Laboratory Test",### trim_levels_to_map needs to be applied at ALL split_rows_by levelssplit_fun =trim_levels_to_map(param_map),section_div =" " ) %>%append_topleft(" Grade, n (%)")# version without explicit denominator (as in shell)lyt <- lyt0 %>%# for testing, it is sometimes convenient to explicitely show the used denominatoranalyze("ATOXGRLH", a_freq_j,extra_args = extra_args_rr,show_labels ="hidden",indent_mod =0L )result <-build_table(lyt, filtered_adlb_tox, alt_counts_df = adsl)# version with explicit denominator (for verification)lyt2 <- lyt0 %>%# for testing, it is sometimes convenient to explicitely show the used denominatoranalyze("ATOXGRLH", a_freq_j,extra_args = extra_args_rr2,show_labels ="visible",indent_mod =0L )### apply layoutresult2 <-build_table(lyt2, filtered_adlb_tox, alt_counts_df = adsl)# Post-Processing:remove_grade0 <-function(tr) {if (is(tr, "DataRow") & (tr@label =="Grade 0")) {return(FALSE) } else {return(TRUE) }}result <- result %>%prune_table(prune_func =keep_rows(remove_grade0))result2 <- result2 %>%prune_table(prune_func =keep_rows(remove_grade0))# Remove colcount from rrisk_header:result <-remove_col_count(result)result2 <-remove_col_count(result2)# 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, orientation ="landscape")
TSFLAB03:Subjects With =1 Laboratory Values With Elevated or Low Values Based on Worst On-treatment Value Using NCI-CTCAE Criteria; Safety Analysis Set (Study jjcs - core)
NCI-CTCAE Category
Active Study Agent
Risk Difference (%) (95% CI)
Laboratory Test
Xanomeline High Dose
Xanomeline Low Dose
Placebo
Xanomeline High Dose vs Placebo
Xanomeline Low Dose vs Placebo
Grade, n (%)
N=53
N=73
N=59
Blood and lymphatic system disorders
Anemia
N
53
73
59
Grade 1
29 (54.7%)
42 (57.5%)
35 (59.3%)
-4.6 (-23.0, 13.7)
-1.8 (-18.7, 15.1)
Grade 2
16 (30.2%)
24 (32.9%)
23 (39.0%)
-8.8 (-26.3, 8.7)
-6.1 (-22.6, 10.4)
Grade 3
12 (22.6%)
18 (24.7%)
13 (22.0%)
0.6 (-14.8, 16.1)
2.6 (-11.9, 17.1)
Leukocytosis
N
53
73
59
Grade 3
0
0
0
0.0 (0.0, 0.0)
0.0 (0.0, 0.0)
Metabolism and nutritional disorders
Hyperkalemia
N
53
73
59
Grade 1
1 (1.9%)
0
0
1.9 (-1.8, 5.5)
0.0 (0.0, 0.0)
Grade 2
0
0
1 (1.7%)
-1.7 (-5.0, 1.6)
-1.7 (-5.0, 1.6)
Grade 3
0
0
0
0.0 (0.0, 0.0)
0.0 (0.0, 0.0)
Grade 4
0
0
0
0.0 (0.0, 0.0)
0.0 (0.0, 0.0)
Hypernatremia
N
53
73
59
Grade 1
6 (11.3%)
5 (6.8%)
9 (15.3%)
-3.9 (-16.5, 8.6)
-8.4 (-19.3, 2.4)
Grade 2
1 (1.9%)
0
0
1.9 (-1.8, 5.5)
0.0 (0.0, 0.0)
Grade 3
0
0
0
0.0 (0.0, 0.0)
0.0 (0.0, 0.0)
Grade 4
0
0
0
0.0 (0.0, 0.0)
0.0 (0.0, 0.0)
Hypoalbuminemia
N
53
73
59
Grade 1
37 (69.8%)
32 (43.8%)
40 (67.8%)
2.0 (-15.2, 19.2)
-24.0 (-40.4, -7.5)
Grade 2
23 (43.4%)
21 (28.8%)
25 (42.4%)
1.0 (-17.3, 19.4)
-13.6 (-29.9, 2.7)
Grade 3
11 (20.8%)
10 (13.7%)
15 (25.4%)
-4.7 (-20.2, 10.9)
-11.7 (-25.4, 1.9)
Hypoglycemia
N
53
72
59
Grade 1
30 (56.6%)
33 (45.8%)
37 (62.7%)
-6.1 (-24.3, 12.1)
-16.9 (-33.8, -0.0)
Grade 2
25 (47.2%)
23 (31.9%)
23 (39.0%)
8.2 (-10.1, 26.5)
-7.0 (-23.5, 9.4)
Grade 3
12 (22.6%)
17 (23.6%)
15 (25.4%)
-2.8 (-18.6, 13.0)
-1.8 (-16.6, 13.0)
Grade 4
0
1 (1.4%)
1 (1.7%)
-1.7 (-5.0, 1.6)
-0.3 (-4.6, 4.0)
Hypokalemia
N
53
73
58
Grade 2
20 (37.7%)
23 (31.5%)
20 (34.5%)
3.3 (-14.6, 21.1)
-3.0 (-19.2, 13.2)
Grade 3
11 (20.8%)
11 (15.1%)
15 (25.9%)
-5.1 (-20.8, 10.6)
-10.8 (-24.7, 3.1)
Grade 4
2 (3.8%)
4 (5.5%)
2 (3.4%)
0.3 (-6.6, 7.3)
2.0 (-5.0, 9.1)
Hyponatremia
N
53
71
59
Grade 1
36 (67.9%)
40 (56.3%)
40 (67.8%)
0.1 (-17.2, 17.5)
-11.5 (-28.0, 5.1)
Grade 3
16 (30.2%)
14 (19.7%)
12 (20.3%)
9.8 (-6.2, 25.9)
-0.6 (-14.4, 13.2)
Grade 4
3 (5.7%)
0
0
5.7 (-0.6, 11.9)
0.0 (0.0, 0.0)
Note: On-treatment is defined as treatment-emergentlaboratory values obtained after the first dose and within [30 days] following treatment discontinuation. [Treatment-emergent values are those that worsened from baseline.]
Note: NCI-CTCAE grades (version 5.0.) are based on the laboratory result and do not take into account the clinical component, if applicable.