This example shows how you can modularize the entire template. The goal is to modularize the template and use macros such that simple changes, such as title changes, are no more complicated than the following:
%SurvivalTemplateRestore %let TitleText0 = "Kaplan-Meier Plot"; %let TitleText1 = &titletext0 " for " STRATUMID; %let TitleText2 = &titletext0; %SurvivalTemplate
You can modularize the entire template as follows:
%macro SurvivalTemplateRestore; %global TitleText0 TitleText1 TitleText2 yOptions xOptions tips tipl groups bandopts gridopts blockopts censored censorstr; %let TitleText0 = METHOD " Survival Estimate"; %let TitleText1 = &titletext0 " for " STRATUMID; %let TitleText2 = &titletext0 "s"; /* plural: Survival Estimates */ %let yOptions = label="Survival Probability" shortlabel="Survival" linearopts=(viewmin=0 viewmax=1 tickvaluelist=(0 .2 .4 .6 .8 1.0)); %let xOptions = shortlabel=XNAME offsetmin=.05 linearopts=(viewmax=MAXTIME tickvaluelist=XTICKVALS tickvaluefitpolicy=XTICKVALFITPOL); %let tips = rolename=(_tip1= ATRISK _tip2=EVENT) tiplabel=(_tip1="Number at Risk" _tip2="Observed Events") tip=(x y _tip1 _tip2); %let tipl = tiplabel=(y="Survival Probability"); %let groups = group=STRATUM index=STRATUMNUM; %let bandopts = &groups modelname="Survival"; %let gridopts = autoalign=(TOPRIGHT BOTTOMLEFT TOP BOTTOM) border=true BackgroundColor=GraphWalls:Color Opaque=true; %let blockopts = repeatedvalues=true valuehalign=start valuefitpolicy=truncate labelposition=left labelattrs=GRAPHVALUETEXT includemissingclass=false valueattrs=GRAPHDATATEXT(size=7pt); %let censored = markerattrs=(symbol=plus); %let censorstr = "+ Censored";
%macro SurvivalTemplate; proc template; define statgraph Stat.Lifetest.Graphics.ProductLimitSurvival; dynamic NStrata xName plotAtRisk plotCL plotHW plotEP labelCL %if %nrbquote(&censored) ne %then plotCensored; labelHW labelEP maxTime xtickVals xtickValFitPol method StratumID classAtRisk plotBand plotTest GroupName yMin Transparency SecondTitle TestName pValue; BeginGraph; if (NSTRATA=1) if (EXISTS(STRATUMID)) entrytitle &titletext1; else entrytitle &titletext0; endif; if (PLOTATRISK=1) entrytitle "with Number of Subjects at Risk" / textattrs= GRAPHVALUETEXT; endif; layout overlay / xaxisopts=(&xoptions) yaxisopts=(&yoptions); %singlestratum endlayout; else entrytitle &titletext2; if (EXISTS(SECONDTITLE)) entrytitle SECONDTITLE / textattrs=GRAPHVALUETEXT; endif; layout overlay / xaxisopts=(&xoptions) yaxisopts=(&yoptions); %multiplestrata endlayout; endif; EndGraph; end; run; %mend;
%macro entry_p; if (PVALUE < .0001) entry TESTNAME " p " eval (PUT(PVALUE, PVALUE6.4)); else entry TESTNAME " p=" eval (PUT(PVALUE, PVALUE6.4)); endif; %mend;
%macro SingleStratum; if (PLOTHW=1 AND PLOTEP=0) bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME / modelname="Survival" fillattrs=GRAPHCONFIDENCE name="HW" legendlabel=LABELHW; endif; if (PLOTHW=0 AND PLOTEP=1) bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME / modelname="Survival" fillattrs=GRAPHCONFIDENCE name="EP" legendlabel=LABELEP; endif; if (PLOTHW=1 AND PLOTEP=1) bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME / modelname="Survival" fillattrs=GRAPHDATA1 datatransparency=.55 name="HW" legendlabel=LABELHW; bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME / modelname="Survival" fillattrs=GRAPHDATA2 datatransparency=.55 name="EP" legendlabel=LABELEP; endif; if (PLOTCL=1) if (PLOTHW=1 OR PLOTEP=1) bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / modelname="Survival" display=(outline) outlineattrs=GRAPHPREDICTIONLIMITS name="CL" legendlabel=LABELCL; else bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / modelname="Survival" fillattrs=GRAPHCONFIDENCE name="CL" legendlabel=LABELCL; endif; endif; stepplot y=SURVIVAL x=TIME / name="Survival" &tips legendlabel="Survival"; if (PLOTCENSORED=1) scatterplot y=CENSORED x=TIME / &censored &tipl name="Censored" legendlabel="Censored"; endif; if (PLOTCL=1 OR PLOTHW=1 OR PLOTEP=1) discretelegend "Censored" "CL" "HW" "EP" / location=outside halign=center; else if (PLOTCENSORED=1) discretelegend "Censored" / location=inside autoalign=(topright bottomleft); endif; endif; if (PLOTATRISK=1) innermargin / align=bottom; blockplot x=TATRISK block=ATRISK / display=(label values) &blockopts; endinnermargin; endif; %mend; %macro MultipleStrata; if (PLOTHW) bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME / &bandopts datatransparency=Transparency; endif; if (PLOTEP) bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME / &bandopts datatransparency=Transparency; endif; if (PLOTCL) if (PLOTBAND) bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / &bandopts display=(outline); else bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / &bandopts datatransparency=Transparency; endif; endif;
stepplot y=SURVIVAL x=TIME / &groups name="Survival" &tips; if (PLOTCENSORED) scatterplot y=CENSORED x=TIME / &groups &censored &tipl; endif; if (PLOTATRISK=1) innermargin / align=bottom; blockplot x=TATRISK block=ATRISK / class=CLASSATRISK display=(label values) &blockopts; endinnermargin; endif; DiscreteLegend "Survival" / title=GROUPNAME location=outside; if (PLOTCENSORED) if (PLOTTEST) layout gridded / rows=2 &gridopts; entry &censorstr; %entry_p endlayout; else layout gridded / rows=1 &gridopts; entry &censorstr; endlayout; endif; else if (PLOTTEST) layout gridded / rows=1 &gridopts; %entry_p endlayout; endif; endif; %mend; %SurvivalTemplate %mend;
This modularized template is available in the SAS sample library. If you are using the SAS windowing environment, select
. Select the tab. Expand , expand , and expand . Select . Search for and select .The following changes were made to the template:
The outer macro, %SurvivalTemplateRestore
, defines a set of macros and a set of global macro variables. This macro makes it easier to restore the default macros and
macro variables. You should not use this outer macro to modify the templates. You should use it only to provide and restore
all of the defaults.
Many options, including most of the options that are specified in multiple places in the template, are extracted to macro variables.
The main body of the template is in a macro, %SurvivalTemplate
, so that it is easier to recompile the template after making changes.
The table for p-values is stored in the macro, %Entry_P
.
The revised template for the single-stratum case is stored in the macro %SingleStratum
.
The revised template for the multiple-stratum case is stored in the macro %MultipleStrata
.
The template has been re-indented.
These changes make it easier to identify the relevant parts of the template, modify them, and recompile the template. All subsequent parts of this example modify this rewritten and more modular template.
Do not edit the template inside the %SurvivalTemplateRestore
macro. Rather, copy the %LET statements and macro definitions and modify them outside the context of the %SurvivalTemplateRestore
macro. If you work this way, then you can restore the defaults with a two step process:
You can restore the default macros and macro variables by running the following step:
%SurvivalTemplateRestore
You can restore the default template by running the following step:
proc template; delete Stat.Lifetest.Graphics.ProductLimitSurvival / store=sasuser.templat; run;
A simple, complete program, with set up, template modification, and clean up works as follows:
/* Make the macros and macro */ %SurvivalTemplateRestore /* variables available */ %let TitleText0 = "Kaplan-Meier Plot"; /* Change the title. */ %let TitleText1 = &titletext0 " for " STRATUMID; %let TitleText2 = &titletext0; %SurvivalTemplate /* Compile the template with */ /* the new title. */ proc lifetest data=sashelp.BMT /* Perform the analysis and make */ plots=survival(cb=hw test); /* the graph. */ time T * Status(0); strata Group; run; %SurvivalTemplateRestore /* Restore the default macros */ /* and macro variables. */ proc template; /* Restore the default template. */ delete Stat.Lifetest.Graphics.ProductLimitSurvival / store=sasuser.templat; run;
The results of this step are not shown, but this same template modification is discussed in the next section. The %SurvivalTemplateRestore
macro creates the macros and macro variables that you can modify to change the template. The %SurvivalTemplate
macro compiles the template with the macro variable changes and macro changes (if any were performed). By default, the compiled
template is stored in the Sasuser.Templat
item store. PROC LIFETEST makes the graph. The %SurvivalTemplateRestore
macro restores the default macros and macro variables. The %SurvivalTemplateRestore
macro ends by calling the %SurvivalTemplate
macro, so it also compiles and stores the default template in the Sasuser.Templat
item store. The PROC TEMPLATE step deletes the compiled template from the Sasuser.Templat
item store so that the original template from the Sashelp.Tmplmst
item store is used in subsequent runs.
Deleting the compiled template from the Sasuser.Templat
item store does not change the macros or macro variables. Hence, if you do not restore the macros and macro variables, but
you delete the compiled template, change a different macro variable, and recompile the template in the same SAS session, you
will see the effects of both changes. In practice, you do not need to restore the default macros and macro variables when
you are done unless (as is the case in this example) you go on in the same SAS session to make other template changes and
you do not want your previous template changes to affect subsequent graphs.
If you modify and manipulate this template frequently, you might find it more convenient to modify the %SurvivalTemplateRestore
macro along the following lines:
%macro SurvivalTemplateRestore(action); . . . %if &action = compile %then %SurvivalTemplate; %else %if &action = delete %then %do; proc template; delete Stat.Lifetest.Graphics.ProductLimitSurvival / store=sasuser.templat; run; %end; %mend;
This modification enables you to clean up with a single step.