**************************************************************************************************** * PROGRAM OVERVIEW **************************************************************************************************** * * PROGRAM: create_tableofcontents.sas * Created (mm/dd/yyyy): 02/09/2021 * *-------------------------------------------------------------------------------------------------- * PURPOSE: This macro createas a dataset with 1 row per table and figure that is used as the * report table of contents * * Program inputs: * * Program outputs: * -tableofcontents: dataset containing table of contents * * PARAMETERS: * * Programming Notes: * * *-------------------------------------------------------------------------------------------------- * CONTACT INFO: * Sentinel Coordinating Center * info@sentinelsystem.org * ***************************************************************************************************; %macro create_tableofcontents(); %put =====> MACRO CALLED: create_tableofcontents; /*********************************************************************************************/ /* Utility macro to add row to tableofcontents file */ /*********************************************************************************************/ %macro addtotoc(tabnum=, caption=, appendixtype=); data tableofcontents; set tableofcontents end=eof; output; if eof then do; tabnum = "&tabnum."; caption = "&caption."; appendixtype = "&appendixtype."; output; end; run; %mend; /*********************************************************************************************/ /* Initialize empty table and table number */ /*********************************************************************************************/ data tableofcontents; length tabnum $25 caption $500 appendixtype $30; call missing(tabnum, caption, appendixtype); run; %let number = 1; %let tablenum = 1; /*********************************************************************************************/ /* Build table of contents */ /*********************************************************************************************/ /*****************/ /* Glossary rows */ /*****************/ %addtotoc(tabnum=Glossary (CIDA), caption=List of Terms to Define Cohort Identification and Descriptive Analysis (CIDA) Found in this Report); %if %str("&reporttype") = %str("T2L2") | %str("&reporttype") = %str("T4L2") %then %do; %addtotoc(tabnum=Glossary (PSA), caption=List of Terms to Define Propensity Score Analysis (PSA) Found in this Report); %end; /******************/ /* Baseline Table */ /******************/ %if %eval(&numbaselinetablegrp.>0) %then %do; /*counter for determining table letter*/ %let tablecount = 1; /* counter for determining table number */ %let tablenum = 2; /*loop through each baseline table*/ %do b = 1 %to &numbaselinetablegrp.; %let analysisgrp = ; %let analysisgrp2 = ; %let baselinegroupnum = ; %let pregnancylabel = ; %let includenonpregnant = N; /*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 = ; data _null_; set baselinefile(where=(order=&b.)); if _n_ = 1 then do; call symputx('analysisgrp', analysisgrp); call symputx('runid', runid); call symputx('cohort', cohort); call symputx('unique_psestimate',unique_psestimate); %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); 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; %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) > 0 %then %do; data _null_; set pscs_masterinputs(where=(analysisgrp = "&analysisgrp." and covarnum=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('truncationlabel',strip(put(truncweight, best.))||'%'); end; run; %end; /*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 - if reporttype = T2L2, T4L2- then analysis must be covariate stratification*/ %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; %else %do; %if &psfile. = covstratfile %then %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; %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")) %end; ; if a then do; if labeltype = 'grouplabel' then call symputx('grouplabel',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',label); end; %end; %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) > 0 & &psfile. ne covstratfile %then %do; if c then do; if labeltype = 'grouplabel' then call symputx('psestimatelabel',label); end; %end; run; %end; %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; /*1 block of code for both aggregate and DP tables*/ %macro baselinetoc(table); %if %eval(&unique_psestimate.) = 1 %then %do; %tableletter(); %addtotoc(tabnum=Table 1&tableletter., caption=%quote(&unadjusted.Characteristics of &captionlabel. (&table.) in the &database. from &startdateformatted. to &&enddate&periodid.formatted.)); %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(); %addtotoc(tabnum=Table 1&tableletter., caption=%quote(Adjusted Characteristics of &grouplabel. (Propensity Score Matched, &table.), &ratiolabel.&caliperlabel., in the &database. from &startdateformatted. to &&enddate&periodid.formatted.)); %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(); %addtotoc(tabnum=Table 1&tableletter., caption=%quote(Unweighted Characteristics of &grouplabel. (Unweighted, Trimmed, &table.) in the &database. from &startdateformatted. to &&enddate&periodid.formatted.)); %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, &table.), Weight: &weightlabel., Truncation: &truncationlabel.; %else %if "&weightscheme." = "ATE" | "&weightscheme." = "ATT" %then %let stratumtitle = (Propensity Score Stratum Weighted, Trimmed, &table.), Percentiles: &percentiles., Weight: &weightlabel.; %else %let stratumtitle =(Propensity Score Stratified, &table.), Percentiles: &percentiles.; %tableletter(); %addtotoc(tabnum=Table 1&tableletter., caption=%quote(Weighted Characteristics of &grouplabel. &stratumtitle., in the &database. from &startdateformatted. to &&enddate&periodid.formatted.)); %end; %end; /*Additional L2 tables*/ %mend; /*loop through each periodid*/ %do periodid = %eval(&look_start.) %to %eval(&look_end.); /*Aggregated*/ %baselinetoc(Aggregated); /*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); %baselinetoc(&maskedid.); %end; %end; /*DP stratification*/ %end; /*loop through each periodid*/ %end; /*loop through each row in baselinefile*/ %end; /*include baseline tables in toc*/ /***************************/ /* Covariate Profile Table */ /***************************/ %if &numprofilecovarstoinclude > 0 %then %do; /* reset counter to reset table letter */ %let tablecount = 1; %do periodid = %eval(&look_start.) %to %eval(&look_end.); proc sql noprint ; select 'order='||strip(put(order,8.))||' and runid='||quote(strip(runid))||' and group='||quote(strip(group))||' and cohort='||quote(strip(cohort)) into :whereexpr separated by '@' from (select order, runid, group, case when(cohort is missing) then 'all' else cohort end as cohort from baselinefile where not missing(profilecovarstoinclude)) order by order; quit; %do wherenum = 1 %to %sysfunc(countw(&whereexpr, @)); %let where = %scan(&whereexpr,&wherenum, @); data _temp_agg_order_profile; set aggregate_profile(where=(periodid=&periodid and &where)); grouplabel=''; if cohort = 'mi' then group2=scan(group,1,'_'); else group2=group; if cohort = 'switch' then switchlabel = ' '; call symputx('runid',runid); run; %let profileswitches = 0; %if &reporttype = T6 %then %do; proc sql noprint; select max(switchstep) into :profileswitches from _temp_agg_order_profile; quit; %end; %isdata(dataset=_temp_agg_order_profile); %if &nobs > 0 %then %do; %do s = 0 %to &profileswitches; %if &reporttype = T6 %then %do; data _temp_agg_profile; set _temp_agg_order_profile (where=(switchstep = &s)); run; /* Join treatment file onto profile table to obtain product group */ proc sql noprint undo_policy=none; create table _temp_agg_profile as select a.*, b.group as productswitchgroup from _temp_agg_profile a inner join infolder.&&&runid._treatmentpathways b on a.group = b.analysisgrp and a.switchstep = b.switchevalstep; quit; %end; %else %do; proc datasets lib=work nolist; change _temp_agg_order_profile = _temp_agg_profile; run; %end; /* Check for existence of label file and join to profile dataset. Set grouplabel to missing if no labelfile */ %isdata(dataset=labelfile); %if &nobs > 0 %then %do; proc sql noprint undo_policy=none; create table _temp_agg_profile as select a.group, a.runid, a.order, a.periodid, b.label as grouplabel %if %index(&where,%str(cohort="mi")) %then %do; ,c.label as grouplabel2, a.group2 %end; %if %index(&where,%str(cohort="switch")) %then %do; ,d.label as switchlabel, a.productswitchgroup %end; from _temp_agg_profile(drop=grouplabel %if &reporttype = T6 %then %do; switchlabel %end;) a left join labelfile(where=(lowcase(labeltype)='grouplabel')) b on a.group = b.group and a.runid = b.runid %if %index(&where,%str(cohort="mi")) %then %do; left join labelfile(where=(lowcase(labeltype)='grouplabel')) c on a.group2 = c.group and a.runid = c.runid %end; %if %index(&where,%str(cohort="switch")) %then %do; left join labelfile(where=(lowcase(labeltype)='grouplabel')) d on a.productswitchgroup = d.group and a.runid = d.runid %end; ; quit; %end; %else %do; data _temp_agg_profile; set _temp_agg_profile; grouplabel2=''; switchlabel=''; run; %end; data _null_; set _temp_agg_profile(keep=group grouplabel order %if %index(&where,%str(cohort="mi")) %then %do; group2 grouplabel2 %end; %if %index(&where,%str(cohort="switch")) %then %do; productswitchgroup switchlabel %end; ); if _n_ = 1; if not missing(grouplabel) then call symputx('grouplabel',grouplabel); else call symputx('grouplabel',group); %if %index(&where,%str(cohort="nopreg")) %then %do; if not missing(grouplabel) then call symputx('grouplabel',catx(' ',grouplabel,'Non-Pregnancy')); else call symputx('grouplabel',catx(' ',group,'Non-Pregnancy')); %end; %else %if %index(&where,%str(cohort="preg")) %then %do; if not missing(grouplabel) then call symputx('grouplabel',catx(' ',grouplabel,'Pregnancy')); else call symputx('grouplabel',catx(' ',group,'Pregnancy')); %end; %else %if %index(&where,%str(cohort="mi")) %then %do; if not missing(grouplabel) then do; if not missing(grouplabel2) then call symputx('grouplabel',grouplabel2); else call symputx('grouplabel',group2); end; else do; call symputx('grouplabel',group2); end; %end; %else %if &reporttype = T6 %then %do; %if &s = 0 %then %do; if not missing(grouplabel) then do; call symputx('grouplabel',grouplabel); end; else do; call symputx('grouplabel',group); end; %end; %else %if &s = 1 %then %do; if not missing(grouplabel) then do; call symputx('grouplabel',grouplabel); end; else do; call symputx('grouplabel',group); end; %end; %else %if &s = 2 %then %do; if not missing(grouplabel) then do; call symputx('grouplabel',grouplabel); end; else do; call symputx('grouplabel',group); end; %end; %end; run; %tableletter(); %if &numprofilecovarstoinclude = 1 and &reporttype ^= T6 %then %let tableletter =; %else %if &numprofilecovarstoinclude = 1 and &profileswitches = 0 and &reporttype = T6 %then %let tableletter =; %addtotoc(tabnum=Table &tablenum.&tableletter., caption=%quote(Characteristic Profile of &grouplabel in the &database. from &startdateformatted. to &&enddate&periodid.formatted.)); %end; /* _temp_agg_order_profile */ %end; /* switch loop */ proc datasets library=work nowarn noprint; delete _temp_agg_profile _temp_agg_order_profile; quit; %end; /* where loop */ %end; /* periodid loop */ %let tablenum = %eval(&tablenum + 1); %end; /* &numprofilecovarstoinclude > 0 */ /*************************/ /* Effect estimate table */ /*************************/ %if &numl2comparisons > 0 %then %do; /*loop through each baseline table*/ %do c = 1 %to &numl2comparisons; /* reset counter to reset table letter */ %let tablecount = 1; data _null_; set l2comparisonfile(where=(order=&c.)); call symputx('analysisgrp', analysisgrp); call symputx('runid', runid); run; /* Merge in group labels if they exist */ %let grouplabel = &analysisgrp; %isdata(dataset=labelfile); %if %eval(&nobs>0) %then %do; data _null_; set labelfile(in=a where=(group="&analysisgrp" and runid = "&runid")) ; if labeltype = 'grouplabel' then call symputx('grouplabel',label); run; %end; /* Store covarnums to determine covar labels */ proc sql noprint; select distinct covarnum into :covarlist separated by ' ' from l2_effectestimates_&look_end. where analysisgrp="&analysisgrp."; quit; %if &covarlist = 0 %then %let tablecount = 0; /* loop covarnums and assign subgroup label */ %do covarcount = 1 %to %sysfunc(countw(&covarlist)); %let covarnum = %scan(&covarlist,&covarcount); %if &covarnum = 0 %then %do; %let titleend = %str(); %end; %else %if &covarnum = 9000 %then %do; %let titleend = %str(and Data Partner); %end; %else %do; %if &covarnum < 1000 %then %do; proc sql noprint; select distinct strip(studyname) into: subgrouplabel from infolder.&&&runid._covariatecodes where covarnum = &covarnum.; quit; %end; %if &covarnum = 1000 %then %let subgrouplabel = Sex; %else %if &covarnum = 1001 %then %let subgrouplabel = Age Group; %else %if &covarnum = 1002 %then %let subgrouplabel = Year; %else %if &covarnum = 1003 %then %let subgrouplabel = Monitoring Period; %else %if &covarnum = 1012 %then %let subgrouplabel = Race; %else %if &covarnum = 1013 %then %let subgrouplabel = Hispanic Origin; %else %if &covarnum = 1014 %then %let subgrouplabel = Delivery Status; %else %if &covarnum = 2000 %then %let subgrouplabel = Match Method; %else %if &covarnum = 2001 %then %let subgrouplabel = Birth Type; %let titleend = %str(and &subgrouplabel); %end; %tableletter(); %addtotoc(tabnum=Table &tablenum.&tableletter., caption=%quote(Effect Estimates for &grouplabel. in the &database. from &startdateformatted. to &&enddate&look_end.formatted., by Analysis Type &titleend.)); %end; /* covarcount */ %let tablenum = %eval(&tablenum + 1); %end; /* numl2comparison do loop */ %end; /* numl2comparison */ /*********************************************************************************************/ /* Code Distribution Tables */ /*********************************************************************************************/ %if &output_code_distribution. eq Y %then %do; /* This macros output a specific distribution type (EXP or HOI) entries in the table of content */ %macro codedistribution_type_toc(distindextype=); /* Compute group label to display in title */ %let grouplabel=; %isdata(dataset=labelfile); %if %eval(&nobs>0) %then %do; proc sql noprint; select label into :grouplabel trimmed from labelfile where lower(group)="&group." and runid = "&runid" and %if &distindextype. eq exp %then %do; lower(labeltype)="grouplabel"; %end; %else %do; lower(labeltype)="outcomelabel"; %end; quit; %end; %if %str("&grouplabel.") eq %str("") %then %let grouplabel = %trim(&group.); /* Full Code Distribution Table */ %tableletter(); %addtotoc(tabnum=Table &tablenum.&tableletter., caption=%quote(Full Code Distribution of &grouplabel. in the &database. from &startdateformatted. to &enddateformatted.)); /* Total Code Counts Table */ %tableletter(); %addtotoc(tabnum=Table &tablenum.&tableletter., caption=%quote(Total Code Counts of &grouplabel. in the &database. from &startdateformatted. to &enddateformatted.)); %mend codedistribution_type_toc; /* reset counter to reset table letter */ %let tablecount=1; proc sql noprint; select count(*) into :numgroupscodedist trimmed from GroupsDist; quit; %do loopcount = 1 %to &numgroupscodedist.; %let codedistexp = N; %let codedisthoi = N; data _null_; set GroupsDist; if &loopcount. = _N_; call symputx('runid', runid); call symputx('group', group); if index(upcase(codedist), "EXP") > 0 then call symputx('codedistexp', 'Y'); if index(upcase(codedist), "HOI") > 0 then call symputx('codedisthoi', 'Y'); run; %if &codedistexp. eq Y %then %do; * Defensive: make sure the requested data is available; %let obscount=0; proc sql noprint; select count(*) into :obscount from codedistdata where lower(group) = "&group." and runid = "&runid" and lower(distindextype) = "exp"; quit; %if %eval(&obscount. > 0) %then %codedistribution_type_toc(distindextype=exp); %end; %if &codedisthoi. eq Y %then %do; * Defensive: make sure the requested data is available; %let obscount=0; proc sql noprint; select count(*) into :obscount from codedistdata where lower(group) = "&group." and runid = "&runid" and lower(distindextype) = "hoi"; quit; %if %eval(&obscount. > 0) %then %codedistribution_type_toc(distindextype=hoi); %end; %end; *numgroupscodedist; %let tablenum = %eval(&tablenum + 1); %end; /*****************/ /* Attrition */ /*****************/ %isdata(dataset=agg_patient_attrition); %let attrition_patient = &nobs; %isdata(dataset=agg_episode_attrition); %let attrition_episode = &nobs; /* reset counter to reset table letter */ %let tablecount=1; %if &attrition_patient > 0 or &attrition_episode > 0 %then %do; %if (&attrition_patient > 0 and &attrition_episode = 0) or (&attrition_patient = 0 and &attrition_episode > 0) %then %do; %let tablecount = 0; %end; %if &attrition_episode > 0 %then %do; %tableletter(); %addtotoc(tabnum=Table &tablenum.&tableletter., caption=%quote(Summary of Episode Level Cohort Attrition in the &database. from &startdateformatted. to &enddateformatted.)); %end; %if &attrition_patient > 0 %then %do; %tableletter(); %addtotoc(tabnum=Table &tablenum.&tableletter., caption=%quote(Summary of Patient Level Cohort Attrition in the &database. from &startdateformatted. to &enddateformatted.)); %end; %let tablenum = %eval(&tablenum + 1); %end; /* attrition_groups file */ /*********************************************************************************************/ /* Figures */ /*********************************************************************************************/ %isdata(dataset=figurefile); %if %eval(&nobs.>0) %then %do; %let figurenum = 1; /* Add +1 for additional figure types that are requested */ %let tablecount = 1; /***************************************************************************************/ /* ReportType = T2L2, T4L2 */ /***************************************************************************************/ %if %sysfunc(prxmatch(m/T2L2|T4L2/i,&reporttype.)) > 0 %then %do; /*F1: PS distribution histograms*/ %if %sysfunc(prxmatch(m/F1/i,&figurelist.)) > 0 %then %do; proc sql noprint; select count(distinct AnalysisGrp) into: numPScomparisons from l2comparisonfile(where=(OutputPSDistribution="Y")); quit; %do loopcount = 1 %to &numl2comparisons.; data _NULL_; set l2comparisonfile(where=(order=&loopcount.)); call symputx('runid', runid); call symputx('analysisgrp', analysisgrp); call symputx('OutputPSDistribution', OutputPSDistribution); run; %if &OutputPSDistribution. = Y %then %do; %isdata(dataset=labelfile); %let grouplabel=&analysisgrp.; %if %eval(&nobs>0) %then %do; data _NULL_; set labelfile(where=(lowcase(labeltype)='grouplabel')); if group="&analysisgrp." and runid = "&runid"; call symputx('grouplabel', Label); run; %put &grouplabel.; %end; %let andafter=; proc sql noprint; select strip(file) into: psfile from pscs_masterinputs where analysisgrp = "&analysisgrp."; quit; %if &psfile. = psmatchfile | &psfile. = stratificationfile | &psfile. = iptwfile %then %do; data _null_; set pscs_masterinputs (where=(lowcase(analysisgrp)="&analysisgrp.")); call symputx("psestimategrp", lowcase(psestimategrp)); %if &psfile. = psmatchfile %then %do; if upcase(ratio) = "F" then do; call symput("andafter", " and After"); end; %end; %if &psfile = iptwfile %then %do; call symput("andafter", " and After"); %end; %else %if &psfile = stratificationfile %then %do; if upcase(strataweight) in ("ATE", "ATT") then do; call symput("andafter", " and After"); end; %end; run; %do j = %eval(&look_start) %to %eval(&look_end); %if &numPScomparisons.=1 and %eval(&look_end)=1 %then %do; %let tablecount = 0; %end; %tableletter(); %addtotoc(tabnum=Figure &figurenum.&tableletter., caption=%quote(Histograms Depicting Propensity Score Distributions Before&andafter Adjustment for &grouplabel. in the &database. from &startdateformatted. to &&enddate&j.formatted.)) %end; /* loop periods */ %end; /*psfile*/ %end; /* OutputPSDistribution */ %end; /* loop comparisons */ %let figurenum = %eval(&figurenum.+1); %end; /*Histograms*/ /*F2: Forest Plots*/ %if %sysfunc(prxmatch(m/F2/i,&figurelist.)) > 0 %then %do; %if %sysfunc(prxmatch(m/T2L2/i,&reporttype.)) > 0 %then %let ForestRatioTitle = Hazard Ratios (HR); %else %let ForestRatioTitle = Odds Ratios (OR); %let tableletter=a; %let tablecount = 1; %do j = %eval(&look_start) %to %eval(&look_end); %do plot = 1 %to 7; %let forest_title = ; data _null_; set forest_&j(where=(plotorder=&plot)); call symputx("forest_title",forest_title); run; %if %length(&forest_title) > 0 %then %do; %tableletter(); %addtotoc(tabnum=Figure &figurenum.&tableletter., caption=%quote(Forest Plot of &ForestRatioTitle and 95% Confidence Intervals (CI) for &forest_title in the &database. from &startdateformatted. to &&enddate&j.formatted.)) %end; /* Forest title exists */ %end; /* loop plots */ %end; /* loop periods */ %end; /*Forest plots */ %end; /*L2 figures*/ %end; /* Figure file */ /*****************/ /* Appendices */ /*****************/ /*Appendix A*/ %addtotoc(tabnum=Appendix A, caption=Dates of Available Data for Each Data Partner (DP) as of Request Distribution Date &datedistributed.); /* The remaining appendices are created in appendix_driver.sas */ /*********************/ /* Remove empty rows */ /*********************/ data tableofcontents; set tableofcontents; if missing(tabnum)=0; run; %put =====> END MACRO: create_tableofcontents ; %mend create_tableofcontents;