Using the ODS statement to add layers in your ODS sandwich

11

The ODS statement controls most aspects of how SAS creates your output results. You use it to specify the destination type (HTML, PDF, RTF, EXCEL or something else), as well as the details of those destinations: file paths, appearance styles, graphics behaviors, and more. The most common use pattern is the "ODS sandwich." In this pattern, you open the destination with the ODS statement, then include all of the code that generates the substance of the output, and then use an ODS CLOSE statement to finish it off. Here's a classic example:

ods html file="c:\project\myout.html" /* top slice of bread */
  style=journal gpath="c:\project";
  proc means data=sashelp.class;      /* the "meat" */
  run;
 
  proc sgplot data=sashelp.class;
  histogram weight;
  run;
ods html close;                       /* bottom slice */

But did you know that you can insert more ODS statements to adjust ODS behavior midstream? These allow you to use a variety of ODS behaviors within a single result. You can create your own "Dagwood sandwich" version of SAS output! For cultural reference:

Dagwood sandwich: A Dagwood is a tall, multi-layered sandwich made with a variety of meats, cheeses, and condiments. It was named after Dagwood Bumstead, a central character in the comic strip Blondie, who is frequently illustrated making enormous sandwiches. Source: Wikipedia

Here's an example program that changes graph style and title behavior within a single ODS output file. You should be able to try this code in any SAS programming environment.

ods _all_ close;
%let outdir = %sysfunc(getoption(WORK));
ods graphics / width=400 height=400;
 
ods html(id=dagwood) file="&outdir./myout.html"
  style=journal gtitle  
  gpath="&outdir.";
 
  title "Example ODS Dagwood sandwich";
  proc means data=sashelp.class;
  run;
ods layout gridded columns=2;
ods region;
ods html(id=dagwood) style=statdoc ;  
  proc sgplot data=sashelp.class;
  title "This title is part of the graph image, Style=STATDOC";
  histogram weight;
  run;
ods region;
ods html(id=dagwood) style=raven nogtitle;
  title "This title is in the HTML, Style=RAVEN";
  proc sgplot data=sashelp.class;
  histogram height;
  run;
ods layout end;
 
ods html(id=dagwood) close;

odsexHere's the result, plus some important items to note about this technique.

  • It's a good practice to distinguish each ODS destination with an ID= value. This allows you to reference the intended ODS stream with no ambiguity. After all, you can have multiple ODS destinations open at once, even multiple destinations of the same type. In my example, I used ID=dagwood to make it obvious which destination the statement applies to.
  • You can use this technique to modify only those directives that can change "mid-file" to apply to different parts of the output. You can't modify those items that apply to the entire file, such as PATH, ENCODING, STYLESHEET and many more. These can be set just once when you create the file; setting multiple different values wouldn't make sense.

You can use this technique within those applications that generate ODS statements for you, such as SAS Enterprise Guide. For example, to modify the default SAS Enterprise Guide HTML output "midstream", add a statement like:

ods html(id=eghtml) /*... plus your options, like STYLE=*/ ;
ods html(eghtml) /* this shorthand works too */ ;

In SAS Studio or SAS OnDemand for Academics, try this:
ods html5(id=web) /*... plus your options, like STYLE=*/ ;
ods html5(web) /* this shorthand works too */ ;

Example: an ODS Graphics style sampler

samplerHere's one more example that puts it all together. Have you ever wanted an easy way to check the appearance of the dozens of different built-in ODS styles? Here's a SAS macro program that you can run in SAS Enterprise Guide (with the HTML result on) that generates a "sampler" of graphs that show variations in fonts, colors, and symbols across the different styles.

This example uses ODS LAYOUT (production in SAS 9.4) to create a gridded layout of example plots. If you want to try this in SAS Studio or in SAS OnDemand for Academics, you can adjust one line in the program (as noted in the code comments).

/* Run within SAS Enterprise Guide       */
/* with the HTML result option turned ON */
%macro styleSampler;
title;
proc sql noprint;
  select style into :style1-:style99  
    from sashelp.vstyle 
    where libname="SASHELP" and memname="TMPLMST";
 
  ods layout gridded columns=4;
  ods graphics / width=300 height=300;
  %do index=1 %to &sqlobs;
    ods region;
    ods html(eghtml) gtitle style=&&style&index.;
    /* In SAS Studio, use this instead: */
    /* ods html5(web) gtitle style=&&style&index.; */
    title "Style=&&style&index.";
    proc sgplot data=sashelp.class;
    scatter x=Height y=Weight /group=Sex;
    reg x=Age y=Weight / x2axis;
    run; 
  %end;
  ods layout end;
%mend;
 
%styleSampler;

See also

Take control of ODS results in SAS Enterprise Guide
Best way to suppress ODS output in SAS
Advanced ODS Graphics techniques: a new free book

Share

About Author

Chris Hemedinger

Director, SAS User Engagement

+Chris Hemedinger is the Director of SAS User Engagement, which includes our SAS Communities and SAS User Groups. Since 1993, Chris has worked for SAS as an author, a software developer, an R&D manager and a consultant. Inexplicably, Chris is still coasting on the limited fame he earned as an author of SAS For Dummies

11 Comments

  1. I first read through the consolidated daily listing of blog contents that comes as email.

    Why was I not surprised when it linked to a blog written by Chris???? Great job of making this entertaining and giving a wonderful way of remembering what this ODS stuff is all about. My first Dagwood was when I forgot to put an "ODS PDF close" at the point I should have. Big sandwich!

    I am going to reference this in a SGF 2016 paper I am doing on Proc Document. Do I have your permission Chris??

    • Chris Hemedinger
      Chris Hemedinger on

      Roger, of course you can reference this blog -- I'll be honored to make a small appearance in your conference paper.

  2. Hi Chris,

    I want to make you a question about SAS/EG:

    I have a process made in SAS/BASE coding that I want to do now in SAS/EG using workflow. I have to do a logistic regression. In my below code you can see that I run a logistic regression (training dataset), save the modelo and after I apply my model with other dataset (validation)

    proc logistic data=test outmodel=modelo plots=ROC;

    class cod_tarifa productos; model hc_consumo=cod_tarifa productos;

    quit;

    /* /* Apply model*/

    proc logistic inmodel=modelo;

    score data=validar out=validar1;

    quit;

    I am trying to do it with logistic regression task in a workflow. I can select target variable (hc_consumo) and features (cod_tarifa productos), but I don't know haw to save the model, and how to apply after hist model, is it possible in a SAS/EG guided task.

    Any advice will be greatly appreciated

    Thanks Chris

    Juan

  3. I am trying to implement this and get an output that is Excel compatible. I changed the file to myout.xls, and the two graphs overlap. Any thoughts on how to get a "cleaner" result?

    I also do not get a title on the Raven graph, and the Raven style doesn't look anything like yours.

    EG6.1 and Excel 10.

    • Chris Hemedinger
      Chris Hemedinger on

      "Raven" was added in SAS 9.4. And ODS EXCEL was also added in SAS 9.4m2, and ODS LAYOUT was also improved in later versions of SAS 9.4. If you're using EG 6.1, maybe you have SAS 9.3 or an earlier SAS 9.4? If so, I think that might explain the layout and title issues you see.

  4. Pingback: Arrange matrices and graphs in a gridded layout - The DO Loop

  5. Pingback: Advanced ODS: Controlling precisely what output is displayed - Graphically Speaking

  6. Pingback: Advanced ODS: Controlling precisely what output is displayed - Graphically Speaking

Back to Top