Skip to content

Commit 6dfb77b

Browse files
Merge pull request #71 from dominodatalab/Interim_01
Final Interim 01
2 parents aa5e527 + 93fc83b commit 6dfb77b

File tree

3 files changed

+1011
-0
lines changed

3 files changed

+1011
-0
lines changed

prod/tfl/t_dm1.sas

Lines changed: 371 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,371 @@
1+
/*****************************************************************************\
2+
* ____ _
3+
* | _ \ ___ _ __ ___ (_)_ __ ___
4+
* | | | |/ _ \| '_ ` _ \| | '_ \ / _ \
5+
* | |_| | (_) | | | | | | | | | | (_) |
6+
* |____/ \___/|_| |_| |_|_|_| |_|\___/
7+
* ____________________________________________________________________________
8+
* Sponsor : Domino
9+
* Study : CDISC01
10+
* Program : t_ae_rel.sas
11+
* Purpose : Create the Treatment Emergent Adverse Events Table
12+
* ____________________________________________________________________________
13+
* DESCRIPTION
14+
*
15+
* Input files: ADaM.ADSL
16+
* ADaM.ADAE
17+
*
18+
* Output files: t_ae_rel.pdf
19+
* t_ae_rel.sas7bdat
20+
*
21+
* Macros: tfl_metadata.sas
22+
*
23+
* Assumptions: test
24+
*
25+
* ____________________________________________________________________________
26+
* PROGRAM HISTORY
27+
* 24MAY2022 | Jake Tombeur | Original version
28+
* 10MAY2023 | Megan Harries | Updates for CDISC01 ADaMs
29+
* ----------------------------------------------------------------------------
30+
\*****************************************************************************/
31+
32+
*********;
33+
** Setup environment including libraries for this reporting effort;
34+
%include "/mnt/code/domino.sas";
35+
*********;
36+
37+
ods path(prepend) work.templat(update);
38+
39+
*Set the template for the output;
40+
proc template;
41+
define style newstyle;
42+
43+
class Table /
44+
Rules = Groups
45+
Frame = void;
46+
47+
style header
48+
/ just = c
49+
fontweight = medium;
50+
51+
replace Body from Document /
52+
bottommargin = 1.54cm
53+
topmargin = 2.54cm
54+
rightmargin = 2.54cm
55+
leftmargin = 2.54cm;
56+
57+
replace fonts /
58+
'TitleFont2' = ("Courier New",9pt)
59+
'TitleFont' = ("Courier New",9pt/*,Bold*/) /* titles */
60+
'StrongFont' = ("Courier New",9pt/*,Bold*/)
61+
'EmphasisFont' = ("Courier New",9pt,Italic)
62+
'FixedEmphasisFont' = ("Courier New, Courier",9pt,Italic)
63+
'FixedStrongFont' = ("Courier New, Courier",9pt/*,Bold*/)
64+
'FixedHeadingFont' = ("Courier New, Courier",9pt/*,Bold*/)
65+
'BatchFixedFont' = ("SAS Monospace, Courier New, Courier",9pt)
66+
'FixedFont' = ("Courier New, Courier",9pt)
67+
'headingEmphasisFont' = ("Courier New",9pt,Bold Italic)
68+
'headingFont' = ("Courier New",9pt/*,Bold*/) /* header block */
69+
'docFont' = ("Courier New",9pt); /* table cells */
70+
71+
replace color_list
72+
"Colors used in the default style" /
73+
'link' = blue
74+
'bgH' = white /* header background */
75+
'fg' = black
76+
'bg' = _undef_;
77+
end;
78+
run ;
79+
80+
options orientation = landscape nonumber nodate nobyline;
81+
82+
proc format;
83+
picture pctmf (round default = 8) /* Picture format for percentages */
84+
. = ' ' (noedit)
85+
low-0.001 = ' ' (noedit)
86+
0.001-<0.1 = ' (<0.1%)' (noedit)
87+
0.1-<1 = ' (9.9%)' (prefix=' (')
88+
1-<99.90001 = ' (00.0%)' (prefix=' (')
89+
99.90001-<100 = '(>99.9%)' (noedit)
90+
100 = '(100%) ' (noedit)
91+
;
92+
run;
93+
94+
data teae (rename = (actarm = trta));
95+
length relcat $20;
96+
set adam.adae;
97+
98+
if aerel in ('POSSIBLE' 'PROBABLE' 'DEFINITE') then relcat = 'Related';
99+
else relcat = 'Not Related';
100+
101+
if actarm = "Placebo" then trtan = 1;
102+
else if actarm = "Xanomeline Low Dose" then trtan = 2;
103+
else if actarm = "Xanomeline High Dose" then trtan = 3;
104+
run;
105+
106+
** exclude non-treated subjects;
107+
data adsl1 (rename = (actarm = trta) where = (trtan ^= .));
108+
set adam.adsl;
109+
110+
if actarm = "Placebo" then trtan = 1;
111+
else if actarm = "Xanomeline Low Dose" then trtan = 2;
112+
else if actarm = "Xanomeline High Dose" then trtan = 3;
113+
run;
114+
115+
%let indat = teae;
116+
%let trtvarn = trtan;
117+
%let inadsl = adsl1;
118+
%let socvar = aesoc;
119+
%let ptvar = aedecod;
120+
%let totval = 99;
121+
%let trtnord = 99;
122+
%let pctfmt = pctmf.;
123+
%let byvar = relcat;
124+
125+
/* Macro for creating #patients/#events counts */
126+
%macro ne_freq (indat =,outdat =, byvars =, anyvars = );
127+
128+
%let byvars2 = %sysfunc(tranwrd(%quote(&byvars.) ,%str( ),%str( , )));
129+
%if &byvars ^= %then %let sep = %str( , );
130+
%else %let sep = ;
131+
132+
proc sql;
133+
create table &outdat. as
134+
select count(distinct USUBJID) as stat_n,
135+
count(USUBJID) as stat_e
136+
&sep. &byvars2.
137+
%if &anyvars ^= %then %do i = 1 %to %sysfunc(countw(&anyvars));
138+
, 'ANY' as %scan(&anyvars, &i)
139+
%end;
140+
from &indat.
141+
%if &byvars. ^= %then group by &byvars2.;
142+
;
143+
quit;
144+
145+
%mend;
146+
147+
/* All aes (with total column if required) */
148+
data aes;
149+
set &indat
150+
&indat (in = intot);
151+
if intot then &trtvarn = &totval;
152+
run;
153+
154+
/* Adsl with total column if required */
155+
data adslmod;
156+
set &inadsl
157+
&inadsl (in = intot );
158+
if intot then &trtvarn = &totval;
159+
run;
160+
161+
/* Counts including totals (by Severity) */
162+
%ne_freq(indat = aes, outdat = out1, byvars = &byvar &trtvarn, anyvars = &socvar &ptvar);
163+
%ne_freq(indat = aes, outdat = out2, byvars = &byvar &trtvarn &socvar, anyvars = &ptvar);
164+
%ne_freq(indat = aes, outdat = out3, byvars = &byvar &trtvarn &socvar &ptvar, anyvars =);
165+
166+
/* Counts including totals (Any Severity) */
167+
%ne_freq(indat = aes, outdat = out4, byvars = &trtvarn, anyvars = &byvar &socvar &ptvar);
168+
%ne_freq(indat = aes, outdat = out5, byvars = &trtvarn &socvar, anyvars = &byvar &ptvar);
169+
%ne_freq(indat = aes, outdat = out6, byvars = &trtvarn &socvar &ptvar, anyvars = &byvar);
170+
171+
/* N counts for denominators */
172+
%ne_freq(indat = adslmod, outdat = Ncounts, byvars = &trtvarn, anyvars =);
173+
174+
data Ncounts;
175+
set Ncounts (drop = stat_e rename = (stat_n = bigN));
176+
call symputx(cats('N_',&trtvarn), bigN, 'g');
177+
run;
178+
179+
/* Set all ae counts together */
180+
data allcounts;
181+
length &socvar &ptvar $ 200;
182+
set out1-out6;
183+
run;
184+
185+
/* Template dataset */
186+
proc sql;
187+
create table template as
188+
select *, 0 as stat_e, 0 as stat_n
189+
from (select distinct &socvar, &ptvar from &indat
190+
union
191+
select distinct &socvar, 'ANY' as &ptvar from &indat
192+
union
193+
select distinct 'ANY' as &ptvar, 'ANY' as &socvar from &indat),
194+
(select distinct &byvar from &indat
195+
union
196+
select distinct 'ANY' as &byvar from &indat),
197+
Ncounts
198+
order by &trtvarn, &socvar, &ptvar, &byvar;
199+
;
200+
quit;
201+
202+
/* Merge on observed counts to template */
203+
proc sort data = allcounts out = allcounts_s;
204+
by &trtvarn &socvar &ptvar &byvar;
205+
run;
206+
data counts_w0;
207+
length &socvar &ptvar $ 200 statc_n statc_e statc_p $ 30;
208+
merge template allcounts_s;
209+
by &trtvarn &socvar &ptvar &byvar;
210+
/* Create character versions of counts */
211+
statc_n = strip(put(stat_n,5.));
212+
statc_e = strip(put(stat_e,5.));
213+
statc_p = put(stat_n/bigN * 100, &pctfmt);
214+
run;
215+
216+
/* Concatenate n and percent*/
217+
data counts_cat (keep = &socvar &ptvar &trtvarn &byvar npp statc_e);
218+
length npp $ 50;
219+
set counts_w0;
220+
npp = cat(strip(statc_n), ' ', strip(statc_p));
221+
run;
222+
223+
/* Create SOC and PT order variables based on # patients / frequency of event */
224+
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;
225+
var stat_n stat_e;
226+
ranks SOCord_NP SOCord_EV;
227+
run;
228+
229+
proc sort data = counts_w0 out = counts_w0s;
230+
by &socvar;
231+
run;
232+
233+
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;
234+
by &socvar;
235+
var stat_n stat_e;
236+
ranks PTord_NP PTord_EV;
237+
run;
238+
239+
proc format;
240+
invalue relord 'ANY' = 1
241+
'Related' = 2
242+
'Not Related' = 3
243+
;
244+
run;
245+
246+
proc sql;
247+
create table counts_word as
248+
select a.*,
249+
case when a.&socvar = 'ANY' then 1 else b.SOCord_NP + 1 end as SOCord_NP,
250+
case when a.&socvar = 'ANY' then 1 else b.SOCord_EV + 1 end as SOCord_EV,
251+
case when a.&ptvar = 'ANY' then 1 else c.PTord_NP + 1 end as PTord_NP,
252+
case when a.&ptvar = 'ANY' then 1 else c.PTord_EV + 1 end as PTord_EV,
253+
input(&byvar,relord.) as relord
254+
from counts_cat a left join socranks b
255+
on a.&socvar = b.&socvar
256+
left join ptranks c
257+
on a.&socvar = c.&socvar
258+
and a.&ptvar = c.&ptvar
259+
order by SOCord_NP, &socvar, PTord_NP, &ptvar, relord, &byvar, &trtvarn
260+
;
261+
quit;
262+
263+
/* Transpose into long format */
264+
proc transpose data = counts_word out = counts_T (rename = (_NAME_ = statty COL1 = statval));
265+
by SOCord_NP &socvar PTord_NP &ptvar relord &byvar &trtvarn ;
266+
var npp statc_e;
267+
run;
268+
269+
data counts_T;
270+
set counts_T;
271+
where &trtvarn ^= .;
272+
run;
273+
274+
/* Transpose to trts are cols */
275+
proc transpose delim = _ prefix = trt_ data = counts_T out = counts_TT (drop = _NAME_);
276+
id &trtvarn statty;
277+
by SOCord_NP &socvar PTord_NP &ptvar relord &byvar;
278+
var statval;
279+
run;
280+
281+
data extrow (keep = aesoc aedecod soc_pt_disp &byvar trt_99_npp);
282+
length soc_pt_disp $ 132;
283+
set counts_TT;
284+
by SOCord_NP aesoc;
285+
286+
if first.aesoc & aesoc ^= 'ANY' then do;
287+
soc_pt_disp = aesoc;
288+
output;
289+
end;
290+
if aesoc = 'ANY' then do;
291+
soc_pt_disp = 'Subjects with at least one TEAE';
292+
output;
293+
end;
294+
if aedecod = 'ANY' then aedecod = 'Any event';
295+
soc_pt_disp = aedecod;
296+
if aesoc ^= 'ANY' then output;
297+
run;
298+
299+
data final (drop = i);
300+
set extrow;
301+
array trtcounts $ trt_:;
302+
if aesoc = soc_pt_disp then do i = 1 to dim(trtcounts);
303+
trtcounts[i] = '';
304+
&byvar = ' ';
305+
end;
306+
if aedecod = soc_pt_disp then indent = 'Y';
307+
else indent = 'N';
308+
309+
if &byvar = 'ANY' then &byvar = 'Total';
310+
&byvar = propcase(&byvar);
311+
312+
soc_pt_disp = propcase(soc_pt_disp);
313+
aesoc = propcase(aesoc);
314+
aedecod = propcase(aedecod);
315+
316+
soc_pt_disp = tranwrd(soc_pt_disp, "Teae", "TEAE");
317+
run;
318+
319+
*include metadata;
320+
%tfl_metadata;
321+
322+
** create the table output;
323+
324+
ods pdf file = "/mnt/artifacts/TFL/&__prog_name..pdf"
325+
style = newstyle;
326+
327+
ods noproctitle;
328+
ods escapechar = "^";
329+
330+
** add titles to output;
331+
title1 justify = left "Domino" justify = right "Page ^{thispage} of ^{lastpage}";
332+
title2 "&DisplayName.";
333+
title3 "&DisplayTitle.";
334+
title4 "&Title1.";
335+
336+
** justify contents to decimal places;
337+
proc report data = final headline split = "*"
338+
style(report) = {width = 100%};
339+
** if you also want TFL written to Dataset out = tfl.&__prog_name.;
340+
column aesoc
341+
aedecod
342+
indent soc_pt_disp &byvar trt_99_npp;
343+
344+
** order variables;
345+
define aesoc / order order = data noprint;
346+
define aedecod / order order = data noprint;
347+
define indent / order order = data noprint;
348+
define &byvar / display ''
349+
style(header) = {width = 8% just = l};
350+
define soc_pt_disp / order order = data "System Organ Class* Preferred Term"
351+
style(header) = {width = 60% asis = on just = l};
352+
define trt_99_npp / display "All Treatments*(N=&N_99)*n (%)"
353+
style(header) = {width = 30%} style(column) = {just = d};
354+
compute soc_pt_disp;
355+
if indent = 'Y' then call define(_COL_, "style", "style=[leftmargin = 0.3in]");
356+
endcomp;
357+
358+
compute before aedecod;
359+
line '';
360+
endcomp;
361+
362+
** add footnotes;
363+
footnote1 justify = left "&Footer1.";
364+
footnote2 justify = left "&Footer2.";
365+
footnote3 justify = left "&Footer3.";
366+
footnote4 justify = left "&Footer4.";
367+
footnote5 justify = left "&Footer5.";
368+
run;
369+
370+
ods pdf close;
371+

0 commit comments

Comments
 (0)