BookmarkSubscribeRSS Feed
KaySca81
Calcite | Level 5

Hi,

I have a problem with drawing some horizontal lines in tables produced by proc report. The table looks like that:

Column1Column2Column3
Section 1xxx xxx
Section 1xxxxxx
Section 1xxxxxx
Section 2xxx xxx
Section 2xxxxxx
Section 3xxx 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!!!

5 REPLIES 5
Cynthia_sas
SAS Super FREQ


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

KaySca81
Calcite | Level 5


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.

Cynthia_sas
SAS Super FREQ


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.

Cynthia_sas
SAS Super FREQ

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;


horizontal_lines_rtf_simple_choices.png
KaySca81
Calcite | Level 5

@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

SAS Innovate 2025: Register Now

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!

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
  • 5 replies
  • 14352 views
  • 5 likes
  • 2 in conversation