BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
PaigeMiller
Diamond | Level 26

I can create an output with four plots on one page using ODS LAYOUT ABSOLUTE, as shown in code #1. But then I want to use a BY statement in PROC SGPLOT, such that the first I get four plots on one page, where all four plots are for the same level of the BY variable and the plots are always in the same position, see code #2.


Code #1, this works as expected, but I have not used a BY statement:

ods pdf file="absolute.pdf";
ods layout absolute ;
ods region x=.5in y=0.1in width=4in height=2.75in;
proc sgplot data=sashelp.cars;
    histogram msrp;
run;
ods region  x=5.1in y=.1in width=4in height=2.75in;
proc sgplot data=sashelp.cars;
    histogram invoice;
run;
ods region  x=.5in y=5.25in width=4in height=2.75in;
proc sgplot data=sashelp.cars;
    histogram mpg_city;
run;
ods region  x=5.1in y=5.25in width=4in height=2.75in;
proc sgplot data=sashelp.cars;
    histogram horsepower;
run;
ods layout end;
ods pdf close;

Now, code #2, with a BY Statement, it doesn't work at all, how can I get something like this to work? I want three output pages, the first page would be four plots for origin='Asia', with MSRP top left, INVOICE top right, MPG_CITY bottom left and HORSEPOWER bottom right; second page would be for origin='Europe', exact same arrangement of plots; third page would be for origin='USA', exact same arrangement of plots.

proc sort data=sashelp.cars out=cars;
    by origin;
run;
ods pdf file="absolute2.pdf";
ods layout absolute ;
ods region x=.5in y=0.1in width=4in height=2.75in;
proc sgplot data=cars;
    by origin;
    histogram msrp;
run;
ods region  x=5.1in y=.1in width=4in height=2.75in;
proc sgplot data=cars;
    by origin;
    histogram invoice;
run;
ods region  x=.5in y=5.25in width=4in height=2.75in;
proc sgplot data=cars;
    by origin;
    histogram mpg_city;
run;
ods region  x=5.1in y=5.25in width=4in height=2.75in;
proc sgplot data=cars;
    by origin;
    histogram horsepower;
run;
ods layout end;
ods pdf close;

Adding: I'm sure I could just wrap this in a macro and loop through all possible values of the BY variable and do it that way, but over the years I have found that SAS is very good at anticipating needs and creating features to do this, so really I'd like to do this without a macro if possible.

--
Paige Miller
1 ACCEPTED SOLUTION

Accepted Solutions
Rick_SAS
SAS Super FREQ

A macro is not bad, but (as requested) here is an alternative that uses a SAS feature: replaying output in a different order by using PROC DOCUMENT.  Do the following:

1. Read the article "Reorder the output from a BY-group analysis in SAS", which shows how to use ODS DOCUMENT to save your output to a document.

2. Use the second part of your program to write the graphs. (You can omit the ODS LAYOUT statements)

3. Use ODS LAYOUT and PROC DOCUMENT to replay the graphs in the order you want.

 

I haven't used ODS LAYOUT ABSOLUTE before and I am not skilled with PDF output, but the following (which uses ODS LAYOUT GRIDDED to HTML) should get you started and demonstrate the technique:

 

proc sort data=sashelp.cars out=cars;
    by origin;
run;
/* write all output to a document */
ods document name=doc(write);      /* wrap ODS DOCUMENT around the output */
proc sgplot data=cars;
    by origin;
    histogram msrp;
run;
proc sgplot data=cars;
    by origin;
    histogram invoice;
run;
proc sgplot data=cars;
    by origin;
    histogram mpg_city;
run;
proc sgplot data=cars;
    by origin;
    histogram horsepower;
run;
ods document close;                /* wrap ODS DOCUMENT around the output */

/* list the outputs */
proc document name=doc(read);
   list / levels=all bygroups;  /* add column for each BY group var */
run;


/* Replay the graphs in a different order */
ods layout gridded rows=2 columns=2 advance=table
    row_gutter=10px column_gutter=10px
    x=.5in y=0.1in width=4in height=2.75in;
proc document name=doc(read);
      replay \SGPlot#1\ByGroup1#1\SGPlot#1;   /* Asia : MSRP */
      replay \SGPlot#2\ByGroup1#1\SGPlot#1;   /* Asia : Invoice */
      replay \SGPlot#3\ByGroup1#1\SGPlot#1;   /* Asia : MPG_City */
      replay \SGPlot#4\ByGroup1#1\SGPlot#1;   /* Asia : Horesepower */
run;quit;
ods layout end;

ods layout gridded rows=2 columns=2 advance=table
    row_gutter=10px column_gutter=10px
    x=.5in y=0.1in width=4in height=2.75in;
proc document name=doc(read);
      replay \SGPlot#1\ByGroup2#1\SGPlot#1;   /* Europe : MSRP */
      replay \SGPlot#2\ByGroup2#1\SGPlot#1;   /* Europe : Invoice */
      replay \SGPlot#3\ByGroup2#1\SGPlot#1;   /* Europe : MPG_City */
      replay \SGPlot#4\ByGroup2#1\SGPlot#1;   /* Europe : Horesepower */
run; quit;
ods layout end;

ods layout gridded rows=2 columns=2 advance=table
    row_gutter=10px column_gutter=10px
    x=.5in y=0.1in width=4in height=2.75in;
proc document name=doc(read);
   replay \SGPlot#1\ByGroup3#1\SGPlot#1;   /* USA : MSRP */
   replay \SGPlot#2\ByGroup3#1\SGPlot#1;   /* USA : Invoice */
   replay \SGPlot#3\ByGroup3#1\SGPlot#1;   /* USA : MPG_City */
   replay \SGPlot#4\ByGroup3#1\SGPlot#1;   /* USA : Horesepower */
run; quit;
ods layout end;

If you don't want to type out all those statements, you can use a DATA _NULL_ step and CALL EXECUTE to automate this process, as shown in "Display output conditionally with PROC DOCUMENT."

 

A hat tip to @WarrenKuhfeld who taught me this technique.

View solution in original post

8 REPLIES 8
Rick_SAS
SAS Super FREQ

A macro is not bad, but (as requested) here is an alternative that uses a SAS feature: replaying output in a different order by using PROC DOCUMENT.  Do the following:

1. Read the article "Reorder the output from a BY-group analysis in SAS", which shows how to use ODS DOCUMENT to save your output to a document.

2. Use the second part of your program to write the graphs. (You can omit the ODS LAYOUT statements)

3. Use ODS LAYOUT and PROC DOCUMENT to replay the graphs in the order you want.

 

I haven't used ODS LAYOUT ABSOLUTE before and I am not skilled with PDF output, but the following (which uses ODS LAYOUT GRIDDED to HTML) should get you started and demonstrate the technique:

 

proc sort data=sashelp.cars out=cars;
    by origin;
run;
/* write all output to a document */
ods document name=doc(write);      /* wrap ODS DOCUMENT around the output */
proc sgplot data=cars;
    by origin;
    histogram msrp;
run;
proc sgplot data=cars;
    by origin;
    histogram invoice;
run;
proc sgplot data=cars;
    by origin;
    histogram mpg_city;
run;
proc sgplot data=cars;
    by origin;
    histogram horsepower;
run;
ods document close;                /* wrap ODS DOCUMENT around the output */

/* list the outputs */
proc document name=doc(read);
   list / levels=all bygroups;  /* add column for each BY group var */
run;


/* Replay the graphs in a different order */
ods layout gridded rows=2 columns=2 advance=table
    row_gutter=10px column_gutter=10px
    x=.5in y=0.1in width=4in height=2.75in;
proc document name=doc(read);
      replay \SGPlot#1\ByGroup1#1\SGPlot#1;   /* Asia : MSRP */
      replay \SGPlot#2\ByGroup1#1\SGPlot#1;   /* Asia : Invoice */
      replay \SGPlot#3\ByGroup1#1\SGPlot#1;   /* Asia : MPG_City */
      replay \SGPlot#4\ByGroup1#1\SGPlot#1;   /* Asia : Horesepower */
run;quit;
ods layout end;

ods layout gridded rows=2 columns=2 advance=table
    row_gutter=10px column_gutter=10px
    x=.5in y=0.1in width=4in height=2.75in;
proc document name=doc(read);
      replay \SGPlot#1\ByGroup2#1\SGPlot#1;   /* Europe : MSRP */
      replay \SGPlot#2\ByGroup2#1\SGPlot#1;   /* Europe : Invoice */
      replay \SGPlot#3\ByGroup2#1\SGPlot#1;   /* Europe : MPG_City */
      replay \SGPlot#4\ByGroup2#1\SGPlot#1;   /* Europe : Horesepower */
run; quit;
ods layout end;

ods layout gridded rows=2 columns=2 advance=table
    row_gutter=10px column_gutter=10px
    x=.5in y=0.1in width=4in height=2.75in;
proc document name=doc(read);
   replay \SGPlot#1\ByGroup3#1\SGPlot#1;   /* USA : MSRP */
   replay \SGPlot#2\ByGroup3#1\SGPlot#1;   /* USA : Invoice */
   replay \SGPlot#3\ByGroup3#1\SGPlot#1;   /* USA : MPG_City */
   replay \SGPlot#4\ByGroup3#1\SGPlot#1;   /* USA : Horesepower */
run; quit;
ods layout end;

If you don't want to type out all those statements, you can use a DATA _NULL_ step and CALL EXECUTE to automate this process, as shown in "Display output conditionally with PROC DOCUMENT."

 

A hat tip to @WarrenKuhfeld who taught me this technique.

PaigeMiller
Diamond | Level 26

Thanks, @Rick_SAS , I will give it a try and report back ... but it does seem like a macro would be useful here too, especially if I have a lot more groups of the BY variable.

--
Paige Miller
WarrenKuhfeld
Ammonite | Level 13
Thanks for the mention, Rick! It is good to see the ODS document plugged. It is an incredibly useful tool. If you have ever used SAS documentation from any of the products from the advanced analytics group (e.g. STAT, QC, IML, OR, ETS, Enterprise Miner, and so on) you have seen the results of using the ODS document behinds the scenes. SAS is run, output is captured, then output, often subsets of the full output, are replayed into portions of the documentation. Many years ago, output was captured manually and there was no guarantee it was current. For many years now, thanks in part to tools that rely on the ODS document, you can be sure that the output is correct and current.
PaigeMiller
Diamond | Level 26

@Rick_SAS or @WarrenKuhfeld 


Can you explain this line? Why does SGPlot#1 appear twice? In particular, what does the second SGPlot#1 indicate? Where can I find this in the docs?

 

replay \SGPlot#1\ByGroup3#1\SGPlot#1;
--
Paige Miller
Rick_SAS
SAS Super FREQ

\ProcName\ByGroup\ODSName

This is a version of the familiar PATH that you see when you use ODS TRACE. See SAS Help Center: Paths and Selection

Use

ODS TRACE ON;

prior to writing to the document to see "human readable" versions.

 

PaigeMiller
Diamond | Level 26

Once I wrote the output of the PROC DOCUMENT to a data set so I could look at it, it all became very clear to me. Either a macro or CALL EXECUTE based on the data set output from PROC DOCUMENT would get the job done.

--
Paige Miller
WarrenKuhfeld
Ammonite | Level 13

The heuristic I always use is list the contents of the document, and then use *precisely* the names that the document says are there. I never try to understand or predict them, although before I retired, I could see the logic.

WarrenKuhfeld
Ammonite | Level 13
I should add that the path is hierarchical with # numbers that identify the sequence so that every object in the document has a unique path.

sas-innovate-wordmark-2025-midnight.png

Register Today!

Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.


Register now!

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 8 replies
  • 1269 views
  • 5 likes
  • 3 in conversation