BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
blueskyxyz
Lapis Lazuli | Level 10

hi, guys, who are familiar with listing rtf output?

 

demand:

1. repeat footnote on each page, not only in the last page.

2. get the page number automatically.(some obs may have more than one line in rtf)

 

rtf.png

 format;
   value $ time10n
   a  =      1.625
   b  =      1.825
 ......
   z  =      1.625
   A  =      2.625
..... 
   X  =      2.625
   Y  =      2.625
   Z  =      2.225
  ' ' =      0.950
  '1' =     1.775
  '2' =     1.775
  ...
  '9' =     1.775
  '0' =     1.775
  '#' =     1.775
  '$' =     1.775
.....
  '<' =     2.025
  '>' =     2.025
........
'"' = 1.450 "'" = 0.650 OTHER = ...; run;

in the template, the total rft width is 9.9 intch, so how to calculate the unit conversion for each character using times new roman (fontsize= 8 pt)

 ?

1 ACCEPTED SOLUTION

Accepted Solutions
Jianmin
Obsidian | Level 7

Hi  @blueskyxyz , @Cynthia_sas and @Kurt_Bremser ,

Wen_23 didn't want to re-invent a wheel, but SAS ODS RTF team did. 

To answer Wen_23's question of Heart data example: you can try to replace 20 with 10 in your code:

page=int(_n_/20)

You may want to try a few other numbers, until you got satisfied results for your data.   This is how many other pharma companies to deal with this type of problem for complicated listings, when they use SAS ODS PROC REPORT.  They almost all have used a SAS macro like RowWrap, to get a better calculation of a dynamical variable page to get a better fit of the results.  The input of this macro is your data and the proc report model, and how many records you want to display on a page.  In your example, you wanted 20, which is too big for the data.  The output is a dynamical variable of page,  resulting a better output from your proc report.   

You can google "SAS ODS RTF pagination" and you will see a few people tried to improve this matter.  But they can never solve this completely. 

The root cause of the problem of pagination was directly from SAS ODS RTF team's early decision to implement PAGE in PROC REPORT!  They invented a squared wheel, along with many fixes.   

SAS ODS RTF started about 20 years ago, based on a SAS macro that was used to generate clinical trial CSR tables about 25 years ago, and the macro later was published by someone else in SAS 

ftp://ftp.sas.com/techsup/download/observations/obswww13/obswww13.pdf
A reference about this macro was mentioned in https://www.lexjansen.com/pharmasug/2003/FDACompliance/fda077.pdf
The original macro didn't deal with pagination, since early tables are mostly on a single page.  But the solution was implied in the macro:  Don't bother to re-invent a wheel, Microsoft already solved the problem. 
Attached is a SAS generated (basically data _null_ and put) listing/summary of COVID-19 cases by the countries in the World. For countries with regional data, the names of those regions (the first column) were randomly changed to use 10 different fonts, 5 different font sizes, and a few different shapes.  (US regional data not presented in this file).   And you can see how well Microsoft handles pagination, without user input about it.   BTW, you may also wander how the data fits in those 26 pages.   
Many thanks for your thoughts.  
Jianmin

View solution in original post

14 REPLIES 14
Kurt_Bremser
Super User

RTF does not have a page size. The actual page size is determined when the text is printed, depending on the target page format (US Letter will need more pages than European A4).

Titles and footnotes are automatically inserted on each page by the user agent (MS Word, LibreOffice, etc).

You need only use ODS RTF, everything else is determined when the text is prepared for printing or display.

blueskyxyz
Lapis Lazuli | Level 10
data final;
	set sashelp.smemsg ;
	page=int(_n_/20);
run;

options orientation=landscape papersize=A4 nodate nonumber center topmargin=0.75 in leftmargin=1.0 in bottommargin=0.75 in rightmargin=1.0 in;
ods escapechar='^';
ods listing close;
ods rtf file="...\heart.rtf"   style=journal;
title j=l 'Company XXX' j=c 'Project ABC' j=r 'Page ^{thispage} of ^{lastpage}';
footnote j=c 'Confidential';

proc report data=final  nowd headline headskip 
   style(column)=[just=c asis=on]
   style(report)=[frame=above bordertopwidth=2] 
   style(header)=[borderbottomwidth=2]
   spanrows SPLIT='|'
   ;

	column page MSGID MNEMONIC LINENO LEVEL TEXT  PBUTTONS;			

	define page/order order=internal noprint;

	define MSGID/display style(column)={cellwidth=8%} flow;
	define MNEMONIC/display order style(column)={cellwidth=10%} flow;
	define LINENO/display style(column)={cellwidth=10%} flow;
	define LEVEL/display style(column)={cellwidth=8%} flow;
	define TEXT/display style(column)={cellwidth=40%} flow;
	define PBUTTONS/display style(column)={cellwidth=10%} flow;

	compute before _page_/style={font_size=10pt font_face="Times New Roman" just=left} ;
	     line "title xxxx";
	endcomp;

	break after page/page;

***add a blank line ;
   compute after LEVEL;
       line " ";
   endcomp;

    compute after _page_/style={font_size=10pt font_face="Times New Roman" just=left};
          line "foot xxx";
    endcomp;
run;

ods rtf close;
ods listing;

here is sample code

blueskyxyz
Lapis Lazuli | Level 10

sample code:

options orientation=landscape papersize=A4 nodate nonumber center topmargin=0.75 in leftmargin=1.0 in bottommargin=0.75 in rightmargin=1.0 in;
ods escapechar='^';
ods listing close;
ods rtf file="...\heart.rtf"   style=journal;
title j=l 'Company XXX' j=c 'Project ABC' j=r 'Page ^{thispage} of ^{lastpage}';
footnote j=c 'Confidential';

proc report data=final  nowd headline headskip 
   style(column)=[just=c asis=on]
   style(report)=[frame=above bordertopwidth=2] 
   style(header)=[borderbottomwidth=2]
   spanrows SPLIT='|'
   ;

	column page MSGID MNEMONIC LINENO LEVEL TEXT  PBUTTONS;			

	define page/order order=internal noprint;

	define MSGID/display style(column)={cellwidth=8%} flow;
	define MNEMONIC/display order style(column)={cellwidth=10%} flow;
	define LINENO/display style(column)={cellwidth=10%} flow;
	define LEVEL/display style(column)={cellwidth=8%} flow;
	define TEXT/display style(column)={cellwidth=40%} flow;
	define PBUTTONS/display style(column)={cellwidth=10%} flow;

	compute before _page_/style={font_size=10pt font_face="Times New Roman" just=left} ;
	     line "title xxxx";
	endcomp;

	break after page/page;

***add a blank line ;
   compute after LEVEL;
       line " ";
   endcomp;

    compute after _page_/style={font_size=10pt font_face="Times New Roman" just=left};
          line "foot xxx";
    endcomp;
run;

ods rtf close;
ods listing;

how to avoid the page break like below? In some  listings, it may have more than one thousand observations/rows.

捕获.JPG

blueskyxyz
Lapis Lazuli | Level 10

what I want for each page , like below:

 

demand:

1. repeat footnote on each page, not only in the last page.

2. get the page number automatically.(some obs may have more than one line in rtf)

 

捕获.JPG

Kurt_Bremser
Super User

Why do you want to reinvent the wheel, and make it squared on top?

This code (that you actually use already) creates nice dynamic titles and footnotes in the RTF files, that are populated with the correct numbers once the file is opened with a word processor (LibreOffice Writer in my case):

ods rtf file="/folders/myfolders/cars.rtf";
ods escapechar='^';

title j=l 'Company XXX' j=c 'Project ABC' j=r 'Page ^{thispage} of ^{lastpage}';
footnote j=c 'Confidential';

proc print data=sashelp.cars;
run;

ods rtf close;
Jianmin
Obsidian | Level 7

Hi  @blueskyxyz , @Cynthia_sas and @Kurt_Bremser ,

Wen_23 didn't want to re-invent a wheel, but SAS ODS RTF team did. 

To answer Wen_23's question of Heart data example: you can try to replace 20 with 10 in your code:

page=int(_n_/20)

You may want to try a few other numbers, until you got satisfied results for your data.   This is how many other pharma companies to deal with this type of problem for complicated listings, when they use SAS ODS PROC REPORT.  They almost all have used a SAS macro like RowWrap, to get a better calculation of a dynamical variable page to get a better fit of the results.  The input of this macro is your data and the proc report model, and how many records you want to display on a page.  In your example, you wanted 20, which is too big for the data.  The output is a dynamical variable of page,  resulting a better output from your proc report.   

You can google "SAS ODS RTF pagination" and you will see a few people tried to improve this matter.  But they can never solve this completely. 

The root cause of the problem of pagination was directly from SAS ODS RTF team's early decision to implement PAGE in PROC REPORT!  They invented a squared wheel, along with many fixes.   

SAS ODS RTF started about 20 years ago, based on a SAS macro that was used to generate clinical trial CSR tables about 25 years ago, and the macro later was published by someone else in SAS 

ftp://ftp.sas.com/techsup/download/observations/obswww13/obswww13.pdf
A reference about this macro was mentioned in https://www.lexjansen.com/pharmasug/2003/FDACompliance/fda077.pdf
The original macro didn't deal with pagination, since early tables are mostly on a single page.  But the solution was implied in the macro:  Don't bother to re-invent a wheel, Microsoft already solved the problem. 
Attached is a SAS generated (basically data _null_ and put) listing/summary of COVID-19 cases by the countries in the World. For countries with regional data, the names of those regions (the first column) were randomly changed to use 10 different fonts, 5 different font sizes, and a few different shapes.  (US regional data not presented in this file).   And you can see how well Microsoft handles pagination, without user input about it.   BTW, you may also wander how the data fits in those 26 pages.   
Many thanks for your thoughts.  
Jianmin
blueskyxyz
Lapis Lazuli | Level 10

@Jianmin @Cynthia_sas @Kurt_Bremser @Tom 

Thanks  for your help and reply.

 

Hey, @Jianmin , thanks for sharing the materials which really inspire me, I'll try these methods later.

To resolve my problem, I had tried this method in this paper.

I am glad you can understand my question.

😃Good night.

(https://www.lexjansen.com/pharmasug/2006/TechnicalTechniques/TT12.pdf)

Cynthia_sas
SAS Super FREQ

Hi:
Your #1 is easy if you use the FOOTNOTE statement. Your #2 doesn't make sense to me. "Get the page number automatically", This is possible because you can use ODS ESCAPECHAR to insert page x of y into the document (page 1 of 10, page 2 of 10, etc). However, the parenthetical comment you make "some obs may have more than one line in rtf" -- what does this have to do with getting the page number? I don't understand that part.

Every font you specify has a size and the font definition includes everything that the rendering application needs to render the document. As you might have guessed, you can get more characters on a line at 8pt font than if you use 16pt font. However, it was my understanding that most of the sizes in RTF were translated to a unit of TWIPS (twentieths of a printers point), so trying to calculate "character" with proportional spaced fonts is a pointless task. As an example, consider this:

Cynthia_sas_0-1594752012670.png

 


The string that I'm showing on each line has 96 characters with no spaces. As you can see, the font and font size that are used make a difference in how many characters can fit on one line. When SAS makes an RTF file, it takes all the table into account -- font characters, spaces, table lines if you have them, margins, cellspacing and cellpadding settings, etc. You can't replicate the calculation that SAS uses to create output for a paged destination.
Hope this helps,
Cynthia

blueskyxyz
Lapis Lazuli | Level 10
Thanks for your reply, Cynthia.

Sorry, I didn't explain my question clearly.

Now we have a lot of listings (*.rtf ) to output, but all of them are different for all contents, titles, footnotes, for example, some width of cells for one observation or one row may have serveral lines(like sex/^n age/^n birthday), some titles or footnotes may also have serveral lines.

I want to find out how many rows(observations) in one page(rtf) , even though some rows may have serveral lines, make sure that each row is in same page without page break.

example :
title1.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
column A column B column C .............. column J
17years / Female drug A the patient did't sign the informed .....
/ 19980910 consent form ......
>>>>>>
>>>>>>
>>>>>>>
********column A and C have two lines, while column B has one line**************;

footnote1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
footnote2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA


Kurt_Bremser
Super User

@blueskyxyz wrote:

I want to find out how many rows(observations) in one page(rtf) 

THIS IS NOT POSSIBLE.

You cannot know the pagesize when creating the RTF, as it is dependent on the settings of the renderer, and set dynamically when the contents of the RTF file are prepared for printing or display.

Let the renderer do it for you, as the code I previously posted does.

 

 

 

Jianmin
Obsidian | Level 7

Hi @Kurt_Bremser , 

It's not possible to know a few things about RTF page when use ODS RTF destination, since the Renderer  takes away the control from the SAS users. 

 

Do get me wrong if you have seen my other post, that ODS RTF's invention of PAGE works wonder in many cases, but it falls in a trap that prevents it doing its jog in other cases.  Merck's implementation of the original RTF macro suffers the same as ODS RTF : https://www.lexjansen.com/pharmasug/2003/TechnicalTechniques/tt038.pdf

 

Let's start a 2x2 tables in a Word document: you can copy whatever content and paste it into a cell, and add a new row when you finish this table, copy and paste again and again, ..., the table will grow and grow.   You will see how well MS Word handles the page.  No matter what contents you put in each cell.  

 

This is only possible if SAS ODS RTF didn't take control from MS Word. 

 

So, SAS ODS RTF can have an option:  Keep PAGE functionality and learn from MS Word to give SAS users an option for other cases that PAGE does not handle well. 

 

Attached is a slightly difficult listing (only part of a 300 page+ listing) and see for yourself. 

Best Regards, Jianmin 

 

 

blueskyxyz
Lapis Lazuli | Level 10

捕获.JPGSorry, I try to expalin  in a simple way: 

According the dataset you have,  how to get the number of  lines in  one rtf listing page?

Tom
Super User Tom
Super User

@blueskyxyz wrote:

捕获.JPGSorry, I try to expalin  in a simple way: 

According the dataset you have,  how to get the number of  lines in  one rtf listing page?


You DON'T.   It there is too much information to fit on one page the word processor that is reading the RTF file will figure that out and start a new page for you.

Please explain why it matters? If you want each value of A or value of TITLE to start on a new page then use the page by feature of the reporting tool.

Are you asking to have multiple groups per page, but force large groups that will not fit int he space left on the page to start a new page?

blueskyxyz
Lapis Lazuli | Level 10

Thanks @Cynthia_sas , I have searched and read a lot of paper and posts in order to solve my puzzle, you can see the paper shared by Janmin. 

 

Sorry, I dig out your reply in the post created serverl years before.

 

Keep curious to solve my puzzle.

 

🙂Night.

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 14 replies
  • 6225 views
  • 0 likes
  • 5 in conversation