It's a basic question but I sometimes get completely lost with loops in SAS. I am trying to use the code below to get separate bar graphs for yeach year between 1949 and 1955, but I get an error. What am I doing wrong?
data test;
set sashelp.air;
year=year(date);
month=month(date);
run;
options mprint mlogic;
%print;
%do i=1949 to 1955 by 1;
ods pdf file = 'c:\year_&i.pdf'
proc sgplot data=test (where=(year=&i));
vbar month/response=air;
title &i;
run;
ods pdf close;
%end;
%mend;
Why do you need 1 file per graph out of interest? As for your code:
data _null_; do i=1949 to 1955; call execute(cats('ods pdf file="c:\year_',put(i,4.),'.pdf";));
call execute(cats('title "',put(i,4.),'";')); call execute(cats('proc sgplot data=test (where=(year=',put(i,4.),')); vbar month/response=air; run;')); call execute('ods pdf close;'); end; run;
However there are two other methods to get what you want. Firstly, and the one I would generally use, is to not output to a new file each time. In most cases there is no need to, then you can just use by group processing, which is quicker, and simpler coding:
ods pdf file="c:\all.pdf"; proc sgplot data=test; by year; title "#byvar1"; vbar month/response=air; run; ods pdf close;
Far simpler. You could also do it in Graph Template Language, dynamic variables/conditional templates - which for this example might be a bit overkill, but it is well worth learning for more complicated graphs, good help is here: http://blogs.sas.com/content/graphicallyspeaking/
You enclosed the filename in single quotes, suppressing resolution of the macro variable &i.
Edit: this was just the first problem.
In the %do, you must also use %to and %by, instead of "to 1955 by 1". And the "%by 1" can be omitted, as this is the default.
%macro print;
%do i=1949 %to 1955;
ods pdf file = "c:\year_&i.pdf";
proc sgplot data=test (where=(year=&i));
vbar month/response=air;
title &i;
run;
ods pdf close;
%end;
%mend;
%print;
But the code doesn't wor even if I get rid of ods pdf statement at all
options mprint mlogic;
%print;
%do i=1949 to 1955 by 1;
proc sgplot data=test (where=(year=&i));
vbar month/response=air;
title &i;
run;
%end;
%mend;
Take another look at my code now, had to do some edits. I also couldn't test it, as I don't have SASHELP.AIR.
If further problems persist, please post the log.
Sorry, I thought sashelp files are available to every sas user. Below is the code with a sample dataset and the log message
data test;
input year month air;
datalines;
1949 1 100
1949 2 150
1949 3 200
1950 1 200
1950 2 250
1950 3 300
1951 1 600
1951 2 150
1951 3 800
;
run;
options mprint mlogic;
%print;
%do i=1949 %to 1951;
proc sgplot data=test (where=(year=&i));
vbar month/response=air;
title &i;
run;
%end;
%mend;
And the log is:
15 data test;
16 input year month air;
17 datalines;
NOTE: The data set WORK.TEST has 9 observations and 3 variables.
NOTE: DATA statement used (Total process time):
real time 0.02 seconds
cpu time 0.03 seconds
27 ;
28 run;
29
30 options mprint mlogic;
31 %print;
-
180
WARNING: Apparent invocation of macro PRINT not resolved.
ERROR 180-322: Statement is not valid or it is used out of proper order.
ERROR: The %DO statement is not valid in open code.
32 %do i=1949 %to 1951;
33
34 proc sgplot data=test (where=(year=&i));
-
22
76
ERROR 22-322: Syntax error, expecting one of the following: nazwa, łańcuch w nawiasach,
stała numeryczna, stała daty i godziny, brak danych, INPUT, PUT.
ERROR 76-322: Syntax error, statement will be ignored.
-
79
ERROR 79-322: Expecting a ).
34 ! proc sgplot data=test (where=(year=&i));
-
22
WARNING: Apparent symbolic reference I not resolved.
ERROR: Błąd składniowy w warunku WHERE. <- it says "Syntax error in WHERE clause"
34 proc sgplot data=test (where=(year=&i));
-
180
ERROR 22-322: Missing ')' parenthesis for data set option list
ERROR 180-322: Statement is not valid or it is used out of proper order.
35 vbar month/response=air;
36 title &i;
WARNING: Apparent symbolic reference I not resolved.
37 run;
38
39 %end;
ERROR: The %END statement is not valid in open code.
40 %mend;
ERROR: No matching %MACRO statement for this %MEND statement.
NOTE: The SAS System stopped processing this step because of errors.
NOTE: PROCEDURE SGPLOT used (Total process time):
real time 1:41.68
cpu time 0.93 seconds
The definition of a macro MUST start with a %macro statement, and then you need to invoke the macro by its name.
Why do you need 1 file per graph out of interest? As for your code:
data _null_; do i=1949 to 1955; call execute(cats('ods pdf file="c:\year_',put(i,4.),'.pdf";));
call execute(cats('title "',put(i,4.),'";')); call execute(cats('proc sgplot data=test (where=(year=',put(i,4.),')); vbar month/response=air; run;')); call execute('ods pdf close;'); end; run;
However there are two other methods to get what you want. Firstly, and the one I would generally use, is to not output to a new file each time. In most cases there is no need to, then you can just use by group processing, which is quicker, and simpler coding:
ods pdf file="c:\all.pdf"; proc sgplot data=test; by year; title "#byvar1"; vbar month/response=air; run; ods pdf close;
Far simpler. You could also do it in Graph Template Language, dynamic variables/conditional templates - which for this example might be a bit overkill, but it is well worth learning for more complicated graphs, good help is here: http://blogs.sas.com/content/graphicallyspeaking/
Since each plot is a bar chart, I recommend that you use the SGPANEL procedure, which will create all charts in a single panel and automatically add the category to each plot:
proc sgpanel data=test;
panelby year / columns=1;
vbar month/response=air;
run;
@RW9 Thanks for the code. I'll try it. I know GTL (at least I've heard of it, not that I have great experience in this area) but I agree that for this example might be a bit overkill - I would rather do it manually 🙂 I looked at your code and I see that you used the put function. So the problem is that SAS does not treat subsequent values of i as numbers but as text? So it tries to run the code like:
proc sgplot data=test (where=(year="1949"))
while year is numeric and this causes a problem. Am I right?
@RW9 @Rick_SAS
I know sgpanel but it is not suitable. I need a separate graph for each value of i. I just used the sashelp.air as the example. In real case it's not a graph for separate year but for separate client ID. I don't want them to be all mixed up in one file.
With regards to your question on put to text, yes this is correct. Call execute() is a function which takes a string, and puts it directly into the compiler after the finish of the current datastep. So what I do within the brackets is to create a string, the put just creates a string of the four numbers. So the final string given to the call execute is:
proc sgplot data=test (where=(year=1949))
Now when the compiler compiles this text, it still sees the number 1949 as it would from normal code.
Don't miss out on SAS Innovate - Register now for the FREE Livestream!
Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.
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.