I need to create a multiple figures for each parent cell/child target combination. So I need CD4+/polyfunctional, CD4+CD69+/polyfunctional, CD4+CD69+/IFNg+, CD4+CD69+/IL2+, CD4+CD69+/TNFa+, and repeated with CD8+ parent cell (what's before the /), and so on. There's a lot of cells to get through, so I'd rather not write out one long list. The following code gives me the error:
ERROR: There were 2 unclosed %DO statements. The macro RPTOUT will not be compiled.
ERROR: A dummy macro will be compiled.
All my %DO statements have an %END statement and I tested the macro outside of the loop and it performed just fine. So I am unsure why I am getting these errors. Is there a better way to do this?
%macro rptout();
%let ctype= %str(4Y, 469Y, 4698, 4699, 4690, 8Y, 869Y, 8698, 8699, 8690);
%let parent= %str(CD4+ T-Cells, CD4+ CD69+ T-Cells, CD4+ CD69+ T-Cells, CD4+ CD69+ T-Cells, CD4+ CD69+ T-Cells, CD8+ T-Cells, CD8+ CD69+ T-Cells, CD8+ CD69+ T-Cells, CD8+ CD69+ T-Cells, CD8+ CD69+ T-Cells);
%let child= %str(IFN-^{unicode gamma}, IL-2, and TNF-^{unicode alpha}*IFN-^{unicode gamma}, IL-2, and TNF-^{unicode alpha}*IFN-^{unicode gamma}*IL-2*TNF-^{unicode alpha});
%let file= %str(poly, poly, IFNg, IL2, TNFa);
%do A= 1 %to %sysfunc(CountW(&CTYPE));
%do B= 1 %to %sysfunc(CountW(&CHILD));
%let W= %scan(&CTYPE, &A, ',');
%let X= %scan(&PARENT, &A, ',');
%let Y= %scan(&CHILD, &B, '*');
%let Z= %scan(&FILE, &B, ',');
%macro rpt( ctype= &W, /*Target Cell Type*/
parent= &X, /*Parent Gate*/
child= %str(&Y),/*Child Gate*/
filename= &Z /*File Name*/
);
%end;
%end;
%mend rptout;
Show your log. Since this involves macro coding then set OPTIONS MPRINT before running the code.
Look up the function COUNTW for default delimiters. You aren't building matching lists because your Countw is using the default list of delimiters which include SPACE.
Note that if what you have run is the code you pasted you likely have a lot of problems and likely need to restart SAS to clear out stacked junk in the macro processor.
%macro rptout(); %let ctype= %str(4Y, 469Y, 4698, 4699, 4690, 8Y, 869Y, 8698, 8699, 8690); %let parent= %str(CD4+ T-Cells, CD4+ CD69+ T-Cells, CD4+ CD69+ T-Cells, CD4+ CD69+ T-Cells, CD4+ CD69+ T-Cells, CD8+ T-Cells, CD8+ CD69+ T-Cells, CD8+ CD69+ T-Cells, CD8+ CD69+ T-Cells, CD8+ CD69+ T-Cells); %let child= %str(IFN-^{unicode gamma}, IL-2, and TNF-^{unicode alpha}*IFN-^{unicode gamma}, IL-2, and TNF-^{unicode alpha}*IFN-^{unicode gamma}*IL-2*TNF-^{unicode alpha}); %let file= %str(poly, poly, IFNg, IL2, TNFa); %do A= 1 %to %sysfunc(CountW(&CTYPE)); %do B= 1 %to %sysfunc(CountW(&CHILD)); %let W= %scan(&CTYPE, &A, ','); %let X= %scan(&PARENT, &A, ','); %let Y= %scan(&CHILD, &B, '*'); %let Z= %scan(&FILE, &B, ','); /* the next line starts the DEFINITION of a new macro*/ %macro rpt( ctype= &W, /*Target Cell Type*/ parent= &X, /*Parent Gate*/ child= %str(&Y),/*Child Gate*/ filename= &Z /*File Name*/ ); %end; %end; %mend rptout; /* this MEND actually would go with the Macro RPT definition and you have no actual Mend for Rptout*/
Suggestion: do not call that other macro until you have working combinations of the parameters. Use %put statement(s) to show those.
If is very difficult to get Macro definitions defined in macros. If you did not intend to redefine your macro RPT (which seems likely as there really isn't any apparent code to do so) then do not include %macro to call rpt, that would be %rpt and assumes the macro rpt is defined at the time this one executes.
Thank you. I corrected some mistakes and updated my code. Note, the macro %RPT was defined previously.
My main issue now is that the macro is getting confused by the commas in the CHILD variable. I tried adding %STR(), as it seemed to help when I ran the %RPT macro by itself, but it doesn't seem to be working within the %RPTOUT loop.
%macro rptout();
%let ctype= %str(4Y, 469Y, 4698, 4699, 4690, 8Y, 869Y, 8698, 8699, 8690);
%let parent= %str(CD4+ T-Cells, CD4+ CD69+ T-Cells, CD4+ CD69+ T-Cells, CD4+ CD69+ T-Cells, CD4+ CD69+ T-Cells, CD8+ T-Cells, CD8+ CD69+ T-Cells, CD8+ CD69+ T-Cells, CD8+ CD69+ T-Cells, CD8+ CD69+ T-Cells);
%let child= %str(%str(IFN-^{unicode gamma}, IL-2, and TNF-^{unicode alpha})*%str(IFN-^{unicode gamma}, IL-2, and TNF-^{unicode alpha})*IFN-^{unicode gamma}*IL-2*TNF-^{unicode alpha});
%let file= %str(cd4_poly, cd4_cd69_poly, cd4_cd69_IFNg, cd4_cd69_IL2, cd4_cd69_TNFa, cd8_poly, cd8_cd69_poly, cd8_cd69_IFNg, cd8_cd69_IL2, cd8_cd69_TNFa);
%do A= 1 %to %sysfunc(CountW(&CTYPE));
%do B= 1 %to %sysfunc(CountW(&CHILD, '*'));
%let W= %scan(&CTYPE, &A, ',');
%let X= %scan(&PARENT, &A, ',');
%let Y= %scan(&CHILD, &B, '*');
%let Z= %scan(&FILE, &A, ',');
%rpt(ctype= &W, /*Target Cell Type*/
parent= &X, /*Parent Gate*/
child= %str(&Y), /*Child Gate*/
filename= &Z /*File Name*/
);
%end;
%end;
%mend rptout;
%rptout;
Use %QSCAN() instead of %SCAN() and the result will be macro quoted. You also probably did not intend to include the single quote characrter as one of the possible delimiter characters. Just use the * character as the delimiter list.
%let Y= %qscan(&CHILD, &B, *);
It is much better to not use comma as the delimiter in macro code. Then you will not have trouble passing the macro variable values into macro calls (or macro function calls).
Updated to %QSCAN() and updated delimiters, but nothing is outputting.
379 %macro rptout();
380 %let ctype= %str(4Y*469Y*4698*4699*4690*8Y*869Y*8698*8699*8690);
381 %let parent= %str(CD4+ T-Cells*CD4+ CD69+ T-Cells*CD4+ CD69+ T-Cells*CD4+ CD69+ T-Cells*CD4+ CD69+ T-Cells*CD8+ T-Cells*CD8+ CD69+ T-Cells*CD8+ CD69+ T-Cells*CD8+ CD69+
381! T-Cells*CD8+ CD69+ T-Cells);
382 %let child= %str(IFN-^{unicode gamma}, IL-2, and TNF-^{unicode alpha}*IFN-^{unicode gamma}, IL-2, and TNF-^{unicode alpha}*IFN-^{unicode gamma}*IL-2*TNF-^{unicode alpha});
383 %let file= %str(cd4_poly*cd4_cd69_poly*cd4_cd69_IFNg*cd4_cd69_IL2*cd4_cd69_TNFa*cd8_poly*cd8_cd69_poly*cd8_cd69_IFNg*cd8_cd69_IL2*Scd8_cd69_TNFa);
384
385 %do A= 1 %to %sysfunc(CountW(&CTYPE, '*'));
386 %do B= 1 %to %sysfunc(CountW(&CHILD, '*'));
387 %let W= %scan(&CTYPE, &A, '*');
388 %let X= %scan(&PARENT, &A, '*');
389 %let Y= %scan(&CHILD, &B, '*');
390 *%let Y= %qscan(&CHILD, &B, *);
391 %let Z= %scan(&FILE, &A, '*');
392 %rpt(ctype= &W, /*Target Cell Type*/
393 parent= &X, /*Parent Gate*/
394 child= &Y, /*Child Gate*/
395 filename= &Z /*File Name*/
396 );
397 %end;
398 %end;
399 %mend rptout;
400 %rptout;
MPRINT(RPTOUT): * %rpt(ctype= &W, parent= &X, child= &Y, filename= &Z );
MPRINT(RPTOUT): * %rpt(ctype= &W, parent= &X, child= &Y, filename= &Z );
MPRINT(RPTOUT): * %rpt(ctype= &W, parent= &X, child= &Y, filename= &Z );
<repeated>
Note, same thing happens whether using %SCAN or &QSCAN now.
Why did you generate SAS comment statements?
MPRINT(RPTOUT): * %rpt(ctype= &W, parent= &X, child= &Y, filename= &Z ); MPRINT(RPTOUT): * %rpt(ctype= &W, parent= &X, child= &Y, filename= &Z ); MPRINT(RPTOUT): * %rpt(ctype= &W, parent= &X, child= &Y, filename= &Z );
Note that trying to call a macro in the middle of a comment statement will have issues, depending on what code the macro generates. If the %RPT() macro generates more than one statement then the first statement will become part of the comment statement. So if %RPT() is defined like this:
%macro rpt(ctype,parent,child,filename);
data x;
set y;
run;
%mend;
And you call it like this:
* %rpt(ctype= &W, parent= &X, child= &Y, filename= &Z );
Then you end up with this SAS code:
* data x;
set y;
run;
;
Which is probably not what you wanted.
We need to see how the macro %RPT() uses those values to see whether commas in the values passed to it will cause trouble.
From the SAS log it looks like %RPT() did not actually run. You might need to start a new SAS session because you might have generated a number of unbalanced quotes and parentheses that are causing SAS to not actually run the macro call.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.
Ready to level-up your skills? Choose your own adventure.