Hello all,
I have this dataset;
id start_date aval1 aval2 grp
1 1 4 . A
1 3 4 . A
1 5 6 . A
1 10 . 12 B
1 12 . 21 B
1 14 . 11 B
1 16 . 12 B
1 11 . 25 B
2 2 4 . A
2 3 6 . A
2 5 9 . A
2 19 12 . A
2 23 . 13 B
3 6 5 . A
3 8 18 . A
3 10 . 20 B
3 13 . 17 B
For each id, I want to get a figure in one rtf page (so 3 pages).For each page , I want to have as footnote 'page n of N'. n is the number of the id and N is the total number (which is 3).I've created macro variables and I tried to use the 'where' statement in proc sgplot but it doesn't work because the where statement was rejected. This is a part of my code:
%DO i=1 %to &TOTAL. ;
TITLE font="Courier New" justify=center h=1.8 j=l "&&sub&i";
footnote4 font="Courier New" h=1.8 j=l "Page &i of &total";
proc sgplot data=fin2;
where id=&i.;
by id;
step x=start_date y=aval1 / lineattrs=(color=grey pattern=solid thickness=1.4mm) ;
step x=start_date y=aval2 / y2axis lineattrs=(color=green pattern=solid thickness=1.4mm) ;
xaxis label='Study day' minor minorcount=4 type=linear ;
yaxis label='Inhaled treprostinil' minor minorcount=4 offsetmin=1 offsetmax=1 type=linear ;
y2axis label='Selexipag' labelpos=center minor minorcount=4 offsetmin=0 offsetmax=0 type=linear ;
keylegend / across=1 down=2 noborder linelength=4mm ;
run;
ods rtf close;
%end;
ods _all_ close;
options ls=120;
%mend print;
%print;
Any suggestion please ?
Hi:
I created an example that uses SASHELP.CLASS and does what I think you want:
I am sorry it is so small, but I have highlighted in yellow the Page X of Y page numbers in each footnote (showing 3 pages) and in the TITLE, I show the name (where you would show ID). You should be able to run this code. As you can see, I did not try to "overcontrol" things by doing my own page numbering or using a %DO loop. Since you did not show all of your macro code and since I find it best to have a working "proof of concept" before macroizing anything, I simplified the program and "hardcoded" the invocation of the macro program for each student inside my ODS RTF "sandwich".
** put the proc report and graph code in a macro program;
%macro makertf(wname=,xx=,xyz=,ffff=);
ods escapechar='^';
proc report data=sashelp.class;
title j=c "ID/Name is for &wname";
footnote1 j=l "&xx";
footnote2 j=l "&xyz";
footnote3 j=l "&FFFF";
footnote4 'Page ^{thispage} of ^{lastpage}';
where name = "&wname";
column name sex age height weight;
run;
** make a data label variable for the name of interest;
data graf_class;
set sashelp.class;
if name in ("&wname") then dl=Name;
else dl = ' ';
run;
** if you are using RTF do NOT need to have ODS LISTING statement;
** before PROC SGPLOT;
proc sgplot data=graf_class;
scatter x=height y=weight / datalabel=dl;
run;
%mend makertf;
** now invoke the macro program 1 time for each student;
options nodate nonumber orientation=portrait;
ods rtf file='c:\temp\test_pg_no.rtf' startpage=no nogtitle nogfootnote;
%makertf(wname=Alice, xx=AA1, xyz=AA12, FFFF=AAA123)
ods rtf startpage=now;
%makertf(wname=Alfred, xx=ABC1, xyz=ABC12, FFFF=ABC123)
ods rtf startpage=now;
%makertf(wname=Robert, xx=ABB1, xyz=ABB12, FFFF=AB123)
ods rtf close;
And while you could certainly "macroize" the whole program and the invocation for every student/patient/ID, I'd recommend getting it working like this and then inserting more macro logic of %DO loops. And you have to think about where you would want the %DO loops to be - or whether 1 macro would do the job or whether you'd need more than one macro program to get things done.
At any rate, I do find that ESCAPECHAR and the regular page x of y page numbering work for me in ODS RTF. Hope this points you in the right direction.
Cynthia
Yes, look up by group processing. It should be a fundamental in the learning material but seems to have been removed and replaced with do everything in macro instead.
ods escapechar="^"; title "..."; footnote4 'Page ^{thispage} of ^{lastpage}'; ods rtf file="..."; proc sgplot...; by id; ... run; ods rtf close;
I don't know why it doesn't work. In the output I get 'page of' and not 'page 1 of 1' (for instance).
You will need to set the option to not have titles/footnotes embedded in the graph:
ods rtf file="..." nogtitle nogfoot;
Then the titles/footers should be in the header/footer section of the output file and be resolved correctly at render time.
This is a part of the code, the problem remains:
options orientation=portrait papersize='ISO A4' nodate noDate nonumber nobyline;
%let figtit0 = XXX ;
%let figtit1 = YYY ;
%LET gtxt = 'Courier New';
%LET gtxtL = 'Courier New';
goptions reset=all
device=png gunit=pct rotate=portrait
xmax=10 in ymax=12 in
xpixels=1400 ypixels=1800
hsize=20.5 cm vsize=13 cm
ftext= 'Arial' htitle=9.0 pt htext=9.0 pt cback=white gwait=2 ;
goption display noborder ;
options orientation=portrait papersize='ISO A4' nodate noDate nonumber nobyline
bottommargin= 2.4 cm topmargin= 2.2 cm
leftmargin= 2.4 cm rightmargin= 2.0 cm;
ods escapechar='^';
TITLE1 font="Courier New" h=1.8 j=l "&figtit0.";
TITLE2 font="Courier New" h=1.8 j=l "&figtit1.";
footnote1 font="Courier New" h=1.8 j=l "xx";
footnote2 font="Courier New" h=1.8 j=l "xyz";
footnote3 font="Courier New" h=1.8 j=l "FFFF";
footnote4 'Page ^{thispage} of ^{lastpage}';
ods rtf file ="aaa.rtf"
style =normal NOGTITLE nogfootnote bodytitle;
ods listing style=listing;
proc sgplot data=fin2;
by ID;
step x=START_DATE y=aval1 / lineattrs=(color=grey pattern=solid thickness=1.4mm) ;
step x=START_DATE y=aval2 / y2axis lineattrs=(color=green pattern=solid thickness=1.4mm) ;
xaxis label='Study day' minor minorcount=4 type=linear ;
yaxis label='AAA' minor minorcount=4 offsetmin=1 offsetmax=1 type=linear values=(0 to 15 by 1) ;
y2axis label='BB' labelpos=center minor minorcount=4 offsetmin=0 offsetmax=0 type=linear values=(0 to 1600 by 200) ;
keylegend / across=1 down=2 noborder linelength=4mm ;
run;
quit;
ods rtf close;
ods _all_ close;
options ls=120;
Use a code window to post code - its the {i} above post - as this preserves formatting.
At a guess I would say update this line to this:
ods rtf file="aaa.rtf" style=normal nogtitle nogfoot;
And remove the ods listing:
ods listing style=listing;
In fact, ods _all_ close; before any programming is good as you aren't using listing output.
Also note, I can't test this.
Hello Cynthia,
I tried with escapechar but I don't know why it doesn't work (see the discussion above).
What I want to get is a graphic for each patient in an RTF file (every page contains one figure and a footnote 'page x of y' and a title which contain the id number). I couldn't combine the by group statement and a loop statement to get the required result.
Hi:
I created an example that uses SASHELP.CLASS and does what I think you want:
I am sorry it is so small, but I have highlighted in yellow the Page X of Y page numbers in each footnote (showing 3 pages) and in the TITLE, I show the name (where you would show ID). You should be able to run this code. As you can see, I did not try to "overcontrol" things by doing my own page numbering or using a %DO loop. Since you did not show all of your macro code and since I find it best to have a working "proof of concept" before macroizing anything, I simplified the program and "hardcoded" the invocation of the macro program for each student inside my ODS RTF "sandwich".
** put the proc report and graph code in a macro program;
%macro makertf(wname=,xx=,xyz=,ffff=);
ods escapechar='^';
proc report data=sashelp.class;
title j=c "ID/Name is for &wname";
footnote1 j=l "&xx";
footnote2 j=l "&xyz";
footnote3 j=l "&FFFF";
footnote4 'Page ^{thispage} of ^{lastpage}';
where name = "&wname";
column name sex age height weight;
run;
** make a data label variable for the name of interest;
data graf_class;
set sashelp.class;
if name in ("&wname") then dl=Name;
else dl = ' ';
run;
** if you are using RTF do NOT need to have ODS LISTING statement;
** before PROC SGPLOT;
proc sgplot data=graf_class;
scatter x=height y=weight / datalabel=dl;
run;
%mend makertf;
** now invoke the macro program 1 time for each student;
options nodate nonumber orientation=portrait;
ods rtf file='c:\temp\test_pg_no.rtf' startpage=no nogtitle nogfootnote;
%makertf(wname=Alice, xx=AA1, xyz=AA12, FFFF=AAA123)
ods rtf startpage=now;
%makertf(wname=Alfred, xx=ABC1, xyz=ABC12, FFFF=ABC123)
ods rtf startpage=now;
%makertf(wname=Robert, xx=ABB1, xyz=ABB12, FFFF=AB123)
ods rtf close;
And while you could certainly "macroize" the whole program and the invocation for every student/patient/ID, I'd recommend getting it working like this and then inserting more macro logic of %DO loops. And you have to think about where you would want the %DO loops to be - or whether 1 macro would do the job or whether you'd need more than one macro program to get things done.
At any rate, I do find that ESCAPECHAR and the regular page x of y page numbering work for me in ODS RTF. Hope this points you in the right direction.
Cynthia
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.