BookmarkSubscribeRSS Feed
BenConner
Pyrite | Level 9

Hi,

Am trying to generate multiple successive images with a graph template and Data step calling it.  Only the last one is showing up. 

 

What am I missing?

 

Thanks!

 

-Ben

 

test code:
data pcts;                                                                                                                             
input prov pct1 zip1;                                                                                                                  
cards;                                                                                                                                 
1 53 43058                                                                                                                             
2 47 43022                                                                                                                             
3 75 43235                                                                                                                             
4 41 43216                                                                                                                             
;;;                                                                                                                                    
                                                                                                                                       
ods path(prepend) work.templat(update);                                                                                                
                                                                                                                                       
    proc template;                                                                                                                     
        define statgraph Pies;                                                                                                         
            mvar PROV PCT1 ZIP1;                                                                                                       
            begingraph / designheight = 2.4in designwidth = 1.5in;                                                                     
                entrytitle '';                                                                                                         
                layout overlay / opaque = false;                                                                                       
                                                                                                                                       
                drawtext textattrs = (size = 7pt ) "Your (" PROV ") stats" /                                                           
                                       width = 80 x = 20 y = 100 ;                                                                     
                                                                                                                                       
                drawtext textattrs = (size = 7pt family = "Arial" ) PCT1 "% of your sales are in "                                     
                         textattrs = (size = 7.5pt family = "Arial" ) ZIP1 / width = 80 x = 20 y = 81 anchor = left justify = left ;   
                                                                                                                                       
                endlayout;                                                                                                             
            endgraph;                                                                                                                  
        end;                                                                                                                           
    run;                                                                                                                               
                                                                                                                                       
ods _all_ close;                                                                                                                       
ods html;                                                                                                                              
options papersize=(1.5in 2.4in);                                                                                                       
                                                                                                                                       
data _null_;                                                                                                                           
   set pcts;                                                                                                                           
                                                                                                                                       
   call symputx('prov',prov); call symputx('pct1',pct1); call symputx('zip1',zip1);                                                    
                                                                                                                                       
   file print ods=(template="pies");                                                                                                   
                                                                                                                                       
   put _ods_;                                                                                                                          
run;                                                                                                                                   
ods html close;                                                                                                                        

 

11 REPLIES 11
ChrisNZ
Tourmaline | Level 20

You have to think that all the call symputs get executed after the data step. So the latest one overwrites the others and only it remains.

 

One way to do what you want is to execute the macro variable initialisations and call a data step for each observation.

 

 

ods _all_ close;
ods html;   
options papersize=(1.5in 2.4in);
data _null_;
   set pcts;
   call execute(cats('%nrstr(%let prov=',PROV,';%let pct1=',PCT1,';%let zip1=',ZIP1,';)'));
   call execute('data _null_; set pcts(obs=1); file print ods=(template="pies"); put _ods_; run;');
run;        
ods html close;

BenConner
Pyrite | Level 9
Hi Chris, From what you're saying, the template execution doesn't occur until the end of the data step? That seems odd. If I had a template where I need a graph generated for each observation, that doesn't seem particularly useful. Not doubting you, just puzzled why it would have been coded that way. --Ben
ChrisNZ
Tourmaline | Level 20

I am only saying the macro variable values don't occur until the end of the data step. And therefore since you need to call the template after the macro variables have a new value, you need to call it in a subsequent data step.

That's what the code I provided does, and it should suit your needs. Hopefully 🙂

BenConner
Pyrite | Level 9

Hi Chris,

 

I haven't found that to be the case regarding macro variables.  Consider the following:

 

633  %let r='no value';

634  data _null_;

635  i="&r";

636   put i=;

637  call symputx('r','some value');

638  t=symget('r');

639  put t=;

640  run;

 

i='no value'

t=some value

 

At data step compilation time, the variable i gets assigned  'no value' from macro variable r in the global macro pool.  During data step execution, the symputx updates r with the value of 'some value', and is verified when the variable t gets assigned the current value of the macro variable.  Or were you referring to something else?

 

--Ben

ChrisNZ
Tourmaline | Level 20

Yes you can retrieve the values before hand. But the uses for this are limited. They only concern operations taking place at run time.

 

That's why I said that you have to think that it all happens at the end. It doesn't really, but that's the apparent behaviour for usual processes, and for all intents and purposes, that's the way it is commonly used.

The documentations states it better than I can:

 

One of the most common problems in using SYMPUT is trying to reference a macro variable value assigned by SYMPUT before that variable is created. The failure generally occurs because the statement referencing the macro variable compiles before execution of the CALL SYMPUT statement that assigns the variable's value. The most important fact to remember in using SYMPUT is that it assigns the value of the macro variable during program execution. Macro variable references resolve during the compilation of a step, a global statement used outside a step, or an SCL program. As a result:

  • You cannot use a macro variable reference to retrieve the value of a macro variable in the same program (or step) in which SYMPUT creates that macro variable and assigns it a value.
  • must You must specify a step boundary statement to force the DATA step to execute before referencing a value in a global statement following the program (for example, a TITLE statement). The boundary could be a RUN statement or another DATA or PROC statement.

I am unsure how this is organised in the case of proc template being called from a data step. What is certain though is that most cases of call symput() not yielding the "expected" result are due to macro variables being used too early and the program not having step boundaries between calls. Adding boundaries did resolve your issue.

 

There may be another way to make this work, but my proposal is a common solution to a common problem. If someone with more knowledge about ODS template behaviour can shed light...

BenConner
Pyrite | Level 9
Hi Chris, Yes, am reasonably familiar with macro variable limitations and pitfalls. If the object oriented methods initialized it at the start of the data step, that would make sense. This was at the other end, and sadly the docs aren't very clear on this issue. Will open a track with T.S. Thanks! --Ben
ChrisNZ
Tourmaline | Level 20

Please keep this page updated if you can shed more light.

BenConner
Pyrite | Level 9

Got a definitive answer from SAS T.S.  The behavior is something I hadn't considered:

 

The data step is in fact writing each template out for each observation in the input file.  What I hadn't considered is it overlays the previous output on the same page(!).  So data from the last observation is what remains in the final document.

 

I find this behavior far less useful than I had hoped, to the point it is (IMO) nearly worthless.  But at least I finally know what is happening.

 

Thanks for your help!  Much appreciated.

 

--Ben

ChrisNZ
Tourmaline | Level 20

Any way to give the images a different name for each iteration?  there is just one image atm called img0.png

 

BenConner
Pyrite | Level 9

I don't know of any direct way to influence that; in this instance the real intended destination is a PDF file anyway.  Same behavior though--it overwrote the first page.  At least it is consistent.

 

--Ben

ChrisNZ
Tourmaline | Level 20

If the images are really overwriting each other, then

1- they shoud all be written to the pdf, but at the same position (i didn't see this in the html, only one image)

2- maybe each image can be written at a different location on the page? (ods layout)?

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
  • 11 replies
  • 1496 views
  • 0 likes
  • 2 in conversation