I have a macro that produces some special graphs by taking as input names of two variables from the dataset.
Let's say I have two variables in the dataset: Age, Date, LoanBig, LoanSmall. In reality there are many more of these.
I can run the macro as follows:
%dograph(Age,LoanBig), etc
But I want to loop through these variables instead. So I created the array:
data summary;
set summary;
array myarray1(2) Age Date;
array myarray2(2) LoanSmall LoanBig;
*The following does not work. the error says that the variable myarray1 can not be found
%dograph(myarray1(1),LoanSmall);
*The following test works. It creates the variable in the dataset called "temp" that is a copy of the variable Age
temp = myarray1(1)
*Eventually I want to loop through these. But for now it does not even work with actual index.
run;
Just created some sample data to work with here:
data temp;
input var1 var2 var3 ;
datalines;
1 1 1
2 4 8
3 9 27
4 16 64
;
run;
and a simple macro that creates a scatterplot:
%macro graphthis(xaxis,yaxis);
proc sgplot data=temp;
scatter x=&xaxis y=&yaxis;
run;
%mend;
Now, if you can write out your variables in a list, then store them in macro variables
%let xs = var1;
%let ys = var2 var3;
and loop through the macro variables like so:
%macro loopthrough();
%do i=1 %to %sysfunc(countw(&xs));
%do j=1 %to %sysfunc(countw(&ys));
%let x&i = %scan(&xs, &i, %str( ));
%let y&i = %scan(&ys, &j, %str( ));
%graphthis(&&x&i, &&y&i);
%end;
%end;
%mend;
options mprint mlogic symbolgen;
%loopthrough();
We'll need to know a lot more about what your macro dograph is all about. Also, when you mention it doesn't work, what are the messages you get? Some log and code would help.
But assuming it does something like proc sgplot or proc plot than it's not a surprise you get problems. Inside a datastep you cannot run another proc.
But ultimately we'll need code and log to be certain. Please show us what you've done sofar and give us a good idea of what you were expecting / hoping to achieve.
Regards,
- Jan,.
Thank you. Please see my reply below. I am actually able to use this macro from within the data step when passing the variable names directly. I just can not do this when referencing an item in the array. I want to run this macro through a loop, but I do not want to change the macro. It is currently being used by hard calling it with different variable combinations over 40 rimes.
We would need the actual code of the macro to address why it works/does not work.
As well as a description of what the macro is supposed to actually accomplish.
First likely issue: ARRAYS are not permanent objects in a data set. Once the data step completes the array object no longer exists. So you cannot reference an array element in the manner you are attempting.
A typical approach is to pass the list of variables as a single parameter and then parse the list and build code using the name(s) selected from the parameter.
A somewhat less macro driven approach is to use a data step to create call execute statements that generate the code needed.
Regarding the likely issue being that arrays are not permanent object and can not be referred to after the data step completes: I am not using the array outside the datastep. I am only using it within the datastep. Also, within the datastep I can do
temp = myarray1(1);
and I can do
%dograph(Age,LoanSmall);
But I can not do:
%dograph(myarray1(1),LoanSmall);
The macro produces some formatted png image files with standardized naming to be read into the Latex document. Before doing that it also collapses the data by some appropriate averages according to the first argument passed (either Age or Date). There will be many douzens of these image files, and the macro will be called from many different parts of the code. Right now somebody is using this code by copying and pasting hardcoded macro calls with actual variable names about 40 times. "%dograph(Age,LoanSmall), %dograph(Age,LoanLarge), etc. In reality there are many more loan types.
For now, I just want a way of looping through the variables for the first and second argument. below I will put a stripped down version of the macro. As I mentioned, the macro itself works when called like this:
%dograph(Age,LoanSmall);
The short version of the macro. It is possible that this macro can be streamlined and improved. But it is being used successfully in production for a while and does work when calling directly with variable names. I do not want to change the macro - it is not mine. I just want to be able to call it as a loop, the way I can do it in STATA, R, Matlab and many other languages.
%macro dograph(AgeorDate,loantype);
data subset;
set summary;
run;
PROC FORMAT;
VALUE genderval 0="All"
1="Couple"
2="Male"
3="Female";
RUN;
data subset0;
set subset;
if female=1 then gender = 3;
if male = 1 then gender = 2;
if couple = 1 then gender = 1;
FORMAT gender genderval.;
LABEL smm = "SMM";
LABEL loanage = "Loan Age in Months";
run;
data subsets;
set subset0;
gender = 0;
run;
proc datasets;
append base= subsets
data= subset0;
Proc sort data= subsets;
by gender &AgeorDate ;
run;
proc means data= subsets noprint;
var smm fit;
by gender &AgeorDate;
weight _weight_;
output out=lalas;
run;
data lalas;
set lalas;
if _STAT_='MEAN';
run;
goptions reset=index device=png gsfname=graphout;
ods graphics on /
width = 5.25in
outputfmt= png
imagemap = on
reset = index
imagename="IJMy_&AgeorDate"
border=off;
ods listing gpath="/sasmart/zkydmjo/IJGraph";
ods graphics on / width=6.75in height=5.25in;
PROC SGPANEL DATA=lalas;
PANELBY gender /SPACING=3 novarname;
series y=smm x=&AgeorDate /
MARKERS MARKERATTRS = (SYMBOL = CircleFilled COLOR = black SIZE = 5)
LINEATTRS = (COLOR = black PATTERN = SOLID);
series y=fit x=&AgeorDate /
MARKERS MARKERATTRS = (SYMBOL = circle COLOR = green SIZE = 5)
LINEATTRS = (COLOR = green PATTERN = SOLID);
COLAXIS grid;
ROWAXIS grid;
RUN;
ods listing close;
%mend dograph;
When you run a macro the TEXT that it generates is then interpreted by SAS as if the original program contained that text.
So if you have a macro that generates a data or proc step.
%macro dograph;
proc plot .....
%mend ;
And you call that macro in the middle of defining a data step.
data test;
...
%dograph;
...
run;
Once the macro processors finishes its pre-processing what SAS sees is a program that looks like.
data test ;
...
proc plot;
...
...
run;
So the definition of your data step is truncated as soon as you start to try to run another step.
Just created some sample data to work with here:
data temp;
input var1 var2 var3 ;
datalines;
1 1 1
2 4 8
3 9 27
4 16 64
;
run;
and a simple macro that creates a scatterplot:
%macro graphthis(xaxis,yaxis);
proc sgplot data=temp;
scatter x=&xaxis y=&yaxis;
run;
%mend;
Now, if you can write out your variables in a list, then store them in macro variables
%let xs = var1;
%let ys = var2 var3;
and loop through the macro variables like so:
%macro loopthrough();
%do i=1 %to %sysfunc(countw(&xs));
%do j=1 %to %sysfunc(countw(&ys));
%let x&i = %scan(&xs, &i, %str( ));
%let y&i = %scan(&ys, &j, %str( ));
%graphthis(&&x&i, &&y&i);
%end;
%end;
%mend;
options mprint mlogic symbolgen;
%loopthrough();
Thank you! This indeed accomplished what I was trying to do!
Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.
Register today!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.
Select SAS Training centers are offering in-person courses. View upcoming courses for: