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 open! SAS is returning to Vegas for an AI and analytics experience like no other! Whether you're an executive, manager, end user or SAS partner, SAS Innovate is designed for everyone on your team. Register for just $495 by 12/31/2023.
If you are interested in speaking, there is still time to submit a session idea. More details are posted on the website.
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.