Newsgroups: bit.listserv.sas-l
Date:         Wed, 12 Aug 1992 10:52:48 CDT
Reply-To:     finger <sue@ONCOLOGY.UTHSCSA.EDU>
From:         finger <sue@ONCOLOGY.UTHSCSA.EDU>
Subject:      Re: Annotating plot lines
Comments: To: sas-l@uga.cc.uga.edu, HAKOMAKI%UMINN1.BITNET@uga.cc.uga.edu

Hakomaki writes:
| A user wants to label multiple lines on a plot - and I'm looking for
| something that might automatically position the text so it would be
| aesthetically pleasing.

The following is a macro that I use to plot survival data obtained as
output from PROC LIFETEST. Most of the macro is involved with handling
hash marks for censored data, etc.

In reference to Hakomaki's problem, each line will be labeled on the
far right (max x) with a string created by put'ting the stratum
indicator variable _strtm_ (automatically created by LIFETEST) using
the macro argument FORMT as a format. Sometimes the lines are close
vertically and this is handled by the datastep that creates _YLBL_. The
y coordinate for the label is initially the y associated with max x,
but is adjusted up or down to get away from its neighbors until they no
longer overlap. The _YLBL_ dataset is then used to help create the
ANNOTE dataset. Of course, survival curves are nicely behaved monotonic
curves, with predictable forms.

The "put's" and "%put's" are for my information to monitor the macro's
behavior. A symbol statement is generated for each _strtm_ and a final
symbol statement handles all the hash marks. Finally, I write all macro's
so that when they are called without arguments (ie. %PLTOSRV()  ) SAS prints
 information
about how to call the macro (who can remember these things? :-)
-------------------------------------------------------------------------
%macro plotsrv(dataset,survar,formt,pval, max,
	vpos=45,hpos=80, line=2, logbase=1, units=Months, by=12, title=, title2=);
%if %length(&dataset)=0 %then %do;
   %put Calling arguments for PLOTSRV:;
   %put      dataset, survar, formt., pval, max;
   %put 		vpos=45, hpos=80, line=2, logbase=1, ;
   %put                 units=months, by=12, title=, title2= ;
   %goto exeunt;
   %end;
%if &logbase=1 %then %let order= order=(0 to 1 by .1) ;
           %else %let order= logbase=&logbase ;
* %put &order;
%annomac;

%if %length(&max)>0 %then %do;
proc sort data=&dataset out=_pltsrv_;
   by _strtum_ descending &survar _censor_;
   run;
data _pltsrv_;
   set _pltsrv_;
   by _strtum_;
   retain lemax;
   if first._strtum_ or &survar>&max then do;
      lemax=0;
      end;
   if lemax=0 then if &survar<&max then do;
         output;
         lemax=1;
         _censor_=1;
         &survar=&max;
         end;
   if lemax=1 or &survar=&max then output;
%end;
%else %do;
data _null_;
   set _pltsrv_ end=eof;
   retain max 0;
   if &survar> then max=&survar;
   if eof then call symput('max',put(ceiling(max),3.0));
   run;
   %end;
%put &max;
%annomac;
proc sort data=_pltsrv_ out=_pltsrv_;
  by _strtum_ &survar _censor_;
  run;
data _ylbl_(keep=ylbl1--ylbl10);
  retain ylbl1-ylbl10 ylbladj;
  array ylbl[*] ylbl1--ylbl10;
  set _pltsrv_ end=eof;
  by _strtum_;
  ylbladj=1/(&vpos*.6);
  if last._strtum_ then ylbl[_strtum_]=survival;
  if eof then do;
     again=0;
     nstr=_strtum_;
loop:do i=1 to nstr-1;
     	do j=i+1 to nstr;
     	   if abs(ylbl[i]-ylbl[j])< 2*ylbladj then do;
     	      dir=sign(ylbl[i]-ylbl[j]);
     	      ylbl[i]=ylbl[i]+dir*ylbladj;
     	      ylbl[j]=ylbl[j]-dir*ylbladj;
     	      again=1;
     	      end;
            end;
         end;
      if again=1 then do;
         again=0;
         goto loop;
         end;
      output;
      end;
    run;
* proc print;

data annote;
  length text $20;
  array ylbls[*] ylbl1-ylbl10;
  retain maxtime 0 maxlen 0 lbly 0 pxlbl 0 pylbl 1 ylbl1--ylbl10;
  %dclanno;
  %system(2,2,4);
  set _pltsrv_ end=eof;
  by _strtum_;
  if _n_=1 then do;
     set _ylbl_;
     put 'added ylbl';
     end;
  if last._strtum_ then do;
     pxlbl=max(pxlbl,&survar);
     pylbl=min(pylbl,survival);
     put _all_;
     x=&survar*1.05;
     ylbl=ylbls[_strtum_];
     put ylbl;
     text=put(_strtum_,&formt.);
     %label(x, ylbl, text,black, 0,0,1.2,swiss,C);
     maxlen=max(maxlen,length(text));
     maxtime=max(&max,maxtime,(int(&survar/&by)+1)*&by);
     end;
  if eof then do;
     text=compress('p='||"&pval");
     %label(pxlbl/4,max(pylbl,.1),text,black, 0,0,1.2,swiss, F);
     call symput('maxtime',put(maxtime,5.0));
     call symput('maxlen',put(maxlen+1,5.0));
     call symput('offset',put(maxlen*&vpos/&hpos-3,5.0));
     call symput('nstr',put(_strtum_,2.0));
     end;
  run;
%put &maxtime;
%put &maxlen;
%put &offset;
%put &nstr;
data _pltsrv_;
  set _pltsrv_;
  output;
  if _censor_=1 then do;
     _strtum_=&nstr+1;
     output;
     end;
  run;
goptions reset=(symbol);
%do i= 1 %to &nstr;
   symbol&i          i=steplj color=black l=&line ;
   %end;

symbol%eval(&nstr+1) font=simplex v='|' h=.5 color=black ;
goptions  vpos=&vpos hpos=&hpos;

run;
title;
proc gplot data=_pltsrv_ annotate=annote;
  plot survival*&survar=_strtum_/nolegend vaxis=axis1 haxis=axis2;
  axis1 label=(a=90 r=0 h=1.5) value=(h=1.1) &order minor=none;
  axis2 label=(h=1.5) value=(h=1.1)
     order=(0 to %eval(&maxtime + &by) by &by) minor=(n=1);
  label &survar="&units"
        survival='Survival Probability';
  format survival 5.1;
  title %if %length(&title)>0  %then %do;
     %if &offset>0 %then j=c a=-90 h=&offset ' ' ; a=0 h=2 &title %end; ;
  title2 %if %length(&title2)>0 %then j=c a=0 h=2 &title2; ;
   run;
%exeunt: ;
%mend;

------------------------------------------------------------------------
Hope this helps,

Susan G. Hilsenbeck
Internet:	sue@oncology.uthscsa.edu
MaBell:		(512) 567-4749
Comments: Gated by NETNEWS@AUVM.AMERICAN.EDU