%macro rocplot ( version, outroc=, out=, p=, id=, plottype=high, font=swissb, size=3, color=black, plotchar=dot, roffset=4, grid=n, mindist=0.02, round=1e-8 ); %let _version=1.1; %if &version ne %then %put ROCPLOT macro Version &_version; %let opts = %sysfunc(getoption(notes)); %if &version ne debug %then %str(options nonotes;); /* Check for newer version */ %if %sysevalf(&sysver >= 8.2) %then %do; %let _notfound=0; filename _ver url 'http://ftp.sas.com/techsup/download/stat/versions.dat' termstr=crlf; data _null_; infile _ver end=_eof; input name:$15. ver; if upcase(name)="&sysmacroname" then do; call symput("_newver",ver); stop; end; if _eof then call symput("_notfound",1); run; %if &syserr ne 0 or &_notfound=1 %then %put &sysmacroname: Unable to check for newer version; %else %if %sysevalf(&_newver > &_version) %then %do; %put &sysmacroname: A newer version of the &sysmacroname macro is available.; %put %str( ) You can get the newer version at this location:; %put %str( ) http://support.sas.com/ctx/samples/index.jsp; %end; %end; %let nomatch=0; /* Verify ID= is specified */ %if %quote(&id)= %then %do; %put ERROR: At least one ID= variable is required.; %goto exit; %end; /* Verify P= is specified */ %if %quote(&p)= %then %do; %put ERROR: The P= option is required.; %goto exit; %end; /* Verify OUTROC= is specified and the data set exists */ %if %quote(&outroc) ne %then %do; %if %sysfunc(exist(&outroc)) ne 1 %then %do; %put ERROR: OUTROC= data set not found.; %goto exit; %end; %end; %else %do; %put ERROR: The OUTROC= option is required.; %goto exit; %end; /* Verify OUT= is specified and the data set exists */ %if %quote(&out) ne %then %do; %if %sysfunc(exist(&out)) ne 1 %then %do; %put ERROR: OUT= data set not found.; %goto exit; %end; %end; %else %do; %put ERROR: The OUT= option is required.; %goto exit; %end; data _outroc; set &outroc; _prob_=round(_prob_,&round); run; data _out; set &out; _obs_=_n_; if &p = . then delete; _prob_=round(&p , &round); run; proc sort data=_out nodupkey; by _prob_; run; proc sort data=_outroc nodupkey; by _prob_; run; data _rocplot; _inout=0; _inroc=0; merge _outroc(in=_inroc) _out(in=_inout); by _prob_; if not(_inout and _inroc) then do; call symput('nomatch',1); delete; end; length _id $ 200; _sens_=put(_sensit_,5.3); _spec_=put(-_1mspec_+1,5.3); /* Create single label variable */ _id=trim(left(%scan(&id,1))) %let i=2; %do %while (%scan(&id,&i) ne %str() ); ||'/'||trim(left(%scan(&id,&i))) %let i=%eval(&i+1); %end; ; run; %if &nomatch=1 %then %do; %put ROCPLOT: Some predicted values in OUT= did not match predicted values; %put %str( in OUTROC=. Verify that you used the ROCEPS=0 option in); %put %str( PROC LOGISTIC.); %end; data _add00; _sensit_=0; _1mspec_=0; run; %if %upcase(%substr(&plottype,1,1))=L %then %do; data _rocplot; set _rocplot _add00; run; proc plot data=_rocplot; plot _sensit_*_1mspec_ / haxis=0 to 1 by .1 vaxis=0 to 1 by .1; run; quit; footnote "Point labels are values of &id"; proc plot data=_rocplot; plot _sensit_*_1mspec_ $ _id / haxis=0 to 1 by .1 vaxis=0 to 1 by .1; run; quit; %end; %if %upcase(%substr(&plottype,1,1))=H %then %do; data _anno; length function style color $ 8 position $ 1 text $ 200; retain function 'label' xsys ysys '2' hsys '3' size &size position '6' style "&font" color "&color" xprev xprevtop 1.4; set _rocplot(keep=_sensit_ _1mspec_ _id) end=eof; by _1mspec_ notsorted; x=_1mspec_; y=_sensit_+.025; /* bottom of vertically stacked points or singleton */ if last._1mspec_ then do; if xprev-x>=&mindist then do; text=" "||trim(left(_id)); xprev=x; end; else text=""; end; /* top of vertically stacked points */ else if first._1mspec_ then do; if xprevtop-x>=&mindist then do; text=trim(left(_id)); xprevtop=x; end; else text=""; position=4; end; /* points in middle of stack */ else text=""; angle=350-x*80; /* rotate label from vertical to almost horizontal */ output; position='6'; /* reset retained label position for next obs */ /* Draw (0,0) to (1,1) reference line */ if eof then do; x=0; y=0; function='move'; output; x=1; y=1; function='draw'; line=1; hsys='1'; size=0.25; output; end; run; data _rocplot; set _rocplot _add00; run; symbol1 i=join v=&plotchar c=darkblue l=1; footnote "Point labels are values of &id"; axis1 offset=(&roffset,&roffset)pct order=(0 to 1 by .1); axis2 offset=(&roffset,&roffset)pct order=(0 to 1 by .1) label=(angle=90); proc gplot data=_rocplot; plot _sensit_*_1mspec_=1 / vaxis=axis2 haxis=axis1 annotate=_anno %if %upcase(%substr(&grid,1,1))=Y %then %do; vref=0 to 1 by .1 href=0 to 1 by .1 cvref=cxd4d4d4 chref=cxd4d4d4 %end; ; run; quit; %end; footnote; %exit: options &opts; %mend;