What to do when a table’s not enough?

6

Sure, you have a great looking table and you produce it with PROC TABULATE. And then, bam! Your boss comes along and decides that since your output looks so good in Word, that he’d like that boilerplate paragraph inserted automatically. Currently, you produce the tables and then pass the RTF files off to a colleague who cuts and pastes the boilerplate text into the document and then resaves the document, but life would be so much easier for everyone if your program could do this automatically. Your boss wants to know if this is possible. And, you want to know, if it’s possible, how?

ODS TEXT to the rescue! The purpose of the ODS TEXT statement is to write text to all open ODS destinations. Your perfectly good PROC TABULATE step looks like this:

Figure 1: Perfectly Good PROC TABULATE Output

The boilerplate text is just a standard disclaimer or maybe it changes for every customer. For illustration purposes, this boilerplate text will be read with a DATA step program:

data boilerplate;
  length line $100 caption1 caption2 $4000;
  retain caption1 ' ' caption2 ' ';
  infile datalines dsd;
  input capnum line $;
  if capnum = 1 then caption1 = catx(' ',caption1,line);
  else caption2 = catx(' ',caption2,line);
  call symputx('caption1',caption1);
  call symputx('caption2',caption2);
return;
datalines4;
1,"xxxxxxxxx yyyyyyyyy zzzzzzzzz"
. . . more text for Caption 1 . . .
2,"aaaaa bbbbbbb ccccccc ddddddd eeeee"
. . . more text for Caption 2 . . . 
;;;;
run;
%put &caption1;
%put &caption2;

The results of the %PUT statements are shown in the SAS Log:

Figure 2: Caption Text Displayed in SAS Log

So now, the captions can be used in the TABULATE program. Here is the revised code:

ods rtf file='c:\temp\caption_program.rtf' startpage=no;
  ods text="&caption1";
 
  proc tabulate data=shoes f=comma10.;
  run;
  title;
 
  ods text="&caption2";
 
  proc tabulate data=shoes f=comma10.;
  run;
ods rtf close;

And here is the output created from that code:

Figure 3: TABULATE Output With Captions

Of course, instead of using a DATA step program and Macro variables, the captions could have been typed into the ODS TEXT statements, but this method would also allow you to change the text programmatically, if you needed to.

ODS TEXT= is one of the ODS options that is covered in our SAS Report Writing 1: Essentials class, along with more details on PROC TABULATE, PROC REPORT and ODS STYLE= options. So now, you know how to add absolutely frabjous captions to your tables and report output.

The full code is available here.

Share

About Author

Cynthia Zender

Cynthia Zender is an instructor and course developer at SAS Institute. With Lauren Haworth and Michele Burlew, she has co-authored the book "Output Delivery System: The Basics and Beyond."

Related Posts

6 Comments

  1. So what if my content also contains titles and footnotes? I've found when I try to add ODS TEXT, it appears after the footnotes. Is there a way to insert ODS text after my table/graph and before the footnote?

    • Cynthia Zender on

      Hi, Andrea:
      I'm guessing that you are discovering that difference usually with HTML versus RTF and PDF destinations. When I run the code below, the HTML output file has the footnote IMMEDIATELY underneath the table and then the ODS TEXT= caption. And that's what I expect, because an HTML file does not have the concept of "header" area or "footer" area in the document, the same way that "paged" destinations like RTF or PDF do.

      . . .

      But usually with paged destinations like RTF and PDF, the TITLE and FOOTNOTES have a specified place to go -- and ODS knows how to insert the SAS TITLE statement text into the "header" area of the paged document (and likewise, the SAS FOOTNOTE goes into the "footer" area of the paged document.

      . . .

      And, of course, you could get into many different scenarios, like using BODYTITLE or SAS Macro programs, where timing issues could throw things off. Or, I could totally break titles and footnotes for RTF and PDF by moving the TITLE and FOOTNOTE statements inside of the PROC TABULATE code. Normally, you don't think about where you use TITLES and FOOTNOTES in your code, because they are GLOBAL statements. But I have noticed that I have the best "luck" with ODS TEXT when I establish by TITLE and FOOTNOTES -before- I ever issue an ODS TEXT= statement. That seems to cause the ODS TEXT statement to behave. For more information or for trickier situations with ODS TEXT, I'd recommend reading this Tech Support note (39195) or working directly with Tech Support.

      . . .

      cynthia

      . . .

      *** the new example;
                           
      ** 4) Revised program with captions added;
      title '4a) PROC TABULATE Captioned Output';
      footnote '4a) Footnote';
      run;
                
      ods html file='c:\temp\caption_program_with_footnote.html';
      ods pdf file='c:\temp\caption_program_with_footnote.pdf' startpage=no;
      ods rtf file='c:\temp\caption_program_with_footnote.rtf' startpage=no;
      ods text="&caption1";
      proc tabulate data=shoes f=comma10.;
      where product contains 'Dress';
        class region product;
        var sales;
        table region=' ' all,
              (product='Product Sales' all)*(n mean sum)*sales=' ' /
              box={label='Region' style={vjust=b}} style={width=5.5in};
        keylabel all='Summary';
      run;
      title;
         
       ods text="&caption2";
          
      proc tabulate data=shoes f=comma10.;
      where product contains 'Casual';
        title ' ';
        class region product;
        var sales;
        table region=' ' all,
              (product='Product Sales' all)*(n mean sum)*sales=' ' /
              box={label='Region' style={vjust=b}} style={width=5.5in};
        keylabel all='Summary';
      run;
      ods text="More Text and ... &caption1";
      ods _all_ close;
      title; footnote;
      
    • Edward Ballard on

      I also find that using POSTText sometimes is a better option than footnotes when using RTF output.

      • Cynthia Zender on

        Hi:
        True. I like to think of SAS and ODS and style attributes as giving you a Swiss Army knife full of choices. I usually use PREIMAGE and POSTIMAGE to put a picture either above or below a table, so PRETEXT and POSTTEXT would serve the same purpose with text. Another reason for using ODS TEXT is that you want your "captions" between PROCEDURE steps; but POSTTEXT and PRETEXT could happen for every PAGE, as generated by PROC REPORT, TABULATE or PRINT.
        ...
        The issue for me is that the FOOTNOTE statement ALWAYS goes in the footer area of the document, while both ODS TEXT and POSTTEXT go IMMEDIATELY underneath the table (not necessarily at the bottom of the page). You just have to know how the technique will "behave" in your destination of choice.
        ...
        cynthia

  2. Great post and example... Would you say that this is a better alternative than using title statements with style changes on the titles? I imagine the style for the ODS text can be easily customized for each ODS text statement too.

    • Cynthia Zender on

      Hi, Michelle:
      I don't know, I suppose it 's a matter of preference over ease of use. The TITLE and FOOTNOTE options are quite easy to use -- easier to explain for the beginner than using ODS ESCAPECHAR or using a style template to change the USERTEXT style element. But for the experienced programmer, I think it comes down to preference.

      Personally, I tend to use ODS TEXT for exactly the blog example -- putting large "chunks" of text (not the poem Jabberwocky) into a document. But different destinations treat TITLE and FOOTNOTES differently, so I'm going to fall back on "it depends on the destination." And, there's also the chance that some destinations might not use ODS TEXT the way you want. But I have seen examples where people will use ODS TEXT for pseudo-titles or pseudo-footnotes, especially in PDF and RTF when you have STARTPAGE=NO. To learn how to change the style of the ODS TEXT= option, you can look in my book with Lauren and Michele, or you can look at the Tech Support note (8044), that has code for both ways to change the style.

      cynthia

Back to Top