BookmarkSubscribeRSS Feed
jiayaqi9061
Calcite | Level 5

Hi

 

When I write SAS macros, I want to send plots generated by PROC SGPLOT directly to word document, but SAS returns a blank work document. Below is the detail:

 

ods rtf file="&outpath.&fname.&sysdate..doc";

options nodate nonumber;

proc sgplot data=_plot;

yaxis values=(0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1.0);

xaxis values= (&xaxisvalue);

step y=CIF x=time /group=status;

run;

 

I can't find the solution. Thanks

 

Best

 

Yaqi

 

7 REPLIES 7
Reeza
Super User

Please post your full code.

 

At the least there's no ODS RTF Close.

jiayaqi9061
Calcite | Level 5

I can get word document, but it is blank. Below is the full code: Thanks

 

%macro cif_plot(dsn=,grplist=,time=,censor=,event=1,censored=0,title1=,title2=,xaxisvalue=,timelist=,plot=T,units=,compete=T,
   outpath=, fname=, debug=F);

   /* Prevent case sensitivity */
   %let plot = %UPCASE(&plot);
   %let debug = %UPCASE(&debug);
   %let compete = %UPCASE(&compete);
   %if &units ~= %str() %then %let units = %sysfunc(PROPCASE(&units));

   /* Count number of time estimates requested */
   %let time_cnt = %sysfunc(countw(&timelist,' '));
   
   %let n=1;
   %do %until (%scan(&grplist,&n)= );
   %let grp=%scan(&grplist,&n);
   %put grp=&grp;
   DATA _cif_temp;
      set &dsn;
      /* If group variable is missing then delete it to avoid a missing category being 
      included in the plots */
      %if &grp ~= %STR() %then %do;
         if MISSING(&grp)=1 then delete;
      %end;
   RUN;

   %CIF(DATA=_cif_temp, out=_stat1, TIME=&time, STATUS=&censor, EVENT=&event, CENSORED=&censored, group=&grp, 
   OPTIONS=NOCIFEST NOPRINTTEST NOPLOT);

   %if &grp ~= %STR() %then %do;
      /* Get Gray's p-value */
      PROC SQL noprint;
         select pval format=pvalue6.4 into :pval1
         from testresult;
      QUIT;
      PROC DATASETS lib=work noprint;
        delete testresult;
      QUIT;
   %end;

   /* If plotting both event of interst and competing event - calculate CIF for competing event */
   %if &compete = T %then %do;
      
      /* Extract value(s) of competing risk from censor variable*/
      proc sql noprint;
	    select distinct &censor into: cenval separated by ' ' from _cif_temp;
	  quit;

	  %put value of censor = &cenval;

	  %let n=1;
	  %let comrisk=; /*macro variable for values of competing risk*/
	  %do %until (%scan(&cenval,&n)= );
	    %let  cenvaln=%scan(&cenval,&n);
	    %if &cenvaln ~= &event and &cenvaln ~= &censored
		%then %let comrisk= &comrisk &cenvaln;
		%let n=%eval(&n+1);
	  %end;
      
	  %put The value(s) of competing risk = &comrisk;/*check the value(s) of competing risk*/

      %CIF(DATA=_cif_temp, out=_stat2, TIME=&time, STATUS=&censor, EVENT=&comrisk, CENSORED=&censored, group=&grp, 
      OPTIONS=NOCIFEST NOPRINTTEST NOPLOT);


      %if &grp ~= %STR() %then %do;
         /* Get Gray's p-value */
         PROC SQL noprint;
            select pval format=pvalue6.4 into :pval2
            from testresult;
         QUIT;

        PROC DATASETS lib=work noprint;
           delete testresult;
        QUIT;
      %end;

   %end;

   /* Get event labels */
   PROC SORT DATA = _cif_temp out = _events nodupkey;
      by &censor;
      where &censor ~= 0;
   RUN;

   PROC SQL noprint;
      select &censor into :event1
      from _events
      where &censor = 1;
      select &censor into :event2
      from _events
      where &censor = 2;
   QUIT;

   /* If groups were used */
   %if &grp ~= %STR() %then %do;
      DATA _NULL_;
         set _cif_temp;
         /* Group Label */
         CALL SYMPUT('grpL',VLABEL(&grp));
      RUN;
   %end;

   /* Create variable to group by in plot */
   DATA _stat1plot;
      set _stat1plot;
      %if &grp ~= %STR() %then %do;
         %if &compete = T %then %do;
            status = TRIM(&grp) || ": " || "&event1";
         %end;      
         %else %do;
            status = TRIM(&grp);
         %end;
      %end;
      %else %do; 
         status = "&event1";
      %end;
   RUN;

   /* If plotting both event of interst and competing event - calculate CIF for competing event */
   %if &compete = T %then %do;

      DATA _stat2plot;
         set _stat2plot;
         %if &grp ~= %STR() %then %do;
            status = TRIM(&grp) || ": " || "&event2";
         %end;
         %else %do; 
            status = "&event2";
         %end;
      RUN;

   %end;

   /* Merge files for plot */
   DATA _plot;
      length status $256;
      set _stat1plot  %if &compete = T %then %do; _stat2plot %end;;
      time = &time;

      %if &grp ~= %STR() %then %do; 
         LABEL status = "&grpL";
      %end;
      %else %do;
        LABEL status = 'Event';
      %end;

      LABEL cif = 'Probability'
         time = "Time (&units)";
   RUN;

   /* Sort groups for plotting */
   %if &grp ~= %STR() %then %do;
      PROC SORT DATA = _plot;
        by &grp;
     RUN;
   %end;     

   %if &title1 ~= %STR() %then %do; TITLE1 &title1; %end;
   %if &title1 ~= %STR() %then %do; TITLE2 &title2; %end;

  ods rtf file="&outpath.&fname.&sysdate..doc";
  options nodate nonumber;
   /* Create plot if requested */
   %if &plot = T %then %do;
   Title " CIF plot by &grp";
      proc sgplot data=_plot;
         yaxis values=(0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1.0);
		 xaxis values= (&xaxisvalue);
         step y=CIF x=time /group=status;
         %if &grp ~= %STR() %then %do;
            /* Report both event of interest and competing risk results */
            %if &compete = T %then %do;
               inset ("%TRIM(&event1.)="="&PVAL1" "%TRIM(&event2.)="="&PVAL2")/position=topright border 
               TITLE="Gray's p-value" LABELALIGN=LEFT;
            %end;
            /* Only report event of interest */
            %else %do;
               inset ("Gray's p-value="="%TRIM(&PVAL1)")/position=topright border LABELALIGN=LEFT;
            %end;
         %end;
      run;
   %end;

   /* If time estimates were requested */
   %if &time_cnt > 0 %then %do;
      DATA _est;
        set _plot;
       %do i = 1 %to &time_cnt;
          %let timept = %SCAN(&timelist,&i,' ');

         /* Create indicator if time is less than or equal to time of interest */
          if &time <= &timept then _LT&i = 1;
         else _LT&i = 0;
       %end;
     RUN;

     PROC SQL;
        create table _est2
       as select *,  max(&time) as max_time, max(&time*_LT1) as _max1 
         %do i = 2 %to &time_cnt;  , max(&time*_LT&i) as _max&i %end;
       from _est
       group by status;
     QUIT;

     DATA _est3;
        set _est2;
       /* Subset on time points of interest */
       %do i = 1 %to &time_cnt;
          %let timept = %SCAN(&timelist,&i,' ');

          if &time = _max&i then do;
            _time = &timept;
            output;
         end;
       %end;

     RUN;

     DATA _est3;
        set _est3;
       /* Convert to character */
       cif_c = PUT(cif,percent8.2);
       lcl_c = PUT(LowerCI,percent8.2);
       ucl_c = PUT(upperCI,percent8.2);

       /* Make sure estimates are not for times beyond the length of the data */
       if _time > max_time then do;
            cif_c = 'NA';
            Lcl_c = 'NA';
            Ucl_c = 'NA';
       end;

       /* Combine estimate and CI */
       rate = TRIM(cif_c) || " (" || TRIM(LEFT(LCL_c)) || ", " || TRIM(LEFT(UCL_c)) || ")";

     RUN;

     PROC SORT DATA = _est3;
        by status _time;
     RUN;

     proc report nowd data=_est3 style(report)={rules=GROUPS}  
            style(header)={BACKGROUNDCOLOR=none} LS=256 STYLE(COLUMN) = {JUST = C};
         col status _time rate;
         define status/order style={just=l};
         LABEL _time = "Time (&units)"
            rate = 'CIF Estimate (95% CI)'; 
      RUN;

   %end;

   TITLE;

   %let n=(&n+1);
%end;
   /* If not in debug mode */
   %if &debug = F %then %do;
      /* Delete intermediate datasets */
      PROC DATASETS lib=work noprint;
        delete _events _plot _stat1 _stat1plot %if &compete = T %then %do; _stat2 _stat2plot %end;
         %if &time_cnt > 0 %then %do; _est _est2 _est3 %end; _cif_temp;
      QUIT;
   %end;

%mend;

 

ballardw
Super User

Also check the log to see if you're getting messages about invalid paths or file names.

The naming a file with a different extension, docx for rtf, than Microsoft uses may not help due to the increasingly obnoxious "extension does not match contents" stuff Microsoft has been doing. name as RTF and Save-As to docx if needed.

jiayaqi9061
Calcite | Level 5

Hi Ballardw:

 

I have checked log message several times and there are not any warning or error messages. At the beginning, I tried RTF, but it doesn't work. Then I use doc, sometimes it works, but most of times, it also doesn't work. ' It doesn't work' means I can get work document, then it pop out a message with  like " open a read only copy', then I open it, nothing is inside. I don't know why. below is the shortcut.

 

Read only copy.png

Reeza
Super User

Make sure to open the RTF file with Word, not a text editor. The graph won't show in a text editor.

 

For your code - add some put statements to make sure the logic is working the way you intendded.

jiayaqi9061
Calcite | Level 5
There is no problem on code, I have checked many times and I can get results of html, if I don't use ods rtf. Even if I use ods rtf, sometimes it works and I cant get figure and table in word document. I didn't do any change, just run it again.
Reeza
Super User

Test if the following works. If it generates a file that opens and shows a graph then your doing something wrong...most likely in your conditonal logic.

 

ods rtf file="c:\_localdata\test.rtf" style=meadow;

proc sgplot data=sashelp.class;
scatter x=weight y=height/group=sex;
run;

ods rtf close;

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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
  • 7 replies
  • 2159 views
  • 0 likes
  • 3 in conversation