From 627c028a12be4f1daa322fb294d64596dadc265e Mon Sep 17 00:00:00 2001 From: Jim Coates Date: Thu, 10 Oct 2024 08:09:10 -0400 Subject: [PATCH 1/3] Create t_dm1.sas --- prod/tfl/t_dm1.sas | 371 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 prod/tfl/t_dm1.sas diff --git a/prod/tfl/t_dm1.sas b/prod/tfl/t_dm1.sas new file mode 100644 index 0000000..9ff44de --- /dev/null +++ b/prod/tfl/t_dm1.sas @@ -0,0 +1,371 @@ +/*****************************************************************************\ +* ____ _ +* | _ \ ___ _ __ ___ (_)_ __ ___ +* | | | |/ _ \| '_ ` _ \| | '_ \ / _ \ +* | |_| | (_) | | | | | | | | | | (_) | +* |____/ \___/|_| |_| |_|_|_| |_|\___/ +* ____________________________________________________________________________ +* Sponsor : Domino +* Study : CDISC01 +* Program : t_ae_rel.sas +* Purpose : Create the Treatment Emergent Adverse Events Table +* ____________________________________________________________________________ +* DESCRIPTION +* +* Input files: ADaM.ADSL +* ADaM.ADAE +* +* Output files: t_ae_rel.pdf +* t_ae_rel.sas7bdat +* +* Macros: tfl_metadata.sas +* +* Assumptions: test +* +* ____________________________________________________________________________ +* PROGRAM HISTORY +* 24MAY2022 | Jake Tombeur | Original version +* 10MAY2023 | Megan Harries | Updates for CDISC01 ADaMs +* ---------------------------------------------------------------------------- +\*****************************************************************************/ + +*********; +** Setup environment including libraries for this reporting effort; +%include "/mnt/code/domino.sas"; +*********; + +ods path(prepend) work.templat(update); + +*Set the template for the output; +proc template; + define style newstyle; + + class Table / + Rules = Groups + Frame = void; + + style header + / just = c + fontweight = medium; + + replace Body from Document / + bottommargin = 1.54cm + topmargin = 2.54cm + rightmargin = 2.54cm + leftmargin = 2.54cm; + + replace fonts / + 'TitleFont2' = ("Courier New",9pt) + 'TitleFont' = ("Courier New",9pt/*,Bold*/) /* titles */ + 'StrongFont' = ("Courier New",9pt/*,Bold*/) + 'EmphasisFont' = ("Courier New",9pt,Italic) + 'FixedEmphasisFont' = ("Courier New, Courier",9pt,Italic) + 'FixedStrongFont' = ("Courier New, Courier",9pt/*,Bold*/) + 'FixedHeadingFont' = ("Courier New, Courier",9pt/*,Bold*/) + 'BatchFixedFont' = ("SAS Monospace, Courier New, Courier",9pt) + 'FixedFont' = ("Courier New, Courier",9pt) + 'headingEmphasisFont' = ("Courier New",9pt,Bold Italic) + 'headingFont' = ("Courier New",9pt/*,Bold*/) /* header block */ + 'docFont' = ("Courier New",9pt); /* table cells */ + + replace color_list + "Colors used in the default style" / + 'link' = blue + 'bgH' = white /* header background */ + 'fg' = black + 'bg' = _undef_; +end; +run ; + +options orientation = landscape nonumber nodate nobyline; + +proc format; + picture pctmf (round default = 8) /* Picture format for percentages */ + . = ' ' (noedit) + low-0.001 = ' ' (noedit) + 0.001-<0.1 = ' (<0.1%)' (noedit) + 0.1-<1 = ' (9.9%)' (prefix=' (') + 1-<99.90001 = ' (00.0%)' (prefix=' (') + 99.90001-<100 = '(>99.9%)' (noedit) + 100 = '(100%) ' (noedit) + ; +run; + +data teae (rename = (actarm = trta)); + length relcat $20; + set adam.adae; + + if aerel in ('POSSIBLE' 'PROBABLE' 'DEFINITE') then relcat = 'Related'; + else relcat = 'Not Related'; + + if actarm = "Placebo" then trtan = 1; + else if actarm = "Xanomeline Low Dose" then trtan = 2; + else if actarm = "Xanomeline High Dose" then trtan = 3; +run; + +** exclude non-treated subjects; +data adsl1 (rename = (actarm = trta) where = (trtan ^= .)); + set adam.adsl; + + if actarm = "Placebo" then trtan = 1; + else if actarm = "Xanomeline Low Dose" then trtan = 2; + else if actarm = "Xanomeline High Dose" then trtan = 3; +run; + +%let indat = teae; +%let trtvarn = trtan; +%let inadsl = adsl1; +%let socvar = aesoc; +%let ptvar = aedecod; +%let totval = 99; +%let trtnord = 99; +%let pctfmt = pctmf.; +%let byvar = relcat; + +/* Macro for creating #patients/#events counts */ +%macro ne_freq (indat =,outdat =, byvars =, anyvars = ); + + %let byvars2 = %sysfunc(tranwrd(%quote(&byvars.) ,%str( ),%str( , ))); + %if &byvars ^= %then %let sep = %str( , ); + %else %let sep = ; + + proc sql; + create table &outdat. as + select count(distinct USUBJID) as stat_n, + count(USUBJID) as stat_e + &sep. &byvars2. + %if &anyvars ^= %then %do i = 1 %to %sysfunc(countw(&anyvars)); + , 'ANY' as %scan(&anyvars, &i) + %end; + from &indat. + %if &byvars. ^= %then group by &byvars2.; + ; + quit; + +%mend; + +/* All aes (with total column if required) */ +data aes; + set &indat + &indat (in = intot); + if intot then &trtvarn = &totval; +run; + +/* Adsl with total column if required */ +data adslmod; + set &inadsl + &inadsl (in = intot ); + if intot then &trtvarn = &totval; +run; + +/* Counts including totals (by Severity) */ +%ne_freq(indat = aes, outdat = out1, byvars = &byvar &trtvarn, anyvars = &socvar &ptvar); +%ne_freq(indat = aes, outdat = out2, byvars = &byvar &trtvarn &socvar, anyvars = &ptvar); +%ne_freq(indat = aes, outdat = out3, byvars = &byvar &trtvarn &socvar &ptvar, anyvars =); + +/* Counts including totals (Any Severity) */ +%ne_freq(indat = aes, outdat = out4, byvars = &trtvarn, anyvars = &byvar &socvar &ptvar); +%ne_freq(indat = aes, outdat = out5, byvars = &trtvarn &socvar, anyvars = &byvar &ptvar); +%ne_freq(indat = aes, outdat = out6, byvars = &trtvarn &socvar &ptvar, anyvars = &byvar); + +/* N counts for denominators */ +%ne_freq(indat = adslmod, outdat = Ncounts, byvars = &trtvarn, anyvars =); + +data Ncounts; + set Ncounts (drop = stat_e rename = (stat_n = bigN)); + call symputx(cats('N_',&trtvarn), bigN, 'g'); +run; + +/* Set all ae counts together */ +data allcounts; + length &socvar &ptvar $ 200; + set out1-out6; +run; + +/* Template dataset */ +proc sql; + create table template as + select *, 0 as stat_e, 0 as stat_n + from (select distinct &socvar, &ptvar from &indat + union + select distinct &socvar, 'ANY' as &ptvar from &indat + union + select distinct 'ANY' as &ptvar, 'ANY' as &socvar from &indat), + (select distinct &byvar from &indat + union + select distinct 'ANY' as &byvar from &indat), + Ncounts + order by &trtvarn, &socvar, &ptvar, &byvar; + ; +quit; + +/* Merge on observed counts to template */ +proc sort data = allcounts out = allcounts_s; + by &trtvarn &socvar &ptvar &byvar; +run; +data counts_w0; + length &socvar &ptvar $ 200 statc_n statc_e statc_p $ 30; + merge template allcounts_s; + by &trtvarn &socvar &ptvar &byvar; + /* Create character versions of counts */ + statc_n = strip(put(stat_n,5.)); + statc_e = strip(put(stat_e,5.)); + statc_p = put(stat_n/bigN * 100, &pctfmt); +run; + +/* Concatenate n and percent*/ +data counts_cat (keep = &socvar &ptvar &trtvarn &byvar npp statc_e); + length npp $ 50; + set counts_w0; + npp = cat(strip(statc_n), ' ', strip(statc_p)); +run; + +/* Create SOC and PT order variables based on # patients / frequency of event */ +proc rank data = counts_w0 (where = (&trtvarn = &trtnord & &ptvar = 'ANY' & &socvar ^= 'ANY' & &byvar = 'ANY')) out = socranks (keep = &socvar SOCord_NP SOCord_EV) ties = low descending; + var stat_n stat_e; + ranks SOCord_NP SOCord_EV; +run; + +proc sort data = counts_w0 out = counts_w0s; + by &socvar; +run; + +proc rank data = counts_w0s (where = (&trtvarn = &trtnord & &ptvar ^= 'ANY' & &socvar ^= 'ANY' & &byvar = 'ANY')) out = ptranks (keep = &socvar &ptvar PTord_NP PTord_EV) ties = low descending; + by &socvar; + var stat_n stat_e; + ranks PTord_NP PTord_EV; +run; + +proc format; + invalue relord 'ANY' = 1 + 'Related' = 2 + 'Not Related' = 3 + ; +run; + +proc sql; + create table counts_word as + select a.*, + case when a.&socvar = 'ANY' then 1 else b.SOCord_NP + 1 end as SOCord_NP, + case when a.&socvar = 'ANY' then 1 else b.SOCord_EV + 1 end as SOCord_EV, + case when a.&ptvar = 'ANY' then 1 else c.PTord_NP + 1 end as PTord_NP, + case when a.&ptvar = 'ANY' then 1 else c.PTord_EV + 1 end as PTord_EV, + input(&byvar,relord.) as relord + from counts_cat a left join socranks b + on a.&socvar = b.&socvar + left join ptranks c + on a.&socvar = c.&socvar + and a.&ptvar = c.&ptvar + order by SOCord_NP, &socvar, PTord_NP, &ptvar, relord, &byvar, &trtvarn + ; +quit; + +/* Transpose into long format */ +proc transpose data = counts_word out = counts_T (rename = (_NAME_ = statty COL1 = statval)); + by SOCord_NP &socvar PTord_NP &ptvar relord &byvar &trtvarn ; + var npp statc_e; +run; + +data counts_T; + set counts_T; + where &trtvarn ^= .; +run; + +/* Transpose to trts are cols */ +proc transpose delim = _ prefix = trt_ data = counts_T out = counts_TT (drop = _NAME_); + id &trtvarn statty; + by SOCord_NP &socvar PTord_NP &ptvar relord &byvar; + var statval; +run; + +data extrow (keep = aesoc aedecod soc_pt_disp &byvar trt_99_npp); + length soc_pt_disp $ 132; + set counts_TT; + by SOCord_NP aesoc; + + if first.aesoc & aesoc ^= 'ANY' then do; + soc_pt_disp = aesoc; + output; + end; + if aesoc = 'ANY' then do; + soc_pt_disp = 'Subjects with at least one TEAE'; + output; + end; + if aedecod = 'ANY' then aedecod = 'Any event'; + soc_pt_disp = aedecod; + if aesoc ^= 'ANY' then output; +run; + +data final (drop = i); + set extrow; + array trtcounts $ trt_:; + if aesoc = soc_pt_disp then do i = 1 to dim(trtcounts); + trtcounts[i] = ''; + &byvar = ' '; + end; + if aedecod = soc_pt_disp then indent = 'Y'; + else indent = 'N'; + + if &byvar = 'ANY' then &byvar = 'Total'; + &byvar = propcase(&byvar); + + soc_pt_disp = propcase(soc_pt_disp); + aesoc = propcase(aesoc); + aedecod = propcase(aedecod); + + soc_pt_disp = tranwrd(soc_pt_disp, "Teae", "TEAE"); +run; + +*include metadata; +%tfl_metadata; + +** create the table output; + +ods pdf file = "/mnt/artifacts/TFL/&__prog_name..pdf" + style = newstyle; + +ods noproctitle; +ods escapechar = "^"; + +** add titles to output; +title1 justify = left "Domino" justify = right "Page ^{thispage} of ^{lastpage}"; +title2 "&DisplayName."; +title3 "&DisplayTitle."; +title4 "&Title1."; + +** justify contents to decimal places; +proc report data = final headline split = "*" + style(report) = {width = 100%}; +** if you also want TFL written to Dataset out = tfl.&__prog_name.; + column aesoc + aedecod + indent soc_pt_disp &byvar trt_99_npp; + + ** order variables; + define aesoc / order order = data noprint; + define aedecod / order order = data noprint; + define indent / order order = data noprint; + define &byvar / display '' + style(header) = {width = 8% just = l}; + define soc_pt_disp / order order = data "System Organ Class* Preferred Term" + style(header) = {width = 60% asis = on just = l}; + define trt_99_npp / display "All Treatments*(N=&N_99)*n (%)" + style(header) = {width = 30%} style(column) = {just = d}; + compute soc_pt_disp; + if indent = 'Y' then call define(_COL_, "style", "style=[leftmargin = 0.3in]"); + endcomp; + + compute before aedecod; + line ''; + endcomp; + + ** add footnotes; + footnote1 justify = left "&Footer1."; + footnote2 justify = left "&Footer2."; + footnote3 justify = left "&Footer3."; + footnote4 justify = left "&Footer4."; + footnote5 justify = left "&Footer5."; +run; + +ods pdf close; + From 25bbd937dc18df23fb29fb1d3a7975840c49c0e9 Mon Sep 17 00:00:00 2001 From: Jim Coates Date: Thu, 10 Oct 2024 08:10:14 -0400 Subject: [PATCH 2/3] Create t_dm2 file sas script --- prod/tfl/t_dm2.sas | 371 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 prod/tfl/t_dm2.sas diff --git a/prod/tfl/t_dm2.sas b/prod/tfl/t_dm2.sas new file mode 100644 index 0000000..9ff44de --- /dev/null +++ b/prod/tfl/t_dm2.sas @@ -0,0 +1,371 @@ +/*****************************************************************************\ +* ____ _ +* | _ \ ___ _ __ ___ (_)_ __ ___ +* | | | |/ _ \| '_ ` _ \| | '_ \ / _ \ +* | |_| | (_) | | | | | | | | | | (_) | +* |____/ \___/|_| |_| |_|_|_| |_|\___/ +* ____________________________________________________________________________ +* Sponsor : Domino +* Study : CDISC01 +* Program : t_ae_rel.sas +* Purpose : Create the Treatment Emergent Adverse Events Table +* ____________________________________________________________________________ +* DESCRIPTION +* +* Input files: ADaM.ADSL +* ADaM.ADAE +* +* Output files: t_ae_rel.pdf +* t_ae_rel.sas7bdat +* +* Macros: tfl_metadata.sas +* +* Assumptions: test +* +* ____________________________________________________________________________ +* PROGRAM HISTORY +* 24MAY2022 | Jake Tombeur | Original version +* 10MAY2023 | Megan Harries | Updates for CDISC01 ADaMs +* ---------------------------------------------------------------------------- +\*****************************************************************************/ + +*********; +** Setup environment including libraries for this reporting effort; +%include "/mnt/code/domino.sas"; +*********; + +ods path(prepend) work.templat(update); + +*Set the template for the output; +proc template; + define style newstyle; + + class Table / + Rules = Groups + Frame = void; + + style header + / just = c + fontweight = medium; + + replace Body from Document / + bottommargin = 1.54cm + topmargin = 2.54cm + rightmargin = 2.54cm + leftmargin = 2.54cm; + + replace fonts / + 'TitleFont2' = ("Courier New",9pt) + 'TitleFont' = ("Courier New",9pt/*,Bold*/) /* titles */ + 'StrongFont' = ("Courier New",9pt/*,Bold*/) + 'EmphasisFont' = ("Courier New",9pt,Italic) + 'FixedEmphasisFont' = ("Courier New, Courier",9pt,Italic) + 'FixedStrongFont' = ("Courier New, Courier",9pt/*,Bold*/) + 'FixedHeadingFont' = ("Courier New, Courier",9pt/*,Bold*/) + 'BatchFixedFont' = ("SAS Monospace, Courier New, Courier",9pt) + 'FixedFont' = ("Courier New, Courier",9pt) + 'headingEmphasisFont' = ("Courier New",9pt,Bold Italic) + 'headingFont' = ("Courier New",9pt/*,Bold*/) /* header block */ + 'docFont' = ("Courier New",9pt); /* table cells */ + + replace color_list + "Colors used in the default style" / + 'link' = blue + 'bgH' = white /* header background */ + 'fg' = black + 'bg' = _undef_; +end; +run ; + +options orientation = landscape nonumber nodate nobyline; + +proc format; + picture pctmf (round default = 8) /* Picture format for percentages */ + . = ' ' (noedit) + low-0.001 = ' ' (noedit) + 0.001-<0.1 = ' (<0.1%)' (noedit) + 0.1-<1 = ' (9.9%)' (prefix=' (') + 1-<99.90001 = ' (00.0%)' (prefix=' (') + 99.90001-<100 = '(>99.9%)' (noedit) + 100 = '(100%) ' (noedit) + ; +run; + +data teae (rename = (actarm = trta)); + length relcat $20; + set adam.adae; + + if aerel in ('POSSIBLE' 'PROBABLE' 'DEFINITE') then relcat = 'Related'; + else relcat = 'Not Related'; + + if actarm = "Placebo" then trtan = 1; + else if actarm = "Xanomeline Low Dose" then trtan = 2; + else if actarm = "Xanomeline High Dose" then trtan = 3; +run; + +** exclude non-treated subjects; +data adsl1 (rename = (actarm = trta) where = (trtan ^= .)); + set adam.adsl; + + if actarm = "Placebo" then trtan = 1; + else if actarm = "Xanomeline Low Dose" then trtan = 2; + else if actarm = "Xanomeline High Dose" then trtan = 3; +run; + +%let indat = teae; +%let trtvarn = trtan; +%let inadsl = adsl1; +%let socvar = aesoc; +%let ptvar = aedecod; +%let totval = 99; +%let trtnord = 99; +%let pctfmt = pctmf.; +%let byvar = relcat; + +/* Macro for creating #patients/#events counts */ +%macro ne_freq (indat =,outdat =, byvars =, anyvars = ); + + %let byvars2 = %sysfunc(tranwrd(%quote(&byvars.) ,%str( ),%str( , ))); + %if &byvars ^= %then %let sep = %str( , ); + %else %let sep = ; + + proc sql; + create table &outdat. as + select count(distinct USUBJID) as stat_n, + count(USUBJID) as stat_e + &sep. &byvars2. + %if &anyvars ^= %then %do i = 1 %to %sysfunc(countw(&anyvars)); + , 'ANY' as %scan(&anyvars, &i) + %end; + from &indat. + %if &byvars. ^= %then group by &byvars2.; + ; + quit; + +%mend; + +/* All aes (with total column if required) */ +data aes; + set &indat + &indat (in = intot); + if intot then &trtvarn = &totval; +run; + +/* Adsl with total column if required */ +data adslmod; + set &inadsl + &inadsl (in = intot ); + if intot then &trtvarn = &totval; +run; + +/* Counts including totals (by Severity) */ +%ne_freq(indat = aes, outdat = out1, byvars = &byvar &trtvarn, anyvars = &socvar &ptvar); +%ne_freq(indat = aes, outdat = out2, byvars = &byvar &trtvarn &socvar, anyvars = &ptvar); +%ne_freq(indat = aes, outdat = out3, byvars = &byvar &trtvarn &socvar &ptvar, anyvars =); + +/* Counts including totals (Any Severity) */ +%ne_freq(indat = aes, outdat = out4, byvars = &trtvarn, anyvars = &byvar &socvar &ptvar); +%ne_freq(indat = aes, outdat = out5, byvars = &trtvarn &socvar, anyvars = &byvar &ptvar); +%ne_freq(indat = aes, outdat = out6, byvars = &trtvarn &socvar &ptvar, anyvars = &byvar); + +/* N counts for denominators */ +%ne_freq(indat = adslmod, outdat = Ncounts, byvars = &trtvarn, anyvars =); + +data Ncounts; + set Ncounts (drop = stat_e rename = (stat_n = bigN)); + call symputx(cats('N_',&trtvarn), bigN, 'g'); +run; + +/* Set all ae counts together */ +data allcounts; + length &socvar &ptvar $ 200; + set out1-out6; +run; + +/* Template dataset */ +proc sql; + create table template as + select *, 0 as stat_e, 0 as stat_n + from (select distinct &socvar, &ptvar from &indat + union + select distinct &socvar, 'ANY' as &ptvar from &indat + union + select distinct 'ANY' as &ptvar, 'ANY' as &socvar from &indat), + (select distinct &byvar from &indat + union + select distinct 'ANY' as &byvar from &indat), + Ncounts + order by &trtvarn, &socvar, &ptvar, &byvar; + ; +quit; + +/* Merge on observed counts to template */ +proc sort data = allcounts out = allcounts_s; + by &trtvarn &socvar &ptvar &byvar; +run; +data counts_w0; + length &socvar &ptvar $ 200 statc_n statc_e statc_p $ 30; + merge template allcounts_s; + by &trtvarn &socvar &ptvar &byvar; + /* Create character versions of counts */ + statc_n = strip(put(stat_n,5.)); + statc_e = strip(put(stat_e,5.)); + statc_p = put(stat_n/bigN * 100, &pctfmt); +run; + +/* Concatenate n and percent*/ +data counts_cat (keep = &socvar &ptvar &trtvarn &byvar npp statc_e); + length npp $ 50; + set counts_w0; + npp = cat(strip(statc_n), ' ', strip(statc_p)); +run; + +/* Create SOC and PT order variables based on # patients / frequency of event */ +proc rank data = counts_w0 (where = (&trtvarn = &trtnord & &ptvar = 'ANY' & &socvar ^= 'ANY' & &byvar = 'ANY')) out = socranks (keep = &socvar SOCord_NP SOCord_EV) ties = low descending; + var stat_n stat_e; + ranks SOCord_NP SOCord_EV; +run; + +proc sort data = counts_w0 out = counts_w0s; + by &socvar; +run; + +proc rank data = counts_w0s (where = (&trtvarn = &trtnord & &ptvar ^= 'ANY' & &socvar ^= 'ANY' & &byvar = 'ANY')) out = ptranks (keep = &socvar &ptvar PTord_NP PTord_EV) ties = low descending; + by &socvar; + var stat_n stat_e; + ranks PTord_NP PTord_EV; +run; + +proc format; + invalue relord 'ANY' = 1 + 'Related' = 2 + 'Not Related' = 3 + ; +run; + +proc sql; + create table counts_word as + select a.*, + case when a.&socvar = 'ANY' then 1 else b.SOCord_NP + 1 end as SOCord_NP, + case when a.&socvar = 'ANY' then 1 else b.SOCord_EV + 1 end as SOCord_EV, + case when a.&ptvar = 'ANY' then 1 else c.PTord_NP + 1 end as PTord_NP, + case when a.&ptvar = 'ANY' then 1 else c.PTord_EV + 1 end as PTord_EV, + input(&byvar,relord.) as relord + from counts_cat a left join socranks b + on a.&socvar = b.&socvar + left join ptranks c + on a.&socvar = c.&socvar + and a.&ptvar = c.&ptvar + order by SOCord_NP, &socvar, PTord_NP, &ptvar, relord, &byvar, &trtvarn + ; +quit; + +/* Transpose into long format */ +proc transpose data = counts_word out = counts_T (rename = (_NAME_ = statty COL1 = statval)); + by SOCord_NP &socvar PTord_NP &ptvar relord &byvar &trtvarn ; + var npp statc_e; +run; + +data counts_T; + set counts_T; + where &trtvarn ^= .; +run; + +/* Transpose to trts are cols */ +proc transpose delim = _ prefix = trt_ data = counts_T out = counts_TT (drop = _NAME_); + id &trtvarn statty; + by SOCord_NP &socvar PTord_NP &ptvar relord &byvar; + var statval; +run; + +data extrow (keep = aesoc aedecod soc_pt_disp &byvar trt_99_npp); + length soc_pt_disp $ 132; + set counts_TT; + by SOCord_NP aesoc; + + if first.aesoc & aesoc ^= 'ANY' then do; + soc_pt_disp = aesoc; + output; + end; + if aesoc = 'ANY' then do; + soc_pt_disp = 'Subjects with at least one TEAE'; + output; + end; + if aedecod = 'ANY' then aedecod = 'Any event'; + soc_pt_disp = aedecod; + if aesoc ^= 'ANY' then output; +run; + +data final (drop = i); + set extrow; + array trtcounts $ trt_:; + if aesoc = soc_pt_disp then do i = 1 to dim(trtcounts); + trtcounts[i] = ''; + &byvar = ' '; + end; + if aedecod = soc_pt_disp then indent = 'Y'; + else indent = 'N'; + + if &byvar = 'ANY' then &byvar = 'Total'; + &byvar = propcase(&byvar); + + soc_pt_disp = propcase(soc_pt_disp); + aesoc = propcase(aesoc); + aedecod = propcase(aedecod); + + soc_pt_disp = tranwrd(soc_pt_disp, "Teae", "TEAE"); +run; + +*include metadata; +%tfl_metadata; + +** create the table output; + +ods pdf file = "/mnt/artifacts/TFL/&__prog_name..pdf" + style = newstyle; + +ods noproctitle; +ods escapechar = "^"; + +** add titles to output; +title1 justify = left "Domino" justify = right "Page ^{thispage} of ^{lastpage}"; +title2 "&DisplayName."; +title3 "&DisplayTitle."; +title4 "&Title1."; + +** justify contents to decimal places; +proc report data = final headline split = "*" + style(report) = {width = 100%}; +** if you also want TFL written to Dataset out = tfl.&__prog_name.; + column aesoc + aedecod + indent soc_pt_disp &byvar trt_99_npp; + + ** order variables; + define aesoc / order order = data noprint; + define aedecod / order order = data noprint; + define indent / order order = data noprint; + define &byvar / display '' + style(header) = {width = 8% just = l}; + define soc_pt_disp / order order = data "System Organ Class* Preferred Term" + style(header) = {width = 60% asis = on just = l}; + define trt_99_npp / display "All Treatments*(N=&N_99)*n (%)" + style(header) = {width = 30%} style(column) = {just = d}; + compute soc_pt_disp; + if indent = 'Y' then call define(_COL_, "style", "style=[leftmargin = 0.3in]"); + endcomp; + + compute before aedecod; + line ''; + endcomp; + + ** add footnotes; + footnote1 justify = left "&Footer1."; + footnote2 justify = left "&Footer2."; + footnote3 justify = left "&Footer3."; + footnote4 justify = left "&Footer4."; + footnote5 justify = left "&Footer5."; +run; + +ods pdf close; + From 573a8ea61aed6dc55b108f9c7196e04b3b03a9e3 Mon Sep 17 00:00:00 2001 From: Jim Coates Date: Thu, 10 Oct 2024 08:11:54 -0400 Subject: [PATCH 3/3] Performed qc of saftey for 01 --- qc/tfl/qc_t_saftey_01.sas | 269 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 qc/tfl/qc_t_saftey_01.sas diff --git a/qc/tfl/qc_t_saftey_01.sas b/qc/tfl/qc_t_saftey_01.sas new file mode 100644 index 0000000..9b5fb8f --- /dev/null +++ b/qc/tfl/qc_t_saftey_01.sas @@ -0,0 +1,269 @@ +/*****************************************************************************\ +* ____ _ +* | _ \ ___ _ __ ___ (_)_ __ ___ +* | | | |/ _ \| '_ ` _ \| | '_ \ / _ \ +* | |_| | (_) | | | | | | | | | | (_) | +* |____/ \___/|_| |_| |_|_|_| |_|\___/ +* ____________________________________________________________________________ +* Sponsor : Domino +* Study : CDISC01 +* Program : qc_t_pop.sas +* Purpose : Create the QC Summary of Populations Table +* ____________________________________________________________________________ +* DESCRIPTION +* +* Input files: ADaM.ADSL +* +* Output files: qc_t_pop. +* t_pop.sas7bdat +* +* Macros: None vt +* +* Assumptions: Demo only - Second comment 20240311 +* +* ____________________________________________________________________________ +* PROGRAM HISTORY +* 10MAY2023 | Megan Harries | Original +* 08DEC2023 | Petter Olsson | Demo Comment +* ---------------------------------------------------------------------------- +\*****************************************************************************/ + +*********; +** Setup environment including libraries for this reporting effort; +%include "/mnt/code/domino.sas"; +*********; + +ods path(prepend) work.templat(update); + +*Set the template for the output; +proc template; + define style newstyle; + + class Table / + Rules = Groups + Frame = void; + + style header + / just = c + fontweight = medium; + + replace Body from Document / + bottommargin = 1.54cm + topmargin = 2.54cm + rightmargin = 2.54cm + leftmargin = 2.54cm; + + replace fonts / + 'TitleFont2' = ("Courier New",9pt) + 'TitleFont' = ("Courier New",9pt/*,Bold*/) /* titles */ + 'StrongFont' = ("Courier New",9pt/*,Bold*/) + 'EmphasisFont' = ("Courier New",9pt,Italic) + 'FixedEmphasisFont' = ("Courier New, Courier",9pt,Italic) + 'FixedStrongFont' = ("Courier New, Courier",9pt/*,Bold*/) + 'FixedHeadingFont' = ("Courier New, Courier",9pt/*,Bold*/) + 'BatchFixedFont' = ("SAS Monospace, Courier New, Courier",9pt) + 'FixedFont' = ("Courier New, Courier",9pt) + 'headingEmphasisFont' = ("Courier New",9pt,Bold Italic) + 'headingFont' = ("Courier New",9pt/*,Bold*/) /* header block */ + 'docFont' = ("Courier New",9pt); /* table cells */ + + replace color_list + "Colors used in the default style" / + 'link' = blue + 'bgH' = white /* header background */ + 'fg' = black + 'bg' = _undef_; +end; +run ; + +options orientation = landscape nonumber nodate nobyline; + +** adsl and include required variables for table; +data adsl_all (rename = (actarm = trta)); + length trtan agen sexn 8.; + set adam.adsl; + + if actarm = "Placebo" then trtan = 1; + else if actarm = "Xanomeline Low Dose" then trtan = 2; + else if actarm = "Xanomeline High Dose" then trtan = 3; + + if age < 60 then agen = 1; + else if 60 <= age < 65 then agen = 2; + else if 65 <= age < 70 then agen = 3; + else if 70 <= age < 75 then agen = 4; + else if 75 <= age < 80 then agen = 5; + else if 80 <= age then agen = 6; + + if sex = 'M' then sexn = 1; + if sex = 'F' then sexn = 2; +run; + +** observations in the population, and the parameters specified in SAP; +data adsl (keep = usubjid trta trtan age agen sex sexn); + set adsl_all(where = (trtan ne .)); +run; + +** create macro for counting number of placebo participants; +proc sql noprint; + select count(distinct usubjid) + into :placebo_n + from adsl(where = (trta = "Placebo")); +quit; + +** create macro for counting number of Xanomeline Low Dose participants; +proc sql noprint; + select count(distinct usubjid) + into :low_dose_n + from adsl(where = (trta = "Xanomeline Low Dose")); +quit; + +** create macro for counting number of Xanomeline High Dose participants; +proc sql noprint; + select count(distinct usubjid) + into :high_dose_n + from adsl(where = (trta = "Xanomeline High Dose")); +quit; + +** create macro for each variable results; +** calculate number of unique subjects with post-baseline results; +proc sql; + create table total_age as + select trta, count(distinct usubjid) as count_age + from adsl + group by trta; +quit; + +** calculate number of unique subjects for each age group; +%macro age_data(agen = ); + data age&agen.; + set adsl; + where agen = &agen.; + run; + + proc sql; + create table total_age&agen. as + select trta, count(distinct usubjid) as n&agen. + from age&agen. + group by trta; + quit; +%mend age_data; + +%age_data(agen = 1); +%age_data(agen = 2); +%age_data(agen = 3); +%age_data(agen = 4); +%age_data(agen = 5); +%age_data(agen = 6); + +** merge the counts and calculate percentages; +data results; + merge total_age total_age1 total_age2 total_age3 total_age4 total_age5 total_age6; + by trta; + if n1 ne . then p1 = cats("(", put(100*n1/count_age, 6.1), ")"); + if n2 ne . then p2 = cats("(", put(100*n2/count_age, 6.1), ")"); + if n3 ne . then p3 = cats("(", put(100*n3/count_age, 6.1), ")"); + if n4 ne . then p4 = cats("(", put(100*n4/count_age, 6.1), ")"); + if n5 ne . then p5 = cats("(", put(100*n5/count_age, 6.1), ")"); + if n6 ne . then p6 = cats("(", put(100*n6/count_age, 6.1), ")"); +run; + +** concatenate results for any parameter data; +data results_c; + length results1 results2 results3 results4 results5 results6 $32; + set results; + + ** convert post baseline count to character; + count_age_c = ""; + + ** if 100% then no decimal places; + if p1 = "(100.0)" then p1 = "(100)"; + if p2 = "(100.0)" then p2 = "(100)"; + if p3 = "(100.0)" then p3 = "(100)"; + if p4 = "(100.0)" then p4 = "(100)"; + if p5 = "(100.0)" then p5 = "(100)"; + if p6 = "(100.0)" then p6 = "(100)"; + + + ** if 0% then only n = 0 is displayed, no event or percentage; + ** concatenate n and p; + if p1 = " " then results1 = "0"; + else results1 = catx(" ", put(n1, 8.), p1); + if p2 = " " then results2 = "0"; + else results2 = catx(" ", put(n2, 8.), p2); + if p3 = " " then results3 = "0"; + else results3 = catx(" ", put(n3, 8.), p3); + if p4 = " " then results4 = "0"; + else results4 = catx(" ", put(n4, 8.), p4); + if p5 = " " then results5 = "0"; + else results5 = catx(" ", put(n5, 8.), p5); + if p6 = " " then results6 = "0"; + else results6 = catx(" ", put(n6, 8.), p6); +run; + +** transpose any results dataset; +options validvarname=v7; +proc transpose data = results_c out = results_t name = agegroup; + id trta; + var count_age_c results1 results2 results3 results4 results5 results6; +run; + + +** add parameter identifier and order variable; +data order_results(rename = (Xanomeline_Low_Dose = Low_Dose Xanomeline_High_Dose = High_Dose)); + length order1 8. ageresults $50 stat $8; + set results_t; + if agegroup = "count_age_c" then do; + order1 = 1; + ageresults = ""; + stat = ""; + end; + else do; + order1 = input(substr(agegroup, 8), 8.)+1; + stat = "n (%)"; + end; + + if agegroup = "results1" then ageresults = "Less than 60 years old"; + else if agegroup = "results2" then ageresults = "60 years old <= age < 65 years old"; + else if agegroup = "results3" then ageresults = "65 years old <= age < 70 years old"; + else if agegroup = "results4" then ageresults = "70 years old <= age < 75 years old"; + else if agegroup = "results5" then ageresults = "75 years old <= age < 80 years old"; + else if agegroup = "results6" then ageresults = "80 years and older"; +run; + +** create the table output; + +ods pdf file = "/mnt/artifacts/TFL_QC/qc_t_pop.pdf" + style = newstyle; + +ods noproctitle; +ods escapechar = "^"; + +** add titles to output; +title1 justify = left "Domino" justify = right "Page ^{thispage} of ^{lastpage}"; +title2 "Table 14.3.4.1"; +title3 "Summary of Age for each Treatment"; +title4 "Analysis Set"; + +** justify contents to decimal places; +** if you want TFL to also be written to Dataset. proc report data = order_results headline split = "*" style(report) = {width = 100% cellpadding = 3} out = tflqc.t_pop; +proc report data = order_results headline split = "*" style(report) = {width = 100% cellpadding = 3}; + column (order1 ageresults stat placebo low_dose high_dose); + + ** order variables; + define order1 / order noprint; + + define ageresults / "*Age Group" style(column) = {just = l asis = on width = 30%} style(header) = {just = l asis = on}; + define stat / "*Statistic" style(column) = {just = l width = 10%}; + define placebo / "Placebo* (N=%cmpres(&placebo_n))" style(column) = {just = d width = 18%}; + define low_dose / "Xanomeline Low Dose* (N=%cmpres(&low_dose_n))" style(column) = {just = d width = 20%}; + define high_dose / "Xanomeline High Dose* (N=%cmpres(&high_dose_n))" style(column) = {just = d width = 20%}; + + ** add footnotes describing the critical codes; + footnote1 justify = left "Note: n = number of unique subjects in age group."; + footnote2 justify = left "Note: percentages are based on the number of patients for each treatment."; + footnote3 justify = left "Dataset(s): ADSL; Program: qc_t_pop.sas; Output: qc_t_pop.pdf; Generated on: &sysdate9 &systime"; +run; + +ods pdf close; + +