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.