The SAS Output Delivery System and reporting techniques

Is it possible to control which ODS destination gets specific output in a Data step?

Accepted Solution Solved
Reply
Regular Contributor
Posts: 150
Accepted Solution

Is it possible to control which ODS destination gets specific output in a Data step?

Hi,

 

Am trying to micro-manage output going to multiple ODS destinations in a DATA step.  Is it possible to specify which destination is active in a FILE statement, or are all of them written to?

 

Thanks!

 

--Ben


Accepted Solutions
Solution
‎06-14-2016 11:32 AM
Grand Advisor
Posts: 9,748

Re: Is it possible to control which ODS destination gets specific output in a Data step?

I am still not sure where your images come in. They would not likely be generated by a data _null_ and file print.

Let's take a stab at some ideas. Suppose I have a very simple report that looks something like this (pseudo code to show that I have two procedures output)

Proc sgplot data=somedata;
   where companyname="somename";
   <plot statements>;
run;

Proc print data=someotherdata;
   where companyname="somename";
   <other print options>
run;

And the code above works for my purpose for a single company and I want to replicate for a large list of companies.

 

So I create a dataset that would have the appropriate values of companyname as it appears in the above procedures and then use a datastep with Call execute to generate one report file for each company. Which could look something like this:

data _null_;
   set companynamelist;
   length tstr $ 200;
   tstr= catt('ODS PDF file="C:\path\',companyname,'.pdf" <other pdf options>;');
   Call execute(tstr);
   call execute("Proc sgplot data=somedata;");
   tstr = catt('where companyname="',companyname,'";');
   call execute(tstr);
   call execute('each of the <plot statements>';
   call execute('run;');
   call execute('Proc print data=someotherdata;');
   tstr = catt('where companyname="',companyname,'";');
   call execute(tstr);
   call execute('each of the <other print statements>';
   call execute('run;');
   call execute('ods pdf close;');
run;

This generates the repeated lines of code for each company. Note that since we are in a data step if some company has additional or fewer procedures needed then the CALL Execute could be executed conditionally within some logic structure. Additional information in the companynamelist dataset might provide text for pretty titles and such as well.

 

View solution in original post


All Replies
Grand Advisor
Posts: 9,748

Re: Is it possible to control which ODS destination gets specific output in a Data step?

I'm moderately sure that FILE PRINT ODS is going to point to the open destinations. It may be that what you want to accomplish could be done by generating all of you output and then use Proc Document to select the bits for sending to specific destinations.

Regular Contributor
Posts: 150

Re: Is it possible to control which ODS destination gets specific output in a Data step?

I'm considering using a document store in this project.  The down side is I have to generate about 20,000 pdf documents each of which has about 27 graphic images in it.  The images could be generated with a call to the appropriate grahics procedure using a BY statement and the output sent to a document store, but that still leaves 20,000 calls to proc document. 

 

I will if I have no other choice but was hoping to avoid that if I can.

 

--Ben

Grand Advisor
Posts: 9,748

Re: Is it possible to control which ODS destination gets specific output in a Data step?

Can you provide a little more description of what you are actually doing? Managing 20,000 outputs plus images makes be think you are doing something other than a data step File Print ODS that the initial question implied.

 

If you are needing to pull a subset of the images to match other procedure output it may be that in this case that By group from the image producing part isn't the way to go but to have something that uses a Where. Then one ODS "sandwich" around output that generates multiple procedures and the graphics may work.

Grand Advisor
Posts: 16,408

Re: Is it possible to control which ODS destination gets specific output in a Data step?

Not sure if this is applicable but what about ODS SELECT/EXCLUDE before relevant Procs? 

 

Regular Contributor
Posts: 150

Re: Is it possible to control which ODS destination gets specific output in a Data step?

Had been reading about the SELECT functionality.  It seems to be the opposite of what I need--you can restrict pulling in different output objects to be selected, but once they are selected they go to all active ODS destinations.

 

I'd like to be able to send all output to a specific destination somehow.

 

--Ben

Grand Advisor
Posts: 16,408

Re: Is it possible to control which ODS destination gets specific output in a Data step?

You should show a sample of your code. What exactly do you mean by File statement for your ODS?

 

You can have multiple ODS open, but you can close them if you're not using them as well.

I can't test it, but I would try something like this:

 

ods pdf file='sample.pdf';
ods html file='sample.html';

proc reg data=sashelp.class;
model weight = height age;
run;quit;

ods html select none;
proc sgplot data=sashelp.class;
scatter x=height y=weight;
run;quit;

ods pdf close;
ods html close;

 

Regular Contributor
Posts: 150

Re: Is it possible to control which ODS destination gets specific output in a Data step?

Say I have the following:

 

ods pdf file='c:\temp\samp1.pdf';

ods pdf file='c:\temp\samp2.pdf';

 

data _null_;

set sashelp.class;

 

file print <....something to point to the first pdf file> ods=(template="mygraphs.template1");

put _ods_;

 

file print <...something to point to the second pdf file> ods=(template="mygraphs.template2");

put _ods_;

run;

ods pdf close;

 

We have available the id= construct on the ods pdf statement but am not sure that can be tied to a specific file print statement.  I found I can dynamically generate an ODS PDF statement via a user defined function that calls a macro which submits the statement, so I can generate them from within a data step.  Trying to close them within that same data step is a different story, but could do that after the data step terminated.

 

The end goal is to generate a 4 page pdf file for about 20,000 companies.  I was hoping to use a Data step to avoid something like calling Proc Document 20,000 times in an ODS sandwich after generating the graphics to a document store.  I wouldn't press my luck by allocating 20000 PDF files in SAS, but probably would do it in batches of 50 or 100 with an ODS PDF close statement in between the DATA steps.

 

--Ben

Solution
‎06-14-2016 11:32 AM
Grand Advisor
Posts: 9,748

Re: Is it possible to control which ODS destination gets specific output in a Data step?

I am still not sure where your images come in. They would not likely be generated by a data _null_ and file print.

Let's take a stab at some ideas. Suppose I have a very simple report that looks something like this (pseudo code to show that I have two procedures output)

Proc sgplot data=somedata;
   where companyname="somename";
   <plot statements>;
run;

Proc print data=someotherdata;
   where companyname="somename";
   <other print options>
run;

And the code above works for my purpose for a single company and I want to replicate for a large list of companies.

 

So I create a dataset that would have the appropriate values of companyname as it appears in the above procedures and then use a datastep with Call execute to generate one report file for each company. Which could look something like this:

data _null_;
   set companynamelist;
   length tstr $ 200;
   tstr= catt('ODS PDF file="C:\path\',companyname,'.pdf" <other pdf options>;');
   Call execute(tstr);
   call execute("Proc sgplot data=somedata;");
   tstr = catt('where companyname="',companyname,'";');
   call execute(tstr);
   call execute('each of the <plot statements>';
   call execute('run;');
   call execute('Proc print data=someotherdata;');
   tstr = catt('where companyname="',companyname,'";');
   call execute(tstr);
   call execute('each of the <other print statements>';
   call execute('run;');
   call execute('ods pdf close;');
run;

This generates the repeated lines of code for each company. Note that since we are in a data step if some company has additional or fewer procedures needed then the CALL Execute could be executed conditionally within some logic structure. Additional information in the companynamelist dataset might provide text for pretty titles and such as well.

 

Regular Contributor
Posts: 150

Re: Is it possible to control which ODS destination gets specific output in a Data step?

The images can be pre-generated in separate procs and put into a document store but that would likely require a Data step object method for retrieving data from a store.  I'm not aware that exists (yet). 

 

Had hoped to use a pre-compiled GTL template to create the graphs from an input file driven by a DATA step, but that sounds like it is not practicle.  Guess I'll have to settle for generating the graphs (by calling the graph procs with a by statement) into a document store and then using the ODS sandwich approach and a call to proc document to construct the final pdf file.  I'm leaning toward this approach as the final output has about 27 graphs per pdf file.  I can either generate code that makes 27 calls to procs for each pdf file for a total of about 540,000 calls, or use a BY statement that stores the output from 27 calls to the procs.  Then use a where clause in a proc document call.

 

Thanks much!

 

--Ben

Grand Advisor
Posts: 9,748

Re: Is it possible to control which ODS destination gets specific output in a Data step?

GTL templates are pretty much only used by Proc SGRender. There is something called Data Step Graphics Interface, I'm not sure if it survived past SAS 9.2 or not, but that uses graphic primatives and I would hate to have to work out something to attempt to mix the graphics output and something else in the same data step.

 

The example I mentioned could replace the SGPlot with SGrender as that was a very generic outline for generating output.

 

Remember the nice things about computers is they do the repetitive work. You could stuff all of the PDF generation into one largish data _null_ with lots of calls to call execute. The example I provided with the one line of proc per Call Execute call was to be very explicit. If you have lots of boilerplate you can put it into large sections with one Call Execute and only have the bits where parameters change.

 

For instance with a Proc Report step that the only change is the Where clause you could likely get by with 3 call executes: the first for the proc statement and options, second for the Where clause and third all of the rest in a single call execute:

call execute ('line of code; second line of code; third line of code; repeat until; run;');

If you intersperse the text or table generating bits with the graphs in the correct order within an ODS sandwich then your report is basically finished.

 

With some ODS text statements and mixing table procs like Tabulate, Print and Report plus some graphs I have completed reports of a 100 or so pages with thirty odd tables intermixed with about 50 graphs.

Post a Question
Discussion Stats
  • 10 replies
  • 556 views
  • 0 likes
  • 3 in conversation