DATA Step, Macro, Functions and more

question about call symput?

Reply
Contributor
Posts: 49

question about call symput?

Hi,

Please see the below for my data:
data temp;
input ID $ score section;
datalines;
1 90 1
1 89 1
1 92 1
1 70 2
1 65 2
1 80 2
1 88 3
1 70 3
1 75 3
2 95 1
2 88 1
2 93 1
2 87 2
2 83 2
2 70 2
***more data;
;
run;

I want to get the plot of score by section for each ID, that is,one page for each ID, and draw a line to label the mean. I have many many IDs so I used a macro to do it. Here is my code:

%macro test(id);

data temp2;
set temp;
if ID="&id";
run;

PROC MEANS DATA=temp2 NOPRINT N MEAN STD;
VAR score;
CLASS section;
OUTPUT OUT=summary N=TOT MEAN=mean_score STD=std_score;
RUN;

data summary2;
set summary;
if section='' then delete;
run;

proc sort data=summary2;
by section;
run;

DATA _NULL_;
SET summary2;
CALL SYMPUT('a'!!TRIM(LEFT(_N_)),mean_score);
RUN;

/* use annotation to draw a line representing mean*/
DATA anno_data;
%SYSTEM(2,2);
%ANNOMAC;
%LINE(0.7,&a1,1.3,&a1,BLACK,1,4);
%LINE(1.7,&a2,2.3,&a2,BLACK,1,4);
%LINE(2.7,&a3,3.3,&a3,BLACK,1,4);
RUN;

AXIS1 ORDER=(0 TO 4 BY 1);
PROC GPLOT DATA=temp2 ANNO=anno_data;
PLOT score*section / haxis=axis1;
RUN;
QUIT;

%mend;

%test(1);
%test(2);

The first plot (ID=1) is correct. For ID=2, the data doesn't have section 3, but sas still draw a line at y=77.6, this is the mean for a3 when ID=1, so it seemed it passed the value of last run. Does anyone know how to solve this problem? Thanks in advance.

Lu
Super Contributor
Posts: 281

Re: question about call symput?

Posted in reply to lueryy2000
This usually indicates there is no data for section 3 and ID=2.

In that case, the value of &a3 retains its value that it had when ID=1.

Your code doesn't seem to need macros here, it can all by done using BY Variables, if I am not mistaken. I have not tested this code:

PROC MEANS DATA=temp(where=(section^=' ')) NOPRINT N MEAN STD;
VAR score;
CLASS ID section;
OUTPUT OUT=summary N=TOT MEAN=mean_score STD=std_score;
RUN;

%ANNOMAC
DATA anno_data;
set summary;
%SYSTEM(2,2)
if section=1 then do; %LINE(0.7,mean_score,1.3,mean_score,BLACK,1,4); end;
if section=2 then do; %LINE(1.7,mean_score,2.3,mean_score,BLACK,1,4); end;
if section=3 then do; %LINE(2.7,mean_score,3.3,mean_score,BLACK,1,4); end;
RUN;

AXIS1 ORDER=(0 TO 4 BY 1);
PROC GPLOT DATA=temp;
by id;
PLOT score*section / haxis=axis1 ANNO=anno_data;
RUN;
QUIT; Message was edited by: Paige
Contributor
Posts: 49

Re: question about call symput?

Thank you. The problem is I have a lot of IDs and later on I will use ods pdf to send the output to seperate files, one for each ID. If I use by statement, the plots for every IDs are in different pages but one file. So I have to use macro to repeat the process. Do you have any suggestion how to use macro to solve this problem? I appreciate your help.
Lu
SAS Super FREQ
Posts: 8,868

Re: question about call symput?

Posted in reply to lueryy2000
Hi:
Aside from any macro issues, you can use NEWFILE=BYGROUP to send each graph to a separate PDF output file:
[pre]
proc sort data=sashelp.class out=class;
by sex age;
run;

ods pdf file='c:\temp\graf1.pdf'
newfile=bygroup;

proc gchart data=class;
by sex;
vbar age;
run;
quit;
ods pdf close;
[/pre]

That still means you will need to make a more "intelligent" macro program if you are going to dynamically generate the reference lines. Either clear out &a!, &a2 and &a3 before each invocation of the macro program or generate a unique set of macro variables for every invocation -- so there is no collision. A simple null %LET statement or a %SYMDEL statement should work for you. If you deleted &a1, &a2 and &a3 before every invocation of the macro program, then the check for existence would work as explained...because, if your logic is correct, you would only create the reference numbers you needed with every invocation.

cynthia
Contributor
Posts: 49

Re: question about call symput?

Posted in reply to Cynthia_sas
Thank you for your suggestion. Actually I figured another way to use macro, initially I created another dataset that a1, a2 and a3 are all negative (eg, -1), then I merged with summary2, so if summary2 doesn't have a3, a3 is still -1. However, sas will draw the reference line (the mean) for a1, a2 but not for a3, cause all score values are positive so y axis is above 0. So the line for a3 couldn't be drawn.

My way looks a bit awkward but it worked. I also know other ways from your replied.

Again, thanks everyone who responded to my post.

Lu
Super Contributor
Super Contributor
Posts: 365

Re: question about call symput?

Posted in reply to lueryy2000
Hello Lueryy200,

Some optimizing notes about your code.
1. You do not need "data summary2..." if you simply put nway option in proc means like this:

PROC MEANS DATA=temp2 NOPRINT N MEAN STD nway;

2. Using CLASS in proc means automaticaly sorts output by class variable so you also do not need proc sort.

Sincerely,
SPR
Regular Contributor
Posts: 241

Re: question about call symput?

Posted in reply to lueryy2000
...
> so it
> seemed it passed the value of last run. Does anyone
> know how to solve this problem? Thanks in advance.

The reason for this is that when ID=2, the data step anno_data fails to compile and thus not replaced. The following steps end up using the old anno_data.

The reason why it fails is because the macro reference &a3 is not resolved, because the macro variable a3 does not exist at the time. This will force macro processor to return a string, "&a3" and the %line macro tries to assign this to a numeric variable Y, resulting in a compiler error.

A quick fix is to check before calling %line macro like below. You can also check the number of a# vars in the data _null_ step above. Hope this helps a bit.
[pre]
OLD> %LINE(2.7,&a3,3.3,&a3,BLACK,1,4);
NEW> %if %symexist(a3) %then %LINE(2.7,&a3,3.3,&a3,BLACK,1,4);
[/pre]
Contributor
Posts: 49

Re: question about call symput?

Posted in reply to chang_y_chung_hotmail_com
Thank you very much for your replying. I tried the way you suggested and I still got a line at y=77.6 for ID=2. When I call %test(1), I used %put &a1 &a2 &a3 to check, sas log gave: 90.3 71.66 77.66. Then I call %test(2), sas gave: 92 80 77.66, so apparently a3 exists but just has been passed the mean of a3 from ID=1. Any other suggestions to solve this problem? Thank you!
Lu
Ask a Question
Discussion stats
  • 7 replies
  • 162 views
  • 0 likes
  • 5 in conversation