Hi,
I have a problem with drawing some horizontal lines in tables produced by proc report. The table looks like that:
Column1 | Column2 | Column3 |
---|---|---|
Section 1 | xxx | xxx |
Section 1 | xxx | xxx |
Section 1 | xxx | xxx |
Section 2 | xxx | xxx |
Section 2 | xxx | xxx |
Section 3 | xxx | xxx |
I want to have a thicker line (underline) after each section (see column1). I tried "break after ... /OL" in proc report but it's only working with listing, not with RTF output. That statement is ignored when using ODS RTF. I also tried to insert another row with 0pt size (computer after and line statement in proc report) but a font size lower than 6pt is not allowed. Last, I wrote RTF code words in the SAS data set, e.g. - Column1 = "^{style [bordertopwidth=2pt]}"||Column1; - and I do that for each column. This solution is working but there is one bug - there is a leading blank in each cell (I tried to demonstrate that in Column3 - if a new section starts, i.e. if RTF code words are implemented in the variables, there will be a leading blank). I cannot see the blank in the SAS dataset but only in the output - I tried SAS character functions, e.g. "strip" but it did not change anything.
If someone has an idea - how to avoid/delete the leading blanks or better, if someone has a better idea than writing RTF code words in SAS datasets, please let me know!
Thanks for help!!!
Hi:
Can you share your PROC REPORT code? The entire code -- including ODS RTF statements and your PROC REPORT statements would be most useful.
Thanks,
cynthia
Hi, here an example SAS code:
ods escapechar='^';
data lines;
input section column1$ column2$ column3$ column4$ column5$;
cards;
1 A B C D E
1 A B C D E
1 A B C D E
2 B C D E F
2 B C D E F
3 C D E F G
3 C D E F G
;
run;
*add RTF code words to data set;
data lines;
length column1-column5 $100.;
set lines;
by section;
if first.section then do;
column1 = "^{style [bordertopwidth=2pt]}"||column1;
column2 = "^{style [bordertopwidth=2pt]}"||column2;
column3 = "^{style [bordertopwidth=2pt]}"||column3;
column4 = "^{style [bordertopwidth=2pt]}"||column4;
column5 = "^{style [bordertopwidth=2pt]}"||column5;
end;
run;
proc template;
define style MYSTYLE;
class Table /
frame = box
rules = none
borderbottomwidth=2pt
bordertopwidth=2pt
borderrightwidth=2pt
borderleftwidth=2pt
;
end;
run;
ods listing close;
ods rtf file = "C:/example_lines.rtf" style=MYSTYLE;
proc report data=lines NOWINDOWS BOX STYLE(header)=[borderrightwidth=2pt background=white];
column section column1 column2 column3 column4 column5;
define section / order order=data noprint;
define column1 / style(column)=[borderrightwidth=2pt]
style(header)=[borderrightwidth=2pt borderbottomwidth=2pt];
define column2 / style(column)=[borderrightwidth=1pt]
style(header)=[borderrightwidth=1pt borderbottomwidth=2pt];
define column3 / style(column)=[borderrightwidth=2pt]
style(header)=[borderrightwidth=2pt borderbottomwidth=2pt];
define column4 / style(column)=[borderrightwidth=1pt]
style(header)=[borderrightwidth=1pt borderbottomwidth=2pt];
define column5 / style(column)=[borderrightwidth=2pt]
style(header)=[borderrightwidth=2pt borderbottomwidth=2pt];
;
quit;
ods rtf close;
>> If someone has an idea - how to avoid/delete the leading blanks or better, if someone has a better idea than writing RTF code words in SAS >> datasets, please let me know!
Thanks.
Hi:
I think you are working too hard. I don't think you need a custom style template. You can add a blank line at the break and then turn the border style of the blank line to be what you want. I think that may be easier than attaching ODS STYLE overrides to each variable value, as you show.
Here's the thing. RTF control strings -- real RTF control strings start with \ -- like \line, \b, \i, etc. What you are putting into your variable values are "pure" ODS -- ODS ESCAPECHAR style = overrides. And, I don't think you need them.
I am teaching this week and not able to run new code. I believe your leading space will go away once you no longer embed the style override on each variable value. I would recommend starting from the JOURNAL style, adding the COLUMN lines and then putting a line at the break. After class, I can search for an example that might help. Otherwise, you could fiddle around with:
ods rtf ... style=journal; (instead of your style)
proc report ....
style(report)={frame=box rules=cols};
and then something like:
compute after section / style={bordertopcolor=black borderbottomcolor=black height=1px cellpadding=0};
line ' ';
endcomp;
Sorry I can't be of more help, but maybe that will help you get pointed in a different direction.
cynthia
BTW, some options like BOX, FLOW, SKIP, etc are LISTING-only options and are ignored by ODS RTF, PDF and HTML.
Hi:
OK...finally had some time to create a set of examples. See attached screenshot that shows all 6 outputs side by side, created with code shown below. Note that each numbered title corresponds to a different method. None of my methods use a custom style template. All my outputs, however, start with using the JOURNAL style and go from there. In #4, I did use "pure" RTF control strings (\brdrt\brdrs) so you could see the difference. What you had in your original code was ODS ESCAPECHAR style overrides - -which look a bit different.
You can use style overrides on the break between sections, but generally, there has to be something you put onto the report at the break. I use the LINE statement with a ' ' (quote space quote) to write out a blank line. As you can see, even though I specify an extremely small height for the blank, there is a limit to how small RTF will let you specify a height value and whether Word will use the value "unadjusted". There are probably "pure" RTF methods that would alter the cell height and/or put a single borderline under the last obs of a group, but I'm not great with RTF control strings.
cynthia
*** The code;
data lines;
input section column1$ column2$ column3$ column4$ column5$;
return;
cards;
1 A B C D E
1 A B C D E
1 A B C D E
2 B C D E F
2 B C D E F
3 C D E F G
3 C D E F G
;
run;
ods listing close;
ods rtf file = "C:\temp\example_lines.rtf" style=journal;
proc report data=lines NOWINDOWS
STYLE(report)=[frame=box rules=cols]
style(header)={borderbottomwidth=2pt borderbottomcolor=black};
title '1) Using color as a divider';
column section column1 column2 column3 column4 column5;
define section / order order=data noprint;
define column1 / "Column 1";
define column2 / "Column 2";
define column3 / "Column 3";
define column4 / "Column 4";
define column5 / "Column 5";
compute after section /
style={height=1px background=cx999999 cellpadding=0};
line ' ';
endcomp;
run;
proc report data=lines NOWINDOWS
STYLE(report)=[frame=box rules=cols]
style(header)={borderbottomwidth=2pt borderbottomcolor=black};
title '2) Using blank (white) line as divider';
column section column1 column2 column3 column4 column5;
define section / order order=data noprint;
define column1 / "Column 1";
define column2 / "Column 2";
define column3 / "Column 3";
define column4 / "Column 4";
define column5 / "Column 5";
compute after section /
style={height=1px cellpadding=0};
line ' ';
endcomp;
run;
proc report data=lines NOWINDOWS
STYLE(report)=[frame=box rules=cols]
style(header)={borderbottomwidth=2pt borderbottomcolor=black};
title '3) Using border lines as a divider';
column section column1 column2 column3 column4 column5;
define section / order order=data noprint;
define column1 / "Column 1";
define column2 / "Column 2";
define column3 / "Column 3";
define column4 / "Column 4";
define column5 / "Column 5";
compute after section /
style={height=1px bordertopcolor=black borderbottomcolor=black cellpadding=0
bordertopstyle=solid borderbottomstyle=solid
bordertopwidth=2pt borderbottomwidth=2pt};
line ' ';
endcomp;
run;
proc report data=lines NOWINDOWS
STYLE(report)=[frame=box rules=cols]
style(header)={borderbottomwidth=2pt borderbottomcolor=black};
title '4) Using RTF control strings';
column section column1 column2 column3 column4 column5;
define section / order order=data noprint;
define column1 / "Column 1";
define column2 / "Column 2";
define column3 / "Column 3";
define column4 / "Column 4";
define column5 / "Column 5";
compute after section /
style={protectspecialchars=off};
line '\brdrt\brdrs ';
endcomp;
run;
ods _all_ close;
ods rtf file='c:\temp\diff_by.rtf' style=journal startpage=no;
** another approach using BY;
proc report data=lines NOWINDOWS
STYLE(report)=[frame=box rules=cols]
style(header)={borderbottomwidth=2pt borderbottomcolor=black};
title '5) Using BY groups';
by section;
column section column1 column2 column3 column4 column5;
define section / order order=data noprint;
define column1 / "Column 1";
define column2 / "Column 2";
define column3 / "Column 3";
define column4 / "Column 4";
define column5 / "Column 5";
run;
ods _all_ close;
ods rtf file='c:\temp\diff_page.rtf' style=journal startpage=no;
** another approach without BY and with PAGE;
proc report data=lines NOWINDOWS
STYLE(report)=[frame=box rules=cols]
style(header)={borderbottomwidth=2pt borderbottomcolor=black};
title '6) Using PAGE for section groups';
column section column1 column2 column3 column4 column5;
define section / order order=data noprint;
define column1 / "Column 1";
define column2 / "Column 2";
define column3 / "Column 3";
define column4 / "Column 4";
define column5 / "Column 5";
break after section / page;
run;
ods _all_ close;
@Cynthia: Thank you very much for all the examples!!!
I got another idea when I was trying your examples - you can use the compute statement to get the lines without having another row. So I just had to add the following code to my proc report statement:
compute after section;
if section ne . then call define (_row_, 'style', 'style=[bordertopwidth=2pt]');
endcomp;
So, I got pointed in another direction because of your examples, thanks a lot!
Sabrina
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.