I am producing a PDF graph that contains some entry statements. However in PDF they seem to get tructation. The graph prints perfectly using ODS rtf. But if you look at the drug names in the medians block you can see they are a. truncated and b. the font seems weird (not the same size). Strangely if I use the text select tool in Acrobat viewer I can select and copy&paste the full text, so it is like it is hidden behind something. Am I missing something?
Code is attached in 3 parts (the 2 macros and the program). I cannot show any data but the dataset consists of
usubjid, months, cnsr, trt01pn. Trt01pn has values 2 & 3 formatted to "ABCDEFG + abcdefghijkl" and ""abcdefghijkl" respectively.
I am using SAS 9.4
%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= 3.1 );
%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 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 RIGHT)
border=false BackgroundColor=GraphWalls:Color Opaque=true;
%let LegendOpts = title=&_legtitl location=inside valueattrs=(size=9pt) &InsetOpts;
%let AtRiskOpts = valueattrs=(size=9pt) display=(label) ;
%let ClassOpts = class=CLASSATRISK colorgroup=CLASSATRISK display=(label);
%let Censored = markerattrs=(symbol=circlefilled size=6);
%let CensorStr = "Censored";
%let GraphOpts = ;
%LET srvtble = YES;
%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 ;
BeginGraph %if %nrbquote(&graphopts) ne %then / border=false pad=0 &graphopts;;
legenditem type=marker name="CenLgd" / label=&CensorStr lineattrs=(color=black) markerattrs=(symbol=circlefilled color=black size=6);
layout lattice / rows=2 rowweights=ROWWEIGHTS columndatarange=union rowgutter=10;
cell;
layout overlay / xaxisopts=(&xoptions) yaxisopts=(&yoptions);
stepplot y=eval(SURVIVAL) x=TIME / &groups name="Survival" &tips &stepopts;
scatterplot y=eval(CENSORED) x=TIME / &groups &tiplabel &censored name="Censored" legendlabel="Censored";
MERGEDLEGEND "Survival" "Censored" / across=1 &legendopts ADDITIONALNAMES=("CenLgd");
%if %nrbquote(&srvtble) ne %then %do;
%SurvivalTable;
%end;
endlayout;
endcell;
cell;
layout overlay / walldisplay=none xaxisopts=(display=none &xOptions);
axistable x=TATRISK value=ATRISK / &atriskopts &classopts;;
endlayout;
endcell;
endlayout;
EndGraph;
end;
quit;
run;
%mend CompileSurvivalTemplates;
%macro SurvivalTable;
%local fmt r i t;
%let fmt = &_fmt;
%let r = halign = right;
layout gridded / columns=1 rows=4 &InsetOpts ;
entry halign=center "Median &kmtype in months (95% CI)" / textattrs=GraphData;
layout gridded / columns=4 &InsetOpts;
dynamic PctMedianConfid;
%do i = 1 %to 2;
%let t = / textattrs=GraphData&i (family="Courier New" size=9pt) ;
dynamic StrVal&i Median&i LowerMedian&i UpperMedian&i;
if (&i <= nstrata)
entry &r StrVal&i &t;
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;
endlayout;
%mend SurvivalTable;
%CompileSurvivalTemplates;
%mend mkmtemplate;
%MACRO mkmplot (_inds=,
_time=,
_cen =,
_strat=,
_timetick=,
_maxtime=,
_ylabel="Probability of Survival (%)",
_legtitl=GROUPNAME,
_alphaqt=0.05,
_fmt=bestd6.,
_kmtime=,
_opts=none,
_opts2=none,
_orint=portrait,
_colour=no,
_showtxt=1,
_dev=svg
);
*******************************************************************************************************/;
***** Find graph limits and by var label and number of strata *****/;
*******************************************************************************************************/;
PROC CONTENTS data=&_inds out=datatest noprint;RUN;
%LET _strata=;
%LET _xtlbl= - &_strat;
DATA _null_;
SET datatest (where=(upcase(name)=upcase(compress("&_strat","_", "kna"))));
call symput('_strata', "&_strat");
call symput('_xtlbl', "");
RUN;
PROC DATASETS lib=work memtype=data nolist;DELETE datatest;RUN;QUIT;
PROC SQL noprint;
%IF %nrbquote(&_maxtime) ne %THEN %DO;
SELECT distinct ceil(&_maxtime./&_timetick.)* &_timetick.
INTO :__maxmon
FROM &_inds;
%END;
%ELSE %DO;
SELECT distinct ceil(max(&_time)/&_timetick.)* &_timetick.
INTO :__maxmon
FROM &_inds;
%END;
QUIT;
*******************************************************************************************************/;
***** Run template and make any required updateds *****/;
*******************************************************************************************************/;
%mkmtemplate;
/* make changes here */
%IF %SYSMACEXIST(&_opts) %THEN %DO;
%&_opts;
%END;
*** =======================================================================;
** This will allow us to define a new temporary template;
ods path(prepend) work.templat(update);
ods path show;
%CompileSurvivalTemplates;
*******************************************************************************************************/;
***** Create plot *****/;
*******************************************************************************************************/;
ods listing close;
ods noptitle;
%IF &_orint=portrait %THEN %DO;
ODS graphics on / border=off height=10cm width=19cm;
GOPTIONS ymax=10cm xmax=19cm;
OPTIONS orientation=portrait papersize='ISO A4' nodate nonumber nobyline ;
%END;
%ELSE %DO;
ODS graphics on / border=off height=12cm width=25cm ;
GOPTIONS xmax=25cm ymax=12cm;
OPTIONS orientation=landscape papersize='ISO A4' nodate nonumber nobyline ;
%END;
ods graphics on / imagefmt=&_dev;
ods select SurvivalPlot;
proc lifetest data=&_inds PLOTS=SURVIVAL( ATRISK (atrisktickonly outside)= 0 TO &__maxmon BY &_timetick) alphaqt=&_alphaqt METHOD=KM CONFTYPE=LOGLOG;
time &_time * &_cen(1);
strata &_strata / order=internal test=none;
run;quit;
ods graphics off;
%MEND mkmplot;
**----------------------------------------------------------------**;
** Report data
**----------------------------------------------------------------**;
ods path(prepend) work.templat(update);
ods path show;
PROC TEMPLATE;
define style styles.graph;
parent=styles.rtf;
%** 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' = ("Courier New",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);
style GraphFonts from GraphFonts /
'GraphDataFont' = ("Courier New",9pt)
'GraphUnicodeFont' = ("Courier New",9pt)
'GraphValueFont' = ("Courier New",9pt)
'GraphLabelFont' = ("Courier New",9pt)
'GraphFootnoteFont' = ("Courier New",9pt)
'GraphTitleFont' = ("Courier New",9pt)
'GraphAnnoFont' = ("Courier New",9pt);
style GraphData1 from GraphData1 / font=("Courier New", 9pt) contrastcolor=black;;
style GraphData2 from GraphData2 / font=("Courier New", 9pt) contrastcolor=cx808080;
style GraphData3 from GraphData3 / LineStyle = 3;
end;
quit;
run;
ODS graphics on / border=off height=12cm width=25cm ;
GOPTIONS xmax=25cm ymax=12cm;
OPTIONS orientation=landscape papersize='ISO A4' nodate nonumber nobyline ;
ods pdf dpi=300 file="..../mygraph.pdf" style=graph;
%LET kmtype=PFS;
%mkmplot (_inds=adtte,
_time=months,
_cen =cnsr,
_strat=trt01pn,
_timetick=3,
_maxtime=24,
_ylabel="Probability of PFS",
_legtitl=" ",
_alphaqt=0.05,
_fmt=5.1,
_kmtime=,
_opts=none,
_opts2=none,
_orint=landscape
_colour=yes
_dev=svg
);
ODS pdf close;
So I had a little play around with this again, if I replace
entry &r StrVal&i &t;
with
entry &r "&&&trt&i" &t;
with the treatment label defined outside the template then the label is printed correctly. So it seems to be related to some kind of style applied to the StrVal within Stat.Graphics.ProductLimitSurvival
Any idea how I may get at this StrVal variable?
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.