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

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

1 ACCEPTED SOLUTION

Accepted Solutions
ballardw
Super User

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

10 REPLIES 10
ballardw
Super User

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.

BenConner
Pyrite | Level 9

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

ballardw
Super User

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.

Reeza
Super User

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

 

BenConner
Pyrite | Level 9

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

Reeza
Super User

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;

 

BenConner
Pyrite | Level 9

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

ballardw
Super User

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.

 

BenConner
Pyrite | Level 9

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

ballardw
Super User

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.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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.

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