I am creating KM plots using a modified lifetest template (https://support.sas.com/resources/papers/proceedings13/427-2013.pdf)
My axistable statement is straightforward
%macro AtRiskLatticeEnd(useclassopts);
endcell;
cell;
layout overlay / walldisplay=none xaxisopts=(display=none);
axistable x=TATRISK value=ATRISK / &atriskopts
headerlabel="No. of patients still at risk &_xtlbl"
%if &useclassopts ne %then &classopts;;
endlayout;
endcell;
endlayout;
%mend AtRiskLatticeEnd;
As is the lifetest call
proc lifetest data=plotdata PLOTS=SURVIVAL( ATRISK (atrisktickonly outside)= 0 TO 24 BY 3) alphaqt=0.05 METHOD=KM CONFTYPE=LOGLOG;
time os*censor(1);
strata treatment / order=internal test=none;
run;quit;
But for some reason the values seem not to be correctly aligned to the tickmarks on the axis. Any idea what may be causing this? Is it a format issue?
I tried changing the font size and it is still the same issue. I have attached the full template code below.
%macro mkmtemplate;
%global atriskopts bandopts censored censorstr classopts
graphopts groups insetopts legendopts ntitles stepopts tiplabel
tips titletext0 titletext1 titletext2 xoptions yoptions srvtble _colr;
%let yOptions = label=&_ylabel shortlabel="Survival" LABELFITPOLICY=splitalways LABELSPLITCHAR="#" labelsplitjustify=bottom
linearopts=(viewmin=0 viewmax=1
tickvaluelist=(0 0.2 0.4 0.6 0.8 1) tickvalueFormat= percent10. );
%IF %length(&_MAXTIME) %THEN %DO;
%let xOptions = shortlabel=XNAME offsetmin=.05 linearopts=(viewmax=&_maxtime tickvaluelist=XTICKVALS tickvaluefitpolicy=XTICKVALFITPOL);
%END;
%ELSE %DO;
%let xOptions = shortlabel=XNAME offsetmin=.05 linearopts=(viewmax=&__maxmon tickvaluelist=XTICKVALS tickvaluefitpolicy=XTICKVALFITPOL);
%END;
%IF %upcase(&_colour)=YES or %upcase(&_colour)=Y %THEN %DO;
%LET _colr=rtf;
%END;
%ELSE %DO;
%LET _colr=journal;
%END;
%let Tips = rolename=(_tip1= ATRISK _tip2=EVENT)
tiplabel=(_tip1="Number at Risk" _tip2="Observed Events")
tip=(x y _tip1 _tip2);
%let TipLabel = tiplabel=(y="Survival Probability");
%let StepOpts = ;
%let Groups = group=STRATUM index=STRATUMNUM;
%let BandOpts = &groups modelname="Survival";
%let InsetOpts = autoalign=(TOPRIGHT BOTTOMLEFT BOTTOMRIGHT TOP BOTTOM)
border=false BackgroundColor=GraphWalls:Color Opaque=true;
%let LegendOpts = title=&_legtitl location=inside &InsetOpts;
%let AtRiskOpts = valueattrs=(size=9pt);
%let ClassOpts = class=CLASSATRISK colorgroup=CLASSATRISK display=(label);
%let Censored = markerattrs=(symbol=plus);
%let CensorStr = "Censored";
%let GraphOpts = ;
%LET srvtble = YES;
%macro StmtsBeginGraph; %mend;
%macro StmtsTop; %mend;
%macro StmtsBottom; %mend;
%macro CompileSurvivalTemplates;
%local outside;
proc template;
define statgraph
Stat.Lifetest.Graphics.ProductLimitSurvival2;
dynamic NStrata xName plotAtRisk
%if %nrbquote(&censored) ne %then plotCensored;
plotCL plotHW plotEP labelCL labelHW labelEP maxTime xtickVals
xtickValFitPol rowWeights method StratumID classAtRisk
plotTest GroupName Transparency SecondTitle TestName pValue
_byline_ _bytitle_ _byfootnote_ _byval_ _byvar_ _hrtext _byval1_ _byval2_ _byval3_;
BeginGraph %if %nrbquote(&graphopts) ne %then / border=false pad=0 &graphopts;;
if (NSTRATA=1)
%StmtsBeginGraph
%AtRiskLatticeStart
layout overlay / xaxisopts=(&xoptions) yaxisopts=(&yoptions);
%StmtsTop
%SingleStratum
%StmtsBottom
endlayout;
%AtRiskLatticeEnd
else
legenditem type=marker name="CenLgd" / label=&CensorStr lineattrs=(color=black) markerattrs=(symbol=plus color=black);
%StmtsBeginGraph
%AtRiskLatticeStart
layout overlay / xaxisopts=(&xoptions) yaxisopts=(&yoptions);
%StmtsTop
%MultipleStrata
%StmtsBottom
endlayout;
%AtRiskLatticeEnd(class)
endif;
%IF %length(&_by) %THEN %DO;
entrytitle halign=left "&bylbl.: " _byval_ / textattrs=GRAPHVALUETEXT;
%END;
EndGraph;
end;
define style graph;
parent=styles.&_colr;
%** important thing to notice is the protectspecialchars, which allows us to push the RTF codes through **;
style table from table / protectspecialchars=off;
replace body from document /
bottommargin = 0.00cm
topmargin = 2.50cm
rightmargin = 0.00cm
leftmargin = 1.10cm;
replace fonts /
'CellFont' = ("arial",9pt)
'TitleFont2' = ("arial",9pt)
'TitleFont' = ("arial",9pt)
'StrongFont' = ("arial",9pt)
'EmphasisFont' = ("arial",9pt)
'FixedEmphasisFont' = ("arial",9pt)
'FixedStrongFont' = ("arial",9pt)
'FixedHeadingFont' = ("arial",9pt)
'BatchFixedFont' = ("arial",9pt)
'FixedFont' = ("arial",9pt)
'headingEmphasisFont' = ("arial",9pt)
'headingFont' = ("arial",9pt)
'docFont' = ("arial",9pt);
%IF %SYSMACEXIST(&_opts2) %THEN %DO;
%&_opts2;
%END;
style GraphFonts from GraphFonts /
'GraphDataFont' = ("arial",9pt)
'GraphUnicodeFont' = ("arial",9pt)
'GraphValueFont' = ("arial",9pt)
'GraphLabelFont' = ("arial",9pt)
'GraphFootnoteFont' = ("arial",9pt)
'GraphTitleFont' = ("arial",9pt)
'GraphAnnoFont' = ("arial",9pt);
style GraphData3 from GraphData3 / LineStyle = 3;
end;
quit;
run;
%mend CompileSurvivalTemplates;
%macro SingleStratum;
stepplot y=eval(SURVIVAL) x=TIME / name="Survival" &tips legendlabel="&_strat"
&stepopts;
if (PLOTCENSORED=1)
scatterplot y=eval(CENSORED) x=TIME / &censored &tiplabel
name="Censored" legendlabel="Censored";
endif;
if (PLOTCENSORED=1)
MERGEDLEGEND "Survival" "Censored" / across=1 &legendopts ADDITIONALNAMES=("CenLgd");
endif;
%if %nrbquote(&srvtble) ne %then %do;
%SurvivalTable;
%end;
%mend SingleStratum;
%macro MultipleStrata;
stepplot y=eval(SURVIVAL) x=TIME / &groups name="Survival" &tips &stepopts;
if (PLOTCENSORED=1)
scatterplot y=eval(CENSORED) x=TIME / &groups &tiplabel &censored name="Censored" legendlabel="Censored";
endif;
%if %nrbquote(&legendopts) ne %then %do;
MERGEDLEGEND "Survival" "Censored" / across=1 &legendopts ADDITIONALNAMES=("CenLgd");
%end;
%if %nrbquote(&srvtble) ne %then %do;
%SurvivalTable;
%end;
%mend MultipleStrata;
%macro SurvTabHeader(multiple);
entry "";
entry "";
entry "";
entry &r "Median";
entry "";
entry "";
entry "";
entry "";
entry "";
entry &r "Survival";
entry "";
entry "";
entry "";
entry &r "Subjects";
entry &r "Event";
entry &r "&_kmtime";
entry &r PctMedianConfid;
entry halign=left "CI";
%mend SurvTabHeader;
%macro SurvivalTable;
%local fmt r i t;
%let fmt = &_fmt;
%let r = halign = right;
if(NSTRATA=1)
layout gridded / columns=6 &InsetOpts;
dynamic StrVal _strat PctMedianConfid NObs NEvent Median LowerMedian UpperMedian ;
%SurvTabHeader(1)
entry &r "&_strat" &t;
if(NObs ne .) entry &r NObs&i &t; else entry &r "N.E" &t; endif;
if(NEvent ne .) entry &r eval(NEvent&i) &t; else entry &r "N.E" &t; endif;
if(Median ne .) entry &r eval(put(Median&i,&fmt)) &t; else entry &r "N.E" &t; endif;
if(LowerMedian ne .) entry &r eval(put(LowerMedian&i,&fmt)) &t; else entry &r "N.E" &t; endif;
if(UpperMedian ne .) entry &r eval(put(UpperMedian&i,&fmt)) &t; else entry &r "N.E" &t; endif;
endlayout;
else
layout gridded / columns=1 &InsetOpts;
layout gridded / columns=6 &InsetOpts;
dynamic PctMedianConfid;
%SurvTabHeader(1)
%do i = 1 %to 5;
%let t = / textattrs=GraphData&i;
dynamic StrVal&i NObs&i NEvent&i Median&i LowerMedian&i UpperMedian&i _hrtext _hrby _pvtext _pvby;
if (&i <= nstrata)
entry &r StrVal&i &t;
if(NObs&i ne .) entry &r NObs&i &t; else entry &r "N.E" &t; endif;
if(NEvent&i ne .) entry &r eval(NEvent&i) &t; else entry &r "N.E" &t; endif;
if(Median&i ne .) entry &r eval(put(Median&i,&fmt)) &t; else entry &r "N.E" &t; endif;
if(LowerMedian&i ne .) entry &r eval(put(LowerMedian&i,&fmt)) &t; else entry &r "N.E" &t; endif;
if(UpperMedian&i ne .) entry &r eval(put(UpperMedian&i,&fmt)) &t; else entry &r "N.E" &t; endif;
endif;
%end;
endlayout;
%IF %length(&_hr) %THEN %DO;
entry halign = left &_hrby;
%END;
%IF %length(&_pval) %THEN %DO;
entry halign = left &_pvby ;
%END;
endlayout;
endif;
%mend SurvivalTable;
%macro AtRiskLatticeStart;
layout lattice / rows=2 rowweights=ROWWEIGHTS
columndatarange=union rowgutter=10;
cell;
%mend AtRiskLatticeStart;
%macro AtRiskLatticeEnd(useclassopts);
endcell;
cell;
layout overlay / walldisplay=none xaxisopts=(display=none);
axistable x=TATRISK value=ATRISK / &atriskopts
headerlabel="No. of patients still at risk &_xtlbl"
%if &useclassopts ne %then &classopts;;
endlayout;
endcell;
endlayout;
%mend AtRiskLatticeEnd;
%CompileSurvivalTemplates;
%mend mkmtemplate;
My apologies Reeza, you were correct. I deleted all the outputs I had currently produced and reran in a clean session and it is now correct. Something had not updated somewhere. Thanks for your help.
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.