SAS technical support confirms that PROC REPORT can not use the full width of page. It is a known bug and still has not been addressed. This post will describe the issue first and then present how to solve the problem with a little trick.

Description of the problem:

Here is an example output created by proc report. Though we have specified outputwidth = 100% in RTF template to make sure that the display area of table can fit entire page up to the margins, there is still blank space between margins and table display area. Blank space between left margin and left border of table and blank space between right margin and right border of table have been pointed out in following figure.

Below is the code to produce above output.

Click here to hide/show code


proc template;
define style customtemp;
parent = Styles.RTF;
replace fonts /
‘TitleFont’ = (“Times New Roman”,10pt) /* Titles from TITLE statements */
‘TitleFont2’ = (“Times New Roman”,10pt) /* Procedure titles */
‘StrongFont’ = (“Times New Roman”,10pt,Bold)
‘EmphasisFont’ = (“Times New Roman”,10pt)
‘headingEmphasisFont’ = (“Times New Roman”,10pt,Bold)
‘headingFont’ = (“Times New Roman”,10pt,Bold) /* Table column and row headings */
‘docFont’ = (“Times New Roman”,10pt) /* Data in table cells */
‘tableFont’ = (“Times New Roman”,10pt)
‘footFont’ = (“Times New Roman”,10pt) /* Footnotes from FOOTNOTE statements */
‘FixedEmphasisFont’ = (“Times New Roman”,10pt)
‘FixedStrongFont’ = (“Times New Roman”,10pt,Bold)
‘FixedHeadingFont’ = (“Times New Roman”,10pt,Bold)
‘BatchFixedFont’ = (“Times New Roman”,10pt)
‘FixedFont’ = (“Times New Roman”,10pt)
;

replace color_list /
‘link’ = blue /* links */
‘bgH’ = _undef_ /* row and column header background */
‘fg’ = black /* text color */
‘bg’ = _undef_; /* page background color */

replace Body from Body /
topmargin = 1 in
bottommargin = 0.375 in
leftmargin = 1 in
rightmargin = 1 in
protectspecialchars = off
outputwidth = 100%
;

style Table from Table /
frame = hsides /* outside borders: void, box, above/below, vsides/hsides, lhs/rhs */
rules = groups /* internal borders: none, all, cols, rows, groups */
cellpadding = 1pt /* the space between table cell contents and the cell border */
cellspacing = 0pt /* the space between table cells, allows background to show */
borderwidth = 0.5pt /* the width of the borders and rules */
outputwidth = 100%
Background=_undef_
;

style UserText from UserText/
outputwidth = 100%
protectspecialchars = off
asis = on
just = left
;

replace NoteContent from NoteContent /
protectspecialchars = off
asis = on
just = left
;

style Footer from Footer /
asis = on
protectspecialchars = off
just = left
;

replace Header from Header /
protectspecialchars = off
asis = on
just = left
;

replace Data from Data /
protectspecialchars = off
asis = on
just = left
;

style systemtitle from systemtitle /
protectspecialchars=off;

style parskip /
fontsize = 0pt
;

end;
run;

options orientation=landscape;
ods escapechar= “^”;
ods tagsets.rtf file = “&tables/class.rtf” style=customtemp nogtitle nogfootnote
options(vspace=”no” tables_off=”prepage” continue_tag=”no”) uniform;
ods listing close;

title1 j=c “Example RTF”;
title2 j=c ” “;
footnote1 j=l “Example foonote.”;

proc report data=sashelp.class;
run;

ods tagsets.rtf close;
ods listing;

How to remove spaces between margins and table:

By opening the RTF output in Notepad++, we can observe how the RTF code is organized for each table element. RTF code in first and second red box were created by title1 and title2 statement respectively. Right boundary of these two rows is 12960 twips away from left margin. While RTF code in the third red box was created by PROC REPORT. Right boundary of the header row is 12786 twips away from left margin.

If we replace 12786 with 12960, the table header row will fit the entire page up to margins.

So far, we have found the approach how to fix the problem. Next step is how to replace number after last \cellx for each table row with 12960 by programming. Look back at the first figure, we can extract the number and use LAG function to put the number in the {\row} observation. By outputting all observations containing {\row}, we can get all numbers for each table row. Duplicate numbers can be removed by PROC SORT NODUPKEY. These distinct numbers can be substituted with TRANWRD function and macro variables. Following is the code to read RTF output into SAS dataset and then put manipulated data into RTF file again.

Click here to hide/show code


%macro postrtf(outfile = );
%let cnum = 12960;
data m_pgno;
length rtfcode $8192;
infile “&tables/&outfile..rtf” lrecl = 8192 end = eof;
input ;
rtfcode = _infile_;
if index(rtfcode, “cellx”) then
cnum = input(substr(rtfcode, find(rtfcode,”cellx”) + 5, length(strip(rtfcode)) – find(rtfcode, “cellx”)),best.);
cnum_lag = lag(cnum);
run;

proc sort data =m_pgno(where=(rtfcode = “{\row}” and cnum_lag ne %eval(&cnum))) out=cnum nodupkey;
by descending cnum_lag; run;
data cnum;
set cnum end=eof;
call symputx(‘cnum’||strip(put(_n_,best.)), strip(put(cnum_lag,best.)));
if eof then call symputx(“cnum_tot”, strip(put(_n_,best.)));
run;

data m_pgno;
retain pgfl;
set m_pgno(where=(rtfcode ne “”)) end=eof;

%do i = 1 %to %eval(&cnum_tot);
rtfcode = tranwrd(rtfcode, “cellx&&cnum&i”, “cellx&cnum”);
%end;
run;

data _null_;
file “&tables/&outfile..rtf”;
set m_pgno;

put rtfcode;
run;
%mend;

%postrtf(outfile = class);


In above macro, we set value of macro variable cnum to be 12960. What if the layout orientation is portrait? US letter size measures 8.5 by 11 inches. According to PROC TEMPLATE, all margins are 1 inch. If the paper layout is portrait, the width will be (8.5 – 1 – 1) which is 6.5 inches. 1 inch is 1440 twips and 6.5 inches will be 6.5*1440 twips. That is 9360 twips. The value of macro variable cnum can be populated automatically based on layout orientation. %sysfunc(getoption(orientation)) can be used to determine the current value of ORIENTATION option.