**************************************************************************************************** * PROGRAM OVERVIEW **************************************************************************************************** * * PROGRAM: baseline_output.sas * Created (mm/dd/yyyy): 03/10/2021 * *-------------------------------------------------------------------------------------------------- * PURPOSE: This macro drives the creation of Baseline Characteristics Tables proc report output * * Program inputs: * - table1_&periodid. * * Program outputs: * * * PARAMETERS: * * Programming Notes: * Utility macro %baseline_procreport created to execute the proc report for each baseline table * * *-------------------------------------------------------------------------------------------------- * CONTACT INFO: * Sentinel Coordinating Center * info@sentinelsystem.org * ***************************************************************************************************; %macro baseline_output(); %put =====> MACRO CALLED: baseline_output; %if %eval(&numbaselinetablegrp.>0) %then %do; /* Set to 2 for effect estimate tables */ %let tablenum = 2; /*********************************************************************************************/ /* proc report */ /*********************************************************************************************/ %macro baseline_procreport(order = , table = , weight = , title= , characteristiclabel =, labcharacteristics =, dpnum = , numcolumns = , grp1_label=, grp2_label=, grp3_label=, computebalance = , includenonpregnant = ); /*save data to reportdata folder*/ %isdata(dataset=repdata.table1&tableletter.); %if %eval(&nobs.<1) %then %do; %let dataset = table1_&periodid.; /*if T6 - merge all switchsteps and create new columns*/ %if &reporttype. = T6 %then %do; proc sql noprint; create table table1&tableletter. as select x.label, x.grouper, x.sortorder1, x.sortorder2, x.sortorder3, x.sortorder4, x.metvar, x.vartype, x.analysisgrp, 'Unadjusted' as table, 'Unweighted' as weight, x.exp_mean&dpnum., x.exp_mean&dpnum._char, x.exp_std&dpnum., x.exp_std&dpnum._char, y.exp_mean&dpnum. as comp_mean&dpnum., y.exp_mean&dpnum._char as comp_mean&dpnum._char, y.exp_std&dpnum. as comp_std&dpnum., y.exp_std&dpnum._char as comp_std&dpnum._char, %if %eval(&maxswitch.=2) %then %do; z.exp_mean&dpnum. as switch2_mean&dpnum., z.exp_mean&dpnum._char as switch2_mean&dpnum._char, z.exp_std&dpnum. as switch2_std&dpnum., z.exp_std&dpnum._char as switch2_std&dpnum._char, %end; x.order from table1_&periodid.(where=(order = &order. and table = 'Switchstep_0')) as x left join table1_&periodid.(where=(order = &order. and table = 'Switchstep_1')) as y on x.metvar = y.metvar and x.sortorder1 = y.sortorder1 and x.sortorder2 = y.sortorder2 and x.sortorder3 = y.sortorder3 and x.sortorder4 = y.sortorder4 %if %eval(&maxswitch.=2) %then %do; left join table1_&periodid.(where=(order = &order. and table = 'Switchstep_2')) as z on x.metvar = z.metvar and x.sortorder1 = z.sortorder1 and x.sortorder2 = z.sortorder2 and x.sortorder3 = z.sortorder3 and x.sortorder4 = z.sortorder4 %end; order by x.sortorder1, x.sortorder2, x.sortorder3, x.sortorder4; quit; %let dataset = table1&tableletter.; %end; data repdata.table1&tableletter.; set &dataset.(where=(order = &order. and table = &table. and weight in (&weight.) %if &reporttype=T2L2 or &reporttype=T4L2 %then %do; and subgroup="&subgroup." and subgroupcat="&subgroupcat." %end;)); keep label grouper metvar vartype analysisgrp table weight exp_mean&dpnum. exp_mean&dpnum._char exp_std&dpnum. exp_std&dpnum._char %if &includecomp. = Y %then %do; comp_mean&dpnum. comp_std&dpnum. comp_mean&dpnum._char comp_std&dpnum._char %end; %if %eval(&maxswitch.=2) %then %do; switch2_mean&dpnum. switch2_std&dpnum. switch2_mean&dpnum._char switch2_std&dpnum._char %end; %if &computebalance. = Y %then %do; ad&dpnum. sd&dpnum. ad&dpnum._char sd&dpnum._char %end; %if &reporttype = T2L2 %then %do; monitoringperiod %end; %if &reporttype=T2L2 or &reporttype=T4L2 %then %do; subgroup subgroupcat %end; ; run; %end; /* Select Footnotes */ %let covnotinpsorder = 19; %global covarlablabels; %let covarlablabels=; /*need to reorder the footnotes when covnotinps is populated because footnote placement is determined by METVAR values listed in the parameter*/ /* L2 covnotinps specified */ %if %length(&covnotinps.) > 0 %then %do; * Check if all covariates specified in &covnotinps are in &labcharacteristics. If this is the case we need to push the footnote further; %let num_covnotinps_nolab=1; %if %str("&labcharacteristics") ^= %str("missing") %then %do; %let tempvarlabs=%upcase(&labcharacteristics); %baseline_expand_parameters(var=tempvarlabs); proc sort data= covarname(keep=studyname cov_varname where=(upcase(cov_varname) in (&tempvarlabs))) out=labcovar(rename=cov_varname=cov); by cov_varname; run; data CovNotInPS; format cov $30.; do obs=1 by 1 until (cov=' '); cov=lowcase(strip(scan(tranwrd(symget('covnotinps'),'"',""),obs))); if cov ne " " then output; end; drop obs; run; proc sort data=CovNotInPS; by cov; run; data CovNotInPS; merge CovNotInPS labcovar(in=b); by cov; NoLab=0; if not b then NoLab=1; run; proc sql noprint; select sum(NoLab) into :num_covnotinps_nolab from CovNotInPS; quit; proc sql noprint undo_policy=none; create table CovNotInPS as select * from CovNotInPS where upcase(cov) in (&Covnotinps.); quit; proc sql noprint; select studyname into :covarlablabels separated by ' ' from CovNotInPS; quit; %create_comma_charlist(inlist=&covarlablabels, outlist=covarlablabels); %put &=num_covnotinps_nolab; %put &=covarlablabels; %end; data _footnotes; length order 8; format order 4.2; set lookup.lookup_footnotes (where = (type = "baseline")); /*birth_enroll or enroll_diff*/ %if %index(%trim(&covnotinps), BIRTH_ENROLL) > 0 %then %do; if order = 19 then order = 14.2; %let covnotinpsorder = 14.2; %end; %else %if %index(%trim(&covnotinps), ENROLL_DIFF) > 0 %then %do; if order = 19 then order = 14.3; %let covnotinpsorder = 14.3; %end; /*age*/ %else %if %index(%trim(&covnotinps), AGE) > 0 %then %do; if order = 19 then order = 14.4; %let covnotinpsorder = 14.4; %end; /*sex*/ %else %if %index(%trim(&covnotinps), SEX) > 0 %then %do; if order = 19 then order = 14.5; %let covnotinpsorder = 14.5; %end; /*race*/ %else %if %index(%trim(&covnotinps), RACE) > 0 %then %do; if order = 19 then do; order = 16.3; %let covnotinpsorder = 16.3; end; %end; /*hispanic*/ %else %if %index(%trim(&covnotinps), HISPANIC) > 0 %then %do; if order =19 then do; order = 16.4; %let covnotinpsorder = 16.4; end; %end; /*year*/ %else %if %index(%trim(&covnotinps), YEAR) > 0 %then %do; if order =19 then do; order = 16.5; %let covnotinpsorder = 16.5; end; %end; /*prepostind*/ %else %if %index(%trim(&covnotinps), PREPOSTIND) > 0 %then %do; if order =19 then do; order = 16.6; %let covnotinpsorder = 16.6; end; %end; /*gestational age*/ %else %if %index(%trim(&covnotinps), GA_) > 0 %then %do; if order =19 then do; order = 17.5; %let covnotinpsorder = 17.5; end; %end; %else %if %index(%trim(&covnotinps), ADJUSTEDDISP_) > 0 %then %do; if order =19 then do; order = 17.6; %let covnotinpsorder = 17.6; end; %end; %else %if %index(%trim(&covnotinps), EXP_) > 0 %then %do; if order =19 then do; order = 17.7; %let covnotinpsorder = 17.7; end; %end; %else %if %eval(&num_covnotinps_nolab = 0) %then %do; if order =19 then do; order = 20.1; %let covnotinpsorder = 20.1; end; %end; run; proc sort data = _footnotes; by order; run; %end; data _footnotes; length footnote_order 3; /* Always displayed across all types */ %if %length(&covnotinps.) > 0 %then %do; set _footnotes (where = ((type = "baseline" and order in (14 &covnotinpsorder. 15 %end; %else %do; set lookup.lookup_footnotes (where = ((type = "baseline" and order in (14 15 %end; /* T4 L1 or L2 gestational age specified*/ %if %index(&reporttype,T4) > 0 and &gestationalage. = Y %then %do; 17 %end; /* if race is collapsed in table*/ %if &collapse_vars. = race %then %do; 16 %end; /* T1, T2L1, T6 when cohortdef is not 01 and T4L1 when a non-MIL */ %if ((%str("&reporttype") = %str("T1") | %str("&reporttype") = %str("T2L1") | %str("&reporttype") = %str("T6")) and %sysfunc(prxmatch(m/02|03/i,&cohortdef.))) > 0 | (%str("&reporttype") = %str("T4L1") and %str("&cohort.") ne %str("mi")) %then %do; 1 %end; /* Sdthreshold greater than 0 */ %if &sdthreshold. > 0 %then %do; 2 %end; %if %index(&reporttype,L2) %then %do; /* L2 weighted table for PS stratification where weight is ATE */ %if &psfile. = stratificationfile and %index(&weight.,Weighted) > 0 %then %do; %if "&weightscheme." = "ATE" %then %do; 4 %end; /* L2 weighted table for PS stratification where weight is ATT */ %else %if "&weightscheme." = "ATT" %then %do; 5 %end; /* L2 weighted table for PS stratification where weight is Blank */ %else %do; 6 %end; %end; %if &psfile. = iptwfile and %index(&table.,Adjusted) > 0 and %index(&weight.,Weighted) > 0 %then %do; /* L2 weighted table for IPTW where weight is ATE */ %if "&weightscheme." = "ATE" %then %do; 7 %end; /* L2 weighted table for IPTW where weight is ATES */ %else %if "&weightscheme." = "ATES" %then %do; 8 %end; /* L2 weighted table for IPTW where weight is ATT */ %else %if "&weightscheme." = "ATT" %then %do; 9 %end; %end; /* L2 weighted table for variable ratio matching */ %if &psfile = psmatchfile and &ratio. = V and %index(&table.,Adjusted) > 0 %then %do; 10 %end; %end; /* T4L2, T4L1 with MIL */ %if (%str("&reporttype.") = %str("T4L1") and %str("&cohort.") = %str("mi")) | %str("&reporttype.") = %str("T4L2") %then %do; 11 %end; /* T6 Switching */ %if %str("&reporttype.") = %str("T6") %then %do; /* 1st switch */ %if %eval(&maxswitch > 0) %then %do; 12 %end; /* 2nd Switch */ %if %eval(&maxswitch=2) %then %do; 13 %end; %end; /* Comorbidscore is specified */ %if &comorbidscore = Y %then %do; 18 %end; /* Lab characteristics specified. */ %if %str("&labcharacteristics.") ^= %str("missing") %then %do; 20 %end; )) %if %index(&reporttype,T4) > 0 %then %do; or (type='type4' and order in (-2 %if &includenonpregnant = Y %then %do; -1 %end; )) %end; )); by order; footnote_order = _n_; run; /*Set first word for SDthreshold footnote*/ %if %str(&sdthreshold.) ne %str() %then %do; %if %index(&reporttype,L2) %then %let covar_characteristic = Covariates; %else %let covar_characteristic = Characteristics; %end; proc sql noprint; select count(order) into: num_fn trimmed from _footnotes; select description into: fn1 - :fn&num_fn. from _footnotes order by order; quit; /* Assign macro variables for superscipts */ %assign_superscripts(type =title, order =-2 -1); %assign_superscripts(type =character, order =1 2 4 5 6 7 8 9 10 11 ); %assign_superscripts(type =max_cell_width, order =4 5 6 7 8 9 10 18 ); %assign_superscripts(type =switch1, order =12); %assign_superscripts(type =switch2, order =13); %assign_superscripts(type =stdev, order =14); %assign_superscripts(type =race, order =15); %assign_superscripts(type =unknownrace, order =16); %assign_superscripts(type =gestage, order =17); %assign_superscripts(type =comorbidscore, order =18 %if %length(&covnotinps.) > 0 and %index(%trim(&covnotinps), COMORBIDSCORE) > 0 %then %do; &covnotinpsorder. %end;); %assign_superscripts(type =covar, order =&covnotinpsorder.); %assign_superscripts(type =labcovar, order =20); /*determine optimal report formatting*/ %let labelwidth = 3.5; %let width = 1.15; %let linebreak = ; %let headerheight = .3; %if %eval(&numcolumns.=4) %then %do; %let labelwidth = 3; %let width = 1.15; %let linebreak = ; %let headerheight = .3; %end; %else %if %eval(&numcolumns.=6) %then %do; %let labelwidth = 3; %let width = .85; %let linebreak = ^n; %let headerheight = .45; %end; %if %length(&pregnancylabel.)>0 %then %let cohortheaderlabel = Cohort; %else %let cohortheaderlabel = Medical Product; %if &destination. = excel %then %do; ods excel options(sheet_name="Table 1&tableletter." tab_color = "lightgreen" flow="1:400"); %let linebreak = ; /*reset line break and headerheight*/ %let headerheight = .3; %if %eval(&numcolumns.=6) %then %let width = 1; %end; ods proclabel = "Table 1&tableletter."; proc report data=repdata.table1&tableletter. nofs nowd spanrows split='*' style(header)=[rules=none frame=void background=BGR borderleftcolor = BGR vjust=b] split='*' style(report)=[rules=none frame=void cellpadding =1.5pt]; column (metvar grouper label %if &computebalance. = Y %then %do; ("^S={background=BGR}&cohortheaderlabel." %end; ("^S={background=BGR}&grp1_label." exp_mean&dpnum._char exp_std&dpnum._char) %if &includecomp. = Y %then %do; ("^S={background=BGR}&grp2_label.&super_switch1." comp_mean&dpnum._char comp_std&dpnum._char) %end; %if &computebalance. = Y %then %do; ) %end; %if %eval(&maxswitch.=2) %then %do; ("^S={background=BGR}&grp3_label.&super_switch2." switch2_mean&dpnum._char switch2_std&dpnum._char) %end; %if &computebalance. = Y %then %do; %if %index(&reporttype,L2) %then %do; ('^S={background=BGR}Covariate Balance' '^S={background=BGR}' ad&dpnum._char sd&dpnum._char) %end; %else %do; ('^S={background=BGR}Characteristic Balance' '^S={background=BGR}' ad&dpnum._char sd&dpnum._char) %end; %end; ); define metvar / noprint; define grouper / order noprint order=data ''; define label / display "&characteristiclabel. Characteristics&super_character." style(column)=[width=&labelwidth.in just=L] style(header)=[background = LIBGR just=L cellheight=&headerheight.in]; define exp_mean&dpnum._char / display 'Number/Mean' style(column)=[width=&width.in background = $backgroundfmt. tagattr="type:string"] style(header)=[background = LIBGR borderleftcolor = LIBGR cellheight=&headerheight.in]; define exp_std&dpnum._char / display "Percent/^n Standard&linebreak. Deviation&super_stdev." style(column)=[width=&width.in tagattr="type:string"] style(header)=[background = LIBGR borderleftcolor = LIBGR cellheight=&headerheight.in]; %if &includecomp. = Y %then %do; define comp_mean&dpnum._char / display 'Number/Mean' style(column)=[width=&width.in background = $backgroundfmt. tagattr="type:string"] style(header)=[background=LIBGR borderleftcolor = LIBGR cellheight=&headerheight.in]; define comp_std&dpnum._char / display "Percent/^n Standard&linebreak. Deviation&super_stdev." style(column)=[width=&width.in tagattr="type:string"] style(header)=[background=LIBGR borderleftcolor = LIBGR cellheight=&headerheight.in]; %end; %if %eval(&maxswitch.=2) %then %do; define switch2_mean&dpnum._char / display 'Number/Mean' style(column)=[width=&width.in background = $backgroundfmt. tagattr="type:string"] style(header)=[background=LIBGR borderleftcolor = LIBGR cellheight=&headerheight.in]; define switch2_std&dpnum._char / display "Percent/^n Standard&linebreak. Deviation&super_stdev." style(column)=[width=&width.in tagattr="type:string"] style(header)=[background=LIBGR borderleftcolor = LIBGR cellheight=&headerheight.in]; %end; %if &computebalance. = Y %then %do; define ad&dpnum._char / display 'Absolute^n Difference' style(column)=[width=&width.in background = $backgroundfmt. tagattr="type:string"] style(header)=[background=LIBGR borderleftcolor = LIBGR cellheight=&headerheight.in]; define sd&dpnum._char / display 'Standardized^n Difference' style(column)=[width=&width.in tagattr="type:string"] style(header)=[background=LIBGR borderleftcolor = LIBGR cellheight=&headerheight.in]; %end; /*Add Characteristic header lines and superscript to Lab characteristic header */ compute before grouper / style=[background=LIBGR color=black just=L font_weight=bold]; length text $100; if grouper ne "&characteristiclabel. Characteristics" then do; if grouper = "Laboratory Characteristics" then do; text=catt(grouper,"&super_labcovar."); end; else do; text=grouper; end; num=100; end; else do; text = ""; num=0; end; line text $Varying. num; endcomp; /*Indent demographic header lines and lab covariate record lines*/ compute label; if index(label,'Race') > 0 then label = catt(label,"&super_race."); else if index(label,'Charlson/Elixhauser') > 0 then label = catt(label,"&super_comorbidscore."); %if %length(&covnotinps.) > 0 %then %do; else if metvar in (&covnotinps.) and metvar eq 'GA_BIRTH' and label = "Gestational age at delivery" then label = "Gestational age&super_gestage. at delivery&super_covar."; %end; else if label = "Gestational age at delivery" then label = "Gestational age&super_gestage. at delivery"; %if %length(&covnotinps.) > 0 %then %do; else if metvar in (&covnotinps.) and metvar eq 'GA_FIRST' and label = "Gestational age of first exposure (weeks)" then label = "Gestational age&super_gestage. of first exposure (weeks)&super_covar."; %end; else if label = "Gestational age of first exposure (weeks)" then label = "Gestational age&super_gestage. of first exposure (weeks)"; %if %length(&covnotinps.) > 0 and %length(&covarlablabels.) > 0 %then %do; else if upcase(label) in (&covarlablabels.) then label = catt(label, "&super_covar."); %end; %if %length(&covnotinps.) > 0 %then %do; /*Comborbidscore already included in &super_comorbidscore*/ else if metvar in (&covnotinps.) and upcase(label) ne "TEST RECORD" and metvar ne 'COMORBIDSCORE' then label = catt(label, "&super_covar."); %end; if prxmatch('/AGE\d|YEAR*|RACE*|HISPANIC*|SEX*/',metvar) > 0 then do; call define(_col_,'style','style={indent=25}'); end; %if %str("&labcharacteristics.") ^= %str("missing") %then %do; if prxmatch('/^(Test record|No test record|Test record with missing or unknown units)$|Test record in/', strip(label)) then do; call define(_col_,'style','style={indent=25}'); end; else if prxmatch('/^(Borderline|Negative|Positive|Invalid categorical result|Undetermined|Mean, standard deviation)$|\|/', strip(label)) then do; call define(_col_,'style','style={indent=50}'); call define(_row_,'style','style={fontstyle=italic}'); end; %end; /*assign unknown race footnote*/ %if &collapse_vars. = race %then %do; if metvar = 'RACE_0' then label = catt(label,"&super_unknownrace."); %end; endcomp; /*Change font color to blue if abs(SD) > threshold value*/ %if &computebalance. = Y and %length(&sdthreshold.) > 0 %then %do; compute sd&dpnum._char; if upcase(strip(sd&dpnum._char)) not in ("", ".", "N/A", "NAN") then do; if abs(input(sd&dpnum._char, 8.3)) > &sdthreshold. then do; call define(_row_,'style','style={foreground=blue}'); end; end; endcomp; %end; /*Add title*/ compute before _page_ / style=[background=white font_weight=bold just=L foreground=black vjust=b bordertopcolor = white borderbottomwidth = &bordersize tagattr="wrap:yes" nobreakspace=off cellheight=.3in]; line "&title.&super_title."; endcomp; /* Add Footnotes */ compute after / style=[just=L nobreakspace=off borderbottomcolor=white bordertopcolor=black vjust=T fontsize=&footfontsize. height=1.75in bordertopwidth = &bordersize]; %do f = 1 %to &num_fn.; line "^{super &f.}&&fn&f."; %end; endcomp; *Remove collapsed rows; %if &collapse_vars. = race %then %do; where exp_mean&dpnum. ne .R %if &includecomp. = Y %then %do; & comp_mean&dpnum. ne .R %end; %if %eval(&maxswitch.=2) %then %do; & switch2_mean&dpnum. ne .R %end; ; %end; run; /*clean up*/ proc datasets nowarn noprint lib=work; delete _footnotes; quit; %mend baseline_procreport; /*counter for determining table letter*/ %let tablecount = 1; /*loop through each baseline table*/ %do b = 1 %to &numbaselinetablegrp.; %let analysisgrp = ; %let analysisgrp2 = ; %let baselinegroupnum = ; %let pregnancylabel = ; %let includenonpregnant = N; %let includecomp = N; %let computebalance =N; %let maxswitch = 0; %let covnotinps = ; /*for L2 tables - need to reference PS/CS specific files to pull additional parameters*/ %let ratio = F; %let psfile = ; %let weightlabel = ; %let weightscheme = ; %let pstrim = ; %let percentiles=; %let ratiolabel = ; %let caliperlabel = ; %let truncationlabel = ; %let psestimategrp = ; %let unadjusted = ; %let eoi = ; %let ref = ; %let switch0group = ; %let switch1group = ; %let switch2group = ; /*parameters for %baseline_procreport*/ %if %sysfunc(prxmatch(m/T4L1|T4L2/i,&reporttype.)) >0 %then %let characteristiclabel = Mother; %else %let characteristiclabel = Patient; %let grp1_label=; %let grp2_label=; %let grp3_label=; data _null_; set baselinefile(where=(order=&b.)); if _n_ = 1 then do; call symputx('analysisgrp', strip(analysisgrp)); call symputx('runid', runid); call symputx('cohort', cohort); call symputx('cohortdef',cohortdef); call symputx('comorbidscore',comorbidscore); call symputx('gestationalage',gestationalage); call symputx('unique_psestimate',unique_psestimate); call symputx('unique_psestimate_orig',unique_psestimate); if missing(sdthreshold) then call symputx('sdthreshold', ''); else call symputx('sdthreshold', sdthreshold); if missing(labcharacteristics) then call symputx('labcharacteristics',"missing"); else call symputx('labcharacteristics', labcharacteristics); %if %str("&reporttype") = %str("T2L2") | %str("&reporttype") = %str("T4L2") %then %do; if missing(covnotinps)=0 then call symputx('covnotinps', strip(upcase(covnotinps))); call symputx('computebalance', 'Y'); %end; %else %do; if computebalance = 'Y' then call symputx('computebalance', 'Y'); %end; %if %sysfunc(prxmatch(m/T4L1/i,&reporttype.)) > 0 %then %do; if cohort in ('preg', 'nopreg') then do; if upcase(includenonpregnant) = 'Y' then call symput('pregnancylabel', ' Pregnancy Cohort and Non-Pregnancy Cohort'); else call symput('pregnancylabel', ' Pregnancy Cohort'); end; call symputx('includenonpregnant', upcase(includenonpregnant)); %end; if missing(baselinegroupnum)=0 then call symputx('baselinegroupnum', baselinegroupnum); /*if reporttype = T2L2, T4L2, T6, or cohort = mi or includenonpreggroup = Y, or BASELINEGROUPNUM is specified then include COMP columns*/ if "&reporttype."="T2L2" | "&reporttype."="T4L2" | "&reporttype."="T6" | upcase(computebalance)= 'Y' | upcase(includenonpregnant) = 'Y' | cohort = "mi" | missing(baselinegroupnum)=0 then do; call symputx('includecomp', 'Y'); end; else do; call symputx('includecomp', 'N'); end; end; /*if baselinegroupnum is specified, a 2nd row will exist in the file*/ if _n_ = 2 then do; if missing(baselinegroupnum)=0 then do; call symputx('analysisgrp2',analysisgrp); end; end; run; /* Assign patient/episode label for lab footnote based on cohortdef value */ %if %str("&labcharacteristics.") ^= %str("missing") %then %do; %if %sysfunc(prxmatch(/01|04/,&cohortdef)) %then %let patientepi = patients; %else %if %sysfunc(prxmatch(/02|03/,&cohortdef)) %then %let patientepi = episodes; %end; /*Additional meta-data and group-specific names for each reporttype*/ %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) > 0 %then %do; data _null_; set pscs_masterinputs(where=(analysisgrp = "&analysisgrp." and missing(subgroup) ne 0)); call symputx('psfile', strip(file)); call symputx('psestimategrp', psestimategrp); call symput('unadjusted', 'Unadjusted '); /*for unadjusted table label*/ if file = 'psmatchfile' then do; call symputx('ratio',upcase(ratio)); if upcase(ratio)='F' then call symputx("ratiolabel",'Fixed Ratio 1:'||strip(put(ceiling, 8.))); if upcase(ratio)='V' then call symputx("ratiolabel",'Variable Ratio 1:'||strip(put(ceiling, 8.))); call symputx("caliperlabel", cat(', Caliper: ', caliper)); end; if file = 'stratificationfile' then do; call symputx('pstrim', pstrim); call symputx('percentiles', percentiles); if missing(strataweight) =0 then call symputx('weightscheme', strataweight); if upcase(strataweight)= 'ATE' or missing(strataweight) then call symputx("weightlabel","Average Treatment Effect (ATE)"); else if upcase(strataweight)= 'ATT' then call symputx("weightlabel","Average Treatment Effect in the Treated (ATT)"); end; if file = 'iptwfile' then do; if upcase(ipweight)= 'ATE' then call symputx("weightlabel","Average Treatment Effect (ATE)"); else if upcase(ipweight)= 'ATES' then call symputx("weightlabel","Average Treatment Effect, Stabilized (ATES)"); else if upcase(ipweight)= 'ATT' then call symputx("weightlabel","Average Treatment Effect in the Treated (ATT)"); call symputx('weightscheme', upcase(ipweight)); call symputx('truncationlabel',strip(put(truncweight, best.))); end; run; /*pull EOI and REF group names*/ %if &psfile. = psmatchfile | &psfile. = stratificationfile | &psfile. = iptwfile %then %do; data _null_; set infolder.&&&runid._&psfile.(where=(analysisgrp="&analysisgrp.")); call symputx('psestimategrp', psestimategrp); run; data _null_; set infolder.&&&runid._psestimationfile(where=(psestimategrp="&psestimategrp.")); call symputx('eoi', strip(eoi)); call symputx('ref', strip(ref)); run; %end; %else %if &psfile. = covstratfile %then %do; data _null_; set infolder.&&&runid._covstratfile(where=(analysisgrp="&analysisgrp.")); call symputx('eoi', strip(eoi)); call symputx('ref', strip(ref)); run; %end; /*Defensive check for sdthreshold and covnotinps parameters*/ %if %eval(&unique_psestimate.) ne 1 %then %do; proc sql noprint; create table baseline_unique_check as select a.analysisgrp, a.psestimategrp, a.sdthreshold, a.covnotinps from baselinefile as a left join pscs_masterinputs as b on a.analysisgrp = b.analysisgrp and a.psestimategrp = a.psestimategrp where b.subgroup="" order by a.order; quit; proc sql noprint; select count (distinct sdthreshold) into :sdthreshold_count trimmed from baseline_unique_check where psestimategrp = "&psestimategrp"; select count (distinct covnotinps) into :covnotinps_count trimmed from baseline_unique_check where psestimategrp = "&psestimategrp"; quit; %if %eval(&sdthreshold_count. > 1) or %eval(&covnotinps_count. > 1) %then %do; %put WARNING: (Sentinel) SDTHRESHOLD or covnotinps value differs across analyses that share the same psestimategrp.; %put PSESTIMATEGRP=&psestimategrp has &sdthreshold_count SDTHRESHOLD distinct value(s) and &covnotinps_count covnotinps distinct value(s); /* If multiple values are detected for a same psestimategrp, assign the first available value for this psestimategrp (already sorted by order)*/ data _null_; set baseline_unique_check(where=(psestimategrp = "&psestimategrp")); if _N_=1; if missing(sdthreshold) then call symputx('sdthreshold', ''); else call symputx('sdthreshold', sdthreshold); call symputx('covnotinps', strip(upcase(covnotinps))); run; %end; %end; %end; %else %if %sysfunc(prxmatch(m/T6/i,&reporttype.)) > 0 %then %do; /*determine maximum switch*/ proc sql noprint; select max(switchevalstep) into: maxswitch trimmed from infolder.&&&runid._treatmentpathways(where=((analysisgrp="&analysisgrp."))); quit; data _null_; set infolder.&&&runid._treatmentpathways(where=((analysisgrp="&analysisgrp."))); if switchevalstep = 0 then call symputx('switch0group', strip(group)); if switchevalstep = 1 then call symputx('switch1group', strip(group)); %if %eval(&maxswitch=2) %then %do; if switchevalstep = 2 then call symputx('switch2group', strip(group)); %end; run; %end; %if %length(&covnotinps.) > 0 %then %baseline_expand_parameters(var=covnotinps); /*For L1 tables, determine if only 1 baseline table and set &tablecount to 0. Will occur if all the following are true: - 1 monitoring period - DP stratification = N - max(order) in baselinefile = 1 For L2 tables, tablecount assigned in macro baselinereport*/ %if %eval(&b.=1) & %eval(&look_start.) = %eval(&look_end.) & &stratifybydp. = N & %eval(&numbaselinetablegrp.=1) %then %do; %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) = 0 %then %do; %let tablecount = 0; %end; %end; /*Assign labels*/ %let baselinelabel = ; %let grouplabel = &analysisgrp.; %let psestimatelabel = &psestimategrp.; %if %length(&baselinegroupnum.)>0 %then %do; %let grouplabel2 = &analysisgrp2.; %end; %if %sysfunc(prxmatch(m/T6/i,&reporttype.)) > 0 %then %do; %let switch0grplabel = &switch0group.; %let switch1grplabel = &switch1group.; %if %eval(&maxswitch=2) %then %do; %let switch2grplabel = &switch2group.; %end; %end; %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) > 0 %then %do; %let eoilabel = &eoi.; %let reflabel = &ref.; %end; %if %sysfunc(prxmatch(m/T4L1/i,&reporttype.)) > 0 & &cohort. = mi %then %do; %let eoilabel = &analysisgrp._eoi; %let reflabel = &analysisgrp._ref; %end; %isdata(dataset=labelfile); %if %eval(&nobs.>0) %then %do; data _null_; set labelfile(in=a where=(group="&analysisgrp" and runid = "&runid")) %if %length(&baselinegroupnum.)>0 %then %do; labelfile(in=b where=(group="&analysisgrp2" and runid = "&runid")) %end; %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) > 0 %then %do; labelfile(in=c where=(group="&psestimategrp" and runid = "&runid")) labelfile(in=d where=(group="&eoi" and runid = "&runid")) labelfile(in=e where=(group="&ref" and runid = "&runid")) %end; %if %sysfunc(prxmatch(m/T6/i,&reporttype.)) > 0 %then %do; labelfile(in=f where=(group="&switch0group." and runid = "&runid")) labelfile(in=g where=(group="&switch1group." and runid = "&runid")) %if %eval(&maxswitch=2) %then %do; labelfile(in=h where=(group="&switch2group." and runid = "&runid")) %end; %end; %if %sysfunc(prxmatch(m/T4L1/i,&reporttype.)) > 0 & &cohort. = mi %then %do; labelfile(in=i where=(group="&analysisgrp._eoi" and runid = "&runid")) labelfile(in=j where=(group="&analysisgrp._ref" and runid = "&runid")) %end; ; if a then do; if labeltype = 'grouplabel' then call symputx('grouplabel',strip(label)); if labeltype = 'baselinelabel' then call symputx('baselinelabel',cat(', ',strip(label), ',')); end; %if %length(&baselinegroupnum.)>0 %then %do; if b then do; if labeltype = 'grouplabel' then call symputx('grouplabel2',strip(label)); end; %end; %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) > 0 %then %do; if c then do; if labeltype = 'grouplabel' then call symputx('psestimatelabel',strip(label)); end; if d then do; if labeltype = 'grouplabel' then call symputx('eoilabel',strip(label)); end; if e then do; if labeltype = 'grouplabel' then call symputx('reflabel',strip(label)); end; %end; %if %sysfunc(prxmatch(m/T6/i,&reporttype.)) > 0 %then %do; if f then do; if labeltype = 'grouplabel' then call symputx('switch0grplabel',strip(label)); end; if g then do; if labeltype = 'grouplabel' then call symputx('switch1grplabel',strip(label)); end; %if %eval(&maxswitch=2) %then %do; if h then do; if labeltype = 'grouplabel' then call symputx('switch2grplabel',strip(label)); end; %end; %end; %if %sysfunc(prxmatch(m/T4L1/i,&reporttype.)) > 0 & &cohort. = mi %then %do; if i then do; if labeltype = 'grouplabel' then call symputx('eoilabel',strip(label)); end; if j then do; if labeltype = 'grouplabel' then call symputx('reflabel',strip(label)); end; %end; ; run; %end; /*Set group labels*/ %if %sysfunc(prxmatch(m/T1|T5|T2L1/i,&reporttype.)) > 0 %then %do; %let grp1_label = %bquote(&grouplabel.); %end; %else %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) > 0 %then %do; %let grp1_label = %bquote(&eoilabel.); %let grp2_label = %bquote(&reflabel.); %end; %else %if %sysfunc(prxmatch(m/T6/i,&reporttype.)) > 0 %then %do; %let grp1_label = %bquote(&switch0grplabel.); %let grp2_label = %bquote(&switch0grplabel. to &switch1grplabel.); %if %eval(&maxswitch=2) %then %do; %let grp3_label = %bquote(&switch1grplabel. to &switch2grplabel.); %end; %end; %else %if %sysfunc(prxmatch(m/T4L1/i,&reporttype.)) > 0 %then %do; %if &cohort = mi %then %do; /*MI exposure and reference cohorts*/ %let grp1_label = %bquote(&eoilabel.); %let grp2_label = %bquote(&reflabel.); %end; %else %do; /*Pregnant and non-pregnant cohorts*/ %let grp1_label = %bquote(&grouplabel. Pregnancy Cohort); %if &includenonpregnant. = Y %then %do; %let grp2_label = %bquote(&grouplabel. Non-Pregnancy Cohort); %end; %end; %end; %if %length(&baselinegroupnum.)>0 %then %do; %let grp2_label = %bquote(&grouplabel2.); %if %sysfunc(prxmatch(m/T4L1/i,&reporttype.)) > 0 %then %do; %let grp2_label = %bquote(&grouplabel2. Pregnancy Cohort); %end; %end; /*Determine number of columns to optimize formatting*/ %let numcolumns = 2; %if &includecomp. = Y %then %do; %let numcolumns = %eval(&numcolumns.+2); %end; %if &computebalance. = Y %then %do; %let numcolumns = %eval(&numcolumns.+2); %end; %if %eval(&maxswitch=2) %then %do; %let numcolumns = %eval(&numcolumns.+2); %end; /*1 block of code for both aggregate and DP tables*/ %macro baselinereport(dpnum=, aggregated=, dpinparenthesis=, dpcomma=); * Process L2 subgroups; %let numsubgroups=0; %let subgroup=; %let subgroupcat=; %let subgrouptitle=; %if &reporttype = T2L2 or &reporttype = T4L2 %then %do; proc sort nodupkey data=Pscs_masterinputs(where=(analysisgrp="&analysisgrp." and runid="&runid." and not missing(subgroup))) out=_subgroups(keep=subgroup subgroupcat subgrouporder subgroupcatorder combinedlabel); by subgrouporder subgroupcatorder; run; proc sql noprint; select count(*) into :numsubgroups from _subgroups; quit; %end; %do sub=0 %to &numsubgroups.; %if &sub. > 0 %then %do; data _null_; set _subgroups; if _N_=&sub.; call symputx("SubGroup",lowcase(strip(subgroup))); call symputx("SubgroupCat",upcase(strip(subgroupcat))); call symputx("subgrouptitle",combinedlabel); run; %let captionlabel = %bquote(&grouplabel.&pregnancylabel&baselinelabel.); %let unique_psestimate = 1; %end; %else %do; %let captionlabel = %bquote(&grouplabel.&pregnancylabel&baselinelabel.); %if %length(&baselinegroupnum.)>0 %then %do; %let captionlabel = %bquote(&grouplabel.&pregnancylabel and &grouplabel2.&pregnancylabel&baselinelabel.); %end; %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) >0 & &psfile. ne covstratfile %then %do; %let captionlabel = %bquote(&psestimatelabel.); %end; %let unique_psestimate = &unique_psestimate_orig; %end; /*For L2 queries, set &tablecount to 0 if covariate stratification AND no subgroups*/ %if &psfile. = covstratfile and &numsubgroups. = 0 and %eval(&look_start.) = %eval(&look_end.) and &stratifybydp. = N and %eval(&numbaselinetablegrp.=1) %then %let tablecount = 0; %if %eval(&unique_psestimate.) = 1 %then %do; %tableletter(); %baseline_procreport(order = &b., table = 'Unadjusted', weight ='Unweighted', title =%quote(Table 1&tableletter.. &aggregated.&unadjusted.Characteristics of &captionlabel. &dpinparenthesis.in the &database. from &startdateformatted. to &&enddate&periodid.formatted.&subgrouptitle.), characteristiclabel =&characteristiclabel., labcharacteristics = %quote(&labcharacteristics), dpnum = &dpnum., numcolumns =&numcolumns., grp1_label=&grp1_label., grp2_label=&grp2_label., grp3_label=&grp3_label., computebalance = &computebalance., includenonpregnant=&includenonpregnant.); %end; /*For L2 tables - up to 2 additional adjusted tables*/ %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) > 0 %then %do; /*PS Match Adjusted*/ %if &psfile. = psmatchfile %then %do; %tableletter(); %baseline_procreport(order = &b., table = 'Adjusted', weight = %str('Unweighted', 'Weighted'), title =%quote(Table 1&tableletter.. &aggregated.Adjusted Characteristics of &grouplabel. (Propensity Score Matched&dpcomma., &ratiolabel.&caliperlabel.) in the &database. from &startdateformatted. to &&enddate&periodid.formatted.&subgrouptitle.), characteristiclabel =&characteristiclabel., labcharacteristics = %quote(&labcharacteristics), dpnum = &dpnum., numcolumns =&numcolumns., grp1_label=&grp1_label., grp2_label=&grp2_label., grp3_label=&grp3_label., computebalance = &computebalance., includenonpregnant=&includenonpregnant.); %end; /*Unweighted - IPTW and PS Stratum*/ %if (&psfile. = iptwfile & %eval(&unique_psestimate.) = 1) | (&psfile. = stratificationfile & ("&weightscheme." = "ATE" | "&weightscheme." = "ATT") & %eval(&pstrim.>=0)) %then %do; %tableletter(); %baseline_procreport(order = &b., table = 'Adjusted', weight = 'Unweighted', title=%quote(Table 1&tableletter.. &aggregated.Unweighted Characteristics of &grouplabel. (Unweighted, Trimmed&dpcomma.) in the &database. from &startdateformatted. to &&enddate&periodid.formatted.&subgrouptitle.), characteristiclabel =&characteristiclabel., labcharacteristics = %quote(&labcharacteristics), dpnum = &dpnum., numcolumns =&numcolumns., grp1_label=&grp1_label., grp2_label=&grp2_label., grp3_label=&grp3_label., computebalance = &computebalance., includenonpregnant=&includenonpregnant.); %end; /*Weighted - IPTW, PS Stratum, PS Stratification*/ %if &psfile. = iptwfile | &psfile. = stratificationfile %then %do; %if &psfile. = iptwfile %then %let stratumtitle = Inverse Probability of Treatment Weighted, Trimmed&dpcomma., Weight: &weightlabel., Truncation: &truncationlabel.%nrbquote(%); %else %if "&weightscheme." = "ATE" | "&weightscheme." = "ATT" %then %let stratumtitle = Propensity Score Stratum Weighted, Trimmed&dpcomma., Percentiles: &percentiles., Weight: &weightlabel.; %else %let stratumtitle =Propensity Score Stratified&dpcomma., Percentiles: &percentiles.; %tableletter(); %baseline_procreport(order = &b., table = 'Adjusted', weight = 'Weighted', title=%quote(Table 1&tableletter.. &aggregated.Weighted Characteristics of &grouplabel. (&stratumtitle.) in the &database. from &startdateformatted. to &&enddate&periodid.formatted.&subgrouptitle.), characteristiclabel =&characteristiclabel., labcharacteristics = %quote(&labcharacteristics), dpnum = &dpnum., numcolumns =&numcolumns., grp1_label=&grp1_label., grp2_label=&grp2_label., grp3_label=&grp3_label., computebalance = &computebalance., includenonpregnant=&includenonpregnant.); %end; %end; /*Additional L2 tables*/ %end; /*Subgroups looping*/ %mend; /*loop through each periodid*/ %do periodid = %eval(&look_start.) %to %eval(&look_end.); /*Aggregated*/ %baselinereport(dpnum=0, %if %eval(&num_dp.)=1 %then %do; aggregated=, %end; %else %do; aggregated=%str(Aggregated ), %end; dpinparenthesis=, dpcomma=); /*Output seperate table for each Data Partner - loop through each DP*/ %if &stratifybydp. = Y %then %do; %do dps = 1 %to %eval(&num_dp.); %let maskedID = %scan(&masked_dplist,&dps); %baselinereport(dpnum=&dps., aggregated = , dpinparenthesis=%str((&maskedid.) ), dpcomma=%str(, &maskedid.)); %end; %end; /*DP stratification*/ %end; /*loop through each periodid*/ %end; /*loop through each row in baselinefile*/ %end; /*include baseline tables */ %put =====> END MACRO: baseline_output ; %mend baseline_output;