BookmarkSubscribeRSS Feed
joachimg
Obsidian | Level 7

Hello, I have been using the macro in Customized Flowcharts Using SAS® Annotation by Abhinav Srivastva to make the process of creating a sample size flowchart easier for my research group. https://www.lexjansen.com/wuss/2016/18_Final_Paper_PDF.pdf The provided macro code allows for 4 tiers in the flowchart, with each tier having three elements. We often have more than 4 exclusion criteria steps, so I'd like to edit this so more tiers are possible. Problem is, I've never used annotate before and my macro knowledge is somewhat limited! Here is the macro code, and I've made red the lines that I think should be edited, but haven't worked when I've tried them - I get an error message that says "a percentage point value lies outside 0 to 100 boundaries." If I can provide any more information, please let me know! Thanks. 

/*==========================================================================*
* MACRO USAGE:
* DSN = Input dataset
* FLOOR = List each element and its links separated by '#' delimiter
*==========================================================================*/
/* Input Dataset */
data example;
 length txt $100;
 var='var1'; txt='IC Signed*(N=100)' ; output;
 var='var2'; txt='Rand. Set*(N=90)' ; output;
 var='var3'; txt='FAS Set*(N=90)' ; output;
 var='var4'; txt='Completed*(N=80)' ; output;
 var='var5'; txt='Terminated*(N=10)' ; output;
run;
/* Invoke annotation macros */
%annomac;
%macro flowchart(dsn= , floor= );
/* Process the parameters passed in 'floor= ' argument */
%let counter=1;
%do %while (%scan(&floor,&counter.,%str(#)) ne %str( ));
 %let zz = %scan(&floor.,&counter.,%str(#));
%let element = 1; * identify elements ;
%let n = 1; * identify links ;
 %do %while (%scan(&zz.,&n.,%str( )) ne %str( ));
 %let ELMT = %scan(&zz.,&element.,%str( )); * element ;
 %let LINK = %scan(&zz.,%eval(&n.+1),%str( )); * link ;
 data _null_;
 call execute('data test;');
 call execute('length ELEMENT LINK $10 ;');
 call execute('ELEMENT='||"'"||"&ELMT."||"'"||';');
 call execute('LINK='||"'"||"&LINK."||"'"||';');
 call execute('run;');
 call execute('proc append base=all data=test; run;');
 run;
 %let n = %eval(&n.+1);
 %end;
%let counter = %eval(&counter.+1);
%end;
data all2 (drop = element);
 set all;
 ID=scan(ELEMENT,1,'>');
 if ELEMENT ne ' ' and LINK eq ' ' then do;
 VAR=scan(ELEMENT,2,'>');
 LINK='00';
 end;
run;
/* Merge with input dataset */
proc sql noprint;
 create table all_dsn as
 select a.*, b.txt
 from all2 a
 left join &dsn. b
 on a.var=b.var
 order by ID, LINK
 ;
quit;
/*------------------------------------------------------------------------------*/
/*----------------- STEP 1: Create Universal Flowchart Template ----------------*/
/*------------------------------------------------------------------------------*/
* Standard Bar dimensions ;
%let b_x1= 0;
%let b_x2= 20;
%let b_y1= 95;
%let b_y2= 80;
/* Annotation dataset */
data anno;
 length style id link $10;
 %do j=1 %to 4; * 4 tiers or floors ;
 %do i=1 %to 3; * 3 elements per tier ;
 ID="&j.&i."; LINK='00';
 when='a'; * Bars will be drawn at the end of annotation ;
 %system(3,3); * absolute scale will be used for drawing bars ;
 %bar(&b_x1.,&b_y1.,&b_x2.,&b_y2.,black,0,e);
 when='b'; * other annotation pieces will be drawn before bars;
 LINK="&j.&i.>%eval(&j.+1)&i.";
 %system(9,9); * relative scale will be used for drawing arrows ;
 %arrow(-10,0,0,-10,black,1,1,90,filled);
if &i. ^= 1 then do;
 LINK="&j.&i.>%eval(&j.+1)%eval(&i.-1)";
 %system(9,9);
 %arrow(0,+10,-27,-10,black,1,1,90,filled);
LINK="&j.&i.>&j.%eval(&i.-1)";
 %system(9,9);
 %arrow(+17,+18,-10,0,black,1,1,90,filled);
LINK="&j.&i.>%eval(&j.+1)%eval(&i.+1)";
 %system(9,9);
 %arrow(+20,-8,+27,-10,black,1,1,90,filled);
end;
else do;
LINK="&j.&i.>%eval(&j.+1)%eval(&i.+1)";
 %system(9,9);
 %arrow(0,+10,+27,-10,black,1,1,90,filled);
end;
 LINK="&j.&i.>&j.%eval(&i.+1)";
 %system(9,9);
 %arrow(-17,+17,+10,0,black,1,1,90,filled);
 /* Text annotation */
LINK='00'; TROW='1';
 %cntl2txt;
 %LABEL(-20,+2,' ', black, 0, 0, 1, 'Arial', 5); * Will be used to display text
 line #1 ;
 TROW='2';
 %system(3,9);
 %LABEL(%eval(&b_x1.+10),-2,' ', black, 0, 0, 1, 'Arial', 5); * Will be used
 to display text line #2 ;
 %txt2cntl;
 TROW = ' ';
 %let b_x1 = %eval(&b_x1. + 30);
 %let b_x2 = %eval(&b_x2. + 30);
 %end;
 %let b_x1= 0;
 %let b_x2= 20;
 %let b_y1 = %eval(&b_y1-25);
 %let b_y2 = %eval(&b_y2-25);
 %end;
run;
/* Hide unnecessary links (if any) obtained from above do-loop processing */
data anno;
 set anno;
 if findc(link,'5')>0 then color='white'; * Hide 5th tier as its not needed here ;
 if substr(link,lengthn(link))='4' then color='white'; * Hide 4th element in each
 tier ;
run;
/*------------------------------------------------------------------------------*/
/*-- STEP 2: Perform Match with Universal Flowchart Template Created in Step 1 -*/
/*------------------------------------------------------------------------------*/
data final_anno (drop=txt);
 length ID LINK var $10 txt text $100;
 if _n_=1 then do;
 declare hash h(dataset:"all_dsn");
 h.defineKey("ID", "LINK");
 h.defineData("txt","var");
call missing(txt,var);
 h.defineDone();
end;
 set anno (drop=text);
 if h.find()>0 then do; * Hide extra element/links in the Universal template ;
 color='white';
 end;
if txt ne ' ' then do;
 if TROW='1' then TEXT=scan(txt,1,'*'); * '*' is the delimiter between lines
 of text ;
 if TROW='2' then TEXT=scan(txt,2,'*');
 end;
run;
/* Output to ODS RTF destination */
ods rtf file=".\flowchart.rtf";
 proc ganno anno=final_anno ;
 run ;
 quit ;
ods rtf close;
%mend;
/* Macro call */
%flowchart(dsn = example, floor= 12>var1 12>22 # 22>var2 22>32 # 32>var3 32>41 32>43 #
41>var4 # 43>var5);
1 REPLY 1
Tom
Super User Tom
Super User

Most likely you need to adjust these hard coded increments to reflect the fact that you want to make smaller boxes so they can fit on the page.

 

 %let b_x1 = %eval(&b_x1. + 30);
 %let b_x2 = %eval(&b_x2. + 30);
 ...
 %let b_y1 = %eval(&b_y1-25);
 %let b_y2 = %eval(&b_y2-25);

hackathon24-white-horiz.png

2025 SAS Hackathon: There is still time!

Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!

Register Now

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 1 reply
  • 353 views
  • 0 likes
  • 2 in conversation