BookmarkSubscribeRSS Feed
kstolzmann
Obsidian | Level 7

 

Hello,

I am trying to modify my KM plots to include dashed lines rather than solid (SAS 9.4) by modifying the template. I see this question was asked and solved here: https://communities.sas.com/t5/SAS-GRAPH-and-ODS-Graphics/Survival-Plot-with-dashed-line/td-p/88446

but the solution 

 

"

Add LINEATTRS=(pattern=dashed) to this line:

 

stepplot y=SURVIVAL x=TIME / name="Survival" rolename=(_tip1=    

               ATRISK _tip2=EVENT) tip=(y x Time _tip1 _tip2) legendlabel=  

               "Survival" lineattrs=(pattern=dashed);

is not working for me (I get errors in my proc template).

 

Any assistance would be greatly appreciated!

 

Error (snippet) from the log:

 

7225 stepplot y=SURVIVAL x=TIME / name="Survival" rolename=(_tip1=ATRISK _tip2=EVENT) tiplabel=(_tip1="Number at

7225! Risk"

7226 _tip2="Observed Events") tip=(x y _tip1 _tip2) legendlabel="Survival" lineattrs=(pattern=dashed);

------

772

7227 if (PLOTCENSORED=1)

-

79

200

ERROR 772-580: Syntax error: expecting a constant or a dynamic.

ERROR 79-322: Expecting a ).

ERROR 200-322: The symbol is not recognized and will be ignored.

 

 

Full code (without the "lineattrs=(pattern=dashed)") below:

 

ods graphics on;

ods path(prepend) work.templat(update);

 

%let TitleText0 = METHOD " Survival Estimate";

%let TitleText1 = &titletext0 " for " STRATUMID;

%let TitleText2 = &titletext0 "s";

%let yOptions = label="Probability of Seeking Care for Back Pain"

shortlabel="Probability of Seeking Care for Back Pain"

labelattrs=(size=9pt weight=bold)

tickvalueattrs=(size=8pt)

linearopts=(viewmin=0 viewmax=1

tickvaluelist=(0 .2 .4 .6 .8 1.0));

%let xOptions = shortlabel="Number of Years to Back Pain"

offsetmin=.05

labelattrs=(size=10pt weight=bold)

tickvalueattrs=(size=8pt)

linearopts=(viewmax=MAXTIME tickvaluelist=XTICKVALS

tickvaluefitpolicy=XTICKVALFITPOL);

 

proc template;

define statgraph Stat.Lifetest.Graphics.ProductLimitSurvival;

dynamic NStrata xName plotAtRisk plotCensored plotCL plotHW plotEP labelCL

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)

entrytitle "with Number of Subjects at Risk" / textattrs=

GRAPHVALUETEXT;

endif;

layout overlay / xaxisopts=(&xoptions) yaxisopts=(&yoptions);

if (PLOTHW=1 AND PLOTEP=0)

bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME / displayTail=false modelname="Survival" fillattrs=

GRAPHCONFIDENCE name="HW" legendlabel=LABELHW;

endif;

if (PLOTHW=0 AND PLOTEP=1)

bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME / displayTail=false modelname="Survival" fillattrs=

GRAPHCONFIDENCE name="EP" legendlabel=LABELEP;

endif;

if (PLOTHW=1 AND PLOTEP=1)

bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME / displayTail=false modelname="Survival" fillattrs=

GRAPHDATA1 datatransparency=.55 name="HW" legendlabel=LABELHW;

bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME / displayTail=false 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 / displayTail=false modelname="Survival" display=(

outline) outlineattrs=GRAPHPREDICTIONLIMITS name="CL" legendlabel=LABELCL;

else

bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / displayTail=false modelname="Survival" fillattrs=

GRAPHCONFIDENCE name="CL" legendlabel=LABELCL;

endif;

endif;

stepplot y=SURVIVAL x=TIME / name="Survival" rolename=(_tip1=ATRISK _tip2=EVENT) tiplabel=(_tip1="Number at Risk"

_tip2="Observed Events") tip=(x y _tip1 _tip2) legendlabel="Survival" lineattrs=(pattern=shortdash longdash);

if (PLOTCENSORED=1)

scatterplot y=CENSORED x=TIME / markerattrs=(symbol=plus) tiplabel=(y="Probability of an Episode of Seeking Care for Back Pain") 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;

axistable x=TATRISK value=ATRISK / display=(label) valueattrs=(size=7pt);

endinnermargin;

endif;

endlayout;

else

entrytitle &titletext2;

if (EXISTS(SECONDTITLE))

entrytitle SECONDTITLE / textattrs=GRAPHVALUETEXT;

endif;

layout overlay / xaxisopts=(&xoptions) yaxisopts=(&yoptions);

if (PLOTHW=1)

bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME / displayTail=false group=STRATUM index=STRATUMNUM modelname

="Survival" datatransparency=Transparency;

endif;

if (PLOTEP=1)

bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME / displayTail=false group=STRATUM index=STRATUMNUM modelname

="Survival" datatransparency=Transparency;

endif;

if (PLOTCL=1)

if (PLOTHW=1 OR PLOTEP=1)

bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / displayTail=false group=STRATUM index=STRATUMNUM

modelname="Survival" display=(outline) outlineattrs=(pattern=ShortDash);

else

bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / displayTail=false group=STRATUM index=STRATUMNUM

modelname="Survival" datatransparency=Transparency;

endif;

endif;

stepplot y=SURVIVAL x=TIME / group=STRATUM index=STRATUMNUM name="Survival" rolename=(_tip1=ATRISK _tip2=EVENT)

tiplabel=(_tip1="Number at Risk" _tip2="Observed Events") tip=(x y _tip1 _tip2);

if (PLOTCENSORED=1)

scatterplot y=CENSORED x=TIME / group=STRATUM index=STRATUMNUM tiplabel=(y="Probability of an Episode of Seeking Care for Back Pain") markerattrs=(

symbol=plus);

endif;

if (PLOTATRISK=1)

innermargin / align=bottom;

axistable x=TATRISK value=ATRISK / display=(label) valueattrs=(size=7pt) class=CLASSATRISK colorgroup=

CLASSATRISK;

endinnermargin;

endif;

DiscreteLegend "Survival" / title=GROUPNAME location=outside;

if (PLOTCENSORED=1)

if (PLOTTEST=1)

layout gridded / rows=2 autoalign=(TOPRIGHT BOTTOMLEFT TOP BOTTOM) border=true BackgroundColor=

GraphWalls:Color Opaque=true;

entry "+ Censored";

if (PVALUE < .0001)

entry TESTNAME " p " eval (PUT(PVALUE, PVALUE6.4));

else

entry TESTNAME " p=" eval (PUT(PVALUE, PVALUE6.4));

endif;

endlayout;

else

layout gridded / rows=1 autoalign=(TOPRIGHT BOTTOMLEFT TOP BOTTOM) border=true BackgroundColor=

GraphWalls:Color Opaque=true;

entry "+ Censored";

endlayout;

endif;

else

if (PLOTTEST=1)

layout gridded / rows=1 autoalign=(TOPRIGHT BOTTOMLEFT TOP BOTTOM) border=true BackgroundColor=

GraphWalls:Color Opaque=true;

if (PVALUE < .0001)

entry TESTNAME " p " eval (PUT(PVALUE, PVALUE6.4));

else

entry TESTNAME " p=" eval (PUT(PVALUE, PVALUE6.4));

endif;

endlayout;

endif;

endif;

endlayout;

endif;

EndGraph;

end;

run;

6 REPLIES 6
ballardw
Super User

With error messages it is best to post the CODE and the Error messages from the log, one copy and paste, into a code box opened with the forum {i} menu icon.

Error messages often have indicators along with the code that indicates likely problem spots. And the reason to include the code that was run (not another version) is because the actual cause of the error could be a missing semicolon, paranthese, comma, quote on a line above where the error was reported. Note that in your snippet there are several dashes or underscores, they appear where the expected element should be but the main message windows reformat text and we cannont see where they should appear in relation to the code. The codebox will retain the formatting to show where the missing element was expected.

 

And the entire data step or proc code submitted, not a snippet.

kstolzmann
Obsidian | Level 7

Thanks, and sorry about that; here is it:

 

 

491
492  ods graphics on;
493  ods path(prepend) work.templat(update);
494
495  %let TitleText0 = METHOD " Survival Estimate";
496  %let TitleText1 = &titletext0 " for " STRATUMID;
497  %let TitleText2 = &titletext0 "s";
498  %let yOptions   = label="Probability of Seeking Care for Back Pain"
499                    shortlabel="Probability of Seeking Care for Back Pain"
500                    labelattrs=(size=9pt weight=bold)
501                    tickvalueattrs=(size=8pt)
502                    linearopts=(viewmin=0 viewmax=1
503                                tickvaluelist=(0 .2 .4 .6 .8 1.0));
504  %let xOptions   = shortlabel="Number of Years to Back Pain"
505                    offsetmin=.05
506                    labelattrs=(size=10pt weight=bold)
507                    tickvalueattrs=(size=8pt)
508                    linearopts=(viewmax=MAXTIME tickvaluelist=XTICKVALS
509                                tickvaluefitpolicy=XTICKVALFITPOL);
510
511
512  proc template;
513     define statgraph Stat.Lifetest.Graphics.ProductLimitSurvival;
514        dynamic NStrata xName plotAtRisk plotCensored plotCL plotHW plotEP labelCL
515           labelHW labelEP maxTime xtickVals xtickValFitPol method StratumID
516           classAtRisk plotBand plotTest GroupName yMin Transparency SecondTitle
517           TestName pValue;
518        BeginGraph;
519           if (NSTRATA=1)
520              if (EXISTS(STRATUMID))
521                 entrytitle &titletext1;
522              else
523                 entrytitle &titletext0;
524              endif;
525              if (PLOTATRISK)
526                 entrytitle "with Number of Subjects at Risk" / textattrs=
527                    GRAPHVALUETEXT;
528              endif;
529              layout overlay / xaxisopts=(&xoptions) yaxisopts=(&yoptions);
530                 if (PLOTHW=1 AND PLOTEP=0)
531                 bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME / displayTail=false modelname="Survival" fillattrs=
532                    GRAPHCONFIDENCE name="HW" legendlabel=LABELHW;
533              endif;
534              if (PLOTHW=0 AND PLOTEP=1)
535                 bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME / displayTail=false modelname="Survival" fillattrs=
536                    GRAPHCONFIDENCE name="EP" legendlabel=LABELEP;
537              endif;
538              if (PLOTHW=1 AND PLOTEP=1)
539                 bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME / displayTail=false modelname="Survival" fillattrs=
540                    GRAPHDATA1 datatransparency=.55 name="HW" legendlabel=LABELHW;
541                 bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME / displayTail=false modelname="Survival" fillattrs=
542                    GRAPHDATA2 datatransparency=.55 name="EP" legendlabel=LABELEP;
543              endif;
544              if (PLOTCL=1)
545                 if (PLOTHW=1 OR PLOTEP=1)
546                    bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / displayTail=false modelname="Survival" display=(
547                       outline) outlineattrs=GRAPHPREDICTIONLIMITS name="CL" legendlabel=LABELCL;
548                 else
549                    bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / displayTail=false modelname="Survival" fillattrs=
550                       GRAPHCONFIDENCE name="CL" legendlabel=LABELCL;
551                 endif;
552              endif;
553              stepplot y=SURVIVAL x=TIME / name="Survival" rolename=(_tip1=ATRISK _tip2=EVENT) tiplabel=(_tip1="Number at
553! Risk"
554                 _tip2="Observed Events") tip=(x y _tip1 _tip2) legendlabel="Survival" lineattrs=(pattern=dashed);
                                                                                                             ------
                                                                                                             772
555              if (PLOTCENSORED=1)
                                 -
                                 79
                                 200
ERROR 772-580: Syntax error: expecting a constant or a dynamic.
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
556                 scatterplot y=CENSORED x=TIME / markerattrs=(symbol=plus) tiplabel=(y="Probability of an Episode of Seeking
556! Care for Back Pain") name="Censored"
557                    legendlabel="Censored";
558              endif;
559              if (PLOTCL=1 OR PLOTHW=1 OR PLOTEP=1)
                           -
                           79
                           76
ERROR 79-322: Expecting a ).
ERROR 76-322: Syntax error, statement will be ignored.
560                 discretelegend "Censored" "CL" "HW" "EP" / location=outside halign=center;
561              else
562                 if (PLOTCENSORED=1)
                                    -
                                    79
                                    200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
563                    discretelegend "Censored" / location=inside autoalign=(topright bottomleft);
564                 endif;
565              endif;
566              if (PLOTATRISK=1)
                               -
                               79
                               200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
567                 innermargin / align=bottom;
568                    axistable x=TATRISK value=ATRISK / display=(label) valueattrs=(size=7pt);
569                 endinnermargin;
570              endif;
571              endlayout;
572           else
573              entrytitle &titletext2;
574              if (EXISTS(SECONDTITLE))
                           -
                           79
                           76
ERROR 79-322: Expecting a ).
ERROR 76-322: Syntax error, statement will be ignored.
575                 entrytitle SECONDTITLE / textattrs=GRAPHVALUETEXT;
576              endif;
577              layout overlay / xaxisopts=(&xoptions) yaxisopts=(&yoptions);
578              if (PLOTHW=1)
                           -
                           79
                           200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
579                 bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME / displayTail=false group=STRATUM index=STRATUMNUM
579! modelname
580                    ="Survival" datatransparency=Transparency;
581              endif;
582              if (PLOTEP=1)
                           -
                           79
                           200
ERROR 79-322: Expecting a ).

ERROR 200-322: The symbol is not recognized and will be ignored.

583                 bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME / displayTail=false group=STRATUM index=STRATUMNUM
583! modelname
584                    ="Survival" datatransparency=Transparency;
585              endif;
586              if (PLOTCL=1)
                           -
                           79
                           200
587                 if (PLOTHW=1 OR PLOTEP=1)
                              -
                              79
                              76
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
ERROR 76-322: Syntax error, statement will be ignored.
588                    bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / displayTail=false group=STRATUM index=STRATUMNUM
589                       modelname="Survival" display=(outline) outlineattrs=(pattern=ShortDash);
590                 else
591                    bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / displayTail=false group=STRATUM index=STRATUMNUM
592                       modelname="Survival" datatransparency=Transparency;
593                 endif;
594              endif;
595              stepplot y=SURVIVAL x=TIME / group=STRATUM index=STRATUMNUM name="Survival" rolename=(_tip1=ATRISK _tip2=EVENT)
596                 tiplabel=(_tip1="Number at Risk" _tip2="Observed Events") tip=(x y _tip1 _tip2);
597              if (PLOTCENSORED=1)
                                 -
                                 79
                                 200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
598                 scatterplot y=CENSORED x=TIME / group=STRATUM index=STRATUMNUM tiplabel=(y="Probability of an Episode of
598! Seeking Care for Back Pain") markerattrs=(
599                    symbol=plus);
600              endif;
601              if (PLOTATRISK=1)
                               -
                               79
                               200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
602                 innermargin / align=bottom;
603                    axistable x=TATRISK value=ATRISK / display=(label) valueattrs=(size=7pt) class=CLASSATRISK colorgroup=
604                       CLASSATRISK;
605                 endinnermargin;
606              endif;
607              DiscreteLegend "Survival" / title=GROUPNAME location=outside;
608              if (PLOTCENSORED=1)
                                 -
                                 79
                                 200
609                 if (PLOTTEST=1)
                                -
                                79
                                200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
610                    layout gridded / rows=2 autoalign=(TOPRIGHT BOTTOMLEFT TOP BOTTOM) border=true BackgroundColor=
611                       GraphWalls:Color Opaque=true;
612                       entry "+ Censored";
613                       if (PVALUE < .0001)
                                     -
                                     79
                                     200
614                          entry TESTNAME " p " eval (PUT(PVALUE, PVALUE6.4));
                                                           -
                                                           79
                                                           200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
615                       else
616                          entry TESTNAME " p=" eval (PUT(PVALUE, PVALUE6.4));
                                                           -
                                                           79
                                                           200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
617                       endif;
618                    endlayout;
619                 else
620                    layout gridded / rows=1 autoalign=(TOPRIGHT BOTTOMLEFT TOP BOTTOM) border=true BackgroundColor=
621                       GraphWalls:Color Opaque=true;
622                       entry "+ Censored";
623                    endlayout;
624                 endif;
625              else
626                 if (PLOTTEST=1)
                                -
                                79
                                200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
627                    layout gridded / rows=1 autoalign=(TOPRIGHT BOTTOMLEFT TOP BOTTOM) border=true BackgroundColor=
628                       GraphWalls:Color Opaque=true;
629                       if (PVALUE < .0001)
                                     -
                                     79
                                     200
630                          entry TESTNAME " p " eval (PUT(PVALUE, PVALUE6.4));
                                                           -
                                                           79
                                                           200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
631                       else
632                          entry TESTNAME " p=" eval (PUT(PVALUE, PVALUE6.4));
                                                           -
                                                           79
                                                           200
ERROR 79-322: Expecting a ).
ERROR 200-322: The symbol is not recognized and will be ignored.
633                          endif;
634                    endlayout;
635                 endif;
636              endif;
637           endlayout;
638        endif;
639     EndGraph;
640  end;
WARNING: Object will not be saved.
641  run;
NOTE: PROCEDURE TEMPLATE used (Total process time):
      real time           0.08 seconds
      cpu time            0.09 seconds

WARNING: Errors were produced.
NOTE: The SAS System stopped processing this step because of errors.

 

ballardw
Super User

Dashed is not a valid name for a dashed line style. So since it is not recognized the syntax checker thinks that Dashed should be a dynamic variable or possibly enclosed in quotes as literal text value.

Choices for line type names are Solid, ShortDash, MediumDash, LongDash,MediumDashShortDash, DashDashDot, DashDotDot, Dash, LongDashShortDash, Dot, ThinDot, ShortDashDot, MediumDashDotDot or numbers from 1 (solid) to 46 which are many combinations of dashes, dots, lengths and numbers of dashes, numbers and sizes of dots.

 

So that is the error at line 554.

 

The errors occuring at = such as

566              if (PLOTATRISK=1)
                               -
                               79
                               200

might be the result of copy and paste from a source using a different symbol for the = or sometimes an invisible character from some sources. Or maybe correcting the pattern may clear some of this up.

 

kstolzmann
Obsidian | Level 7

Thanks! That solved the error message at least although I was only able to change all of the lines using this method (I couldn't figure out how to change one to dashed, one to solid, etc.).

 

I found another way to modify the proc template, which is easy and worked!

 


data _null_;
%let url = //support.sas.com/documentation/onlinedoc/stat/ex_code/131;
infile "http:&url/templft.html" device=url;
file 'macros.tmp';
retain pre 0;
input;
if index(_infile_, '</pre>') then pre = 0;
if pre then put _infile_;
if index(_infile_, '<pre>')  then pre = 1;
run;
%inc 'macros.tmp' / nosource;


%ProvideSurvivalMacros

%let GraphOpts = attrpriority=none
DataLinePatterns=(Solid ShortDash LongDash);

%let StepOpts = lineattrs=(thickness=1.5);

%let TitleText0 = METHOD " Survival Estimate";
%let TitleText1 = &titletext0 " for " STRATUMID;
%let TitleText2 = &titletext0 "s";
%let yOptions   = label="Probability of Seeking Care for Back Pain"
                  shortlabel="Probability of Seeking Care for Back Pain"
				  labelattrs=(size=9pt weight=bold)
				  tickvalueattrs=(size=8pt)
                  linearopts=(viewmin=0 viewmax=1
                              tickvaluelist=(0 .2 .4 .6 .8 1.0));
%let xOptions   = shortlabel="Number of Years to Back Pain"
                  offsetmin=.05
				  labelattrs=(size=10pt weight=bold)
				  tickvalueattrs=(size=8pt)
                  linearopts=(viewmax=MAXTIME tickvaluelist=XTICKVALS
                              tickvaluefitpolicy=XTICKVALFITPOL);

%CompileSurvivalTemplates

kstolzmann
Obsidian | Level 7

Thanks, I did look into this but I think I figured out a different way (I spent so much time on modifying the proc template and I wasn't sure if the %modstyle macro was compatible) 

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 6 replies
  • 2187 views
  • 2 likes
  • 3 in conversation