DATA Step, Macro, Functions and more

Sgplot in a do loop

Accepted Solution Solved
Reply
Contributor
Posts: 60
Accepted Solution

Sgplot in a do loop

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;

Accepted Solutions
Solution
‎02-02-2016 08:49 AM
Super User
Super User
Posts: 7,955

Re: Sgplot in a do loop

Posted in reply to chris2377

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/

 

View solution in original post


All Replies
Super User
Posts: 7,782

Re: Sgplot in a do loop

[ Edited ]
Posted in reply to chris2377

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;

 

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Contributor
Posts: 60

Re: Sgplot in a do loop

Posted in reply to KurtBremser

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;
Super User
Posts: 7,782

Re: Sgplot in a do loop

Posted in reply to chris2377

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.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Contributor
Posts: 60

Re: Sgplot in a do loop

Posted in reply to KurtBremser

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

Super User
Posts: 7,782

Re: Sgplot in a do loop

[ Edited ]
Posted in reply to chris2377

The definition of a macro MUST start with a %macro statement, and then you need to invoke the macro by its name.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Solution
‎02-02-2016 08:49 AM
Super User
Super User
Posts: 7,955

Re: Sgplot in a do loop

Posted in reply to chris2377

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/

 

SAS Super FREQ
Posts: 3,753

Re: Sgplot in a do loop

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;
Contributor
Posts: 60

Re: Sgplot in a do loop

@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 Smiley Happy 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.

Super User
Super User
Posts: 7,955

Re: Sgplot in a do loop

Posted in reply to chris2377

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.

☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 9 replies
  • 860 views
  • 0 likes
  • 4 in conversation