The SAS Output Delivery System and reporting techniques

Proc Report for the clinical trial report (Appendix 16.2.5 and 16.2.6) *the topic updated

Reply
Occasional Contributor
Posts: 13

Proc Report for the clinical trial report (Appendix 16.2.5 and 16.2.6) *the topic updated

[ Edited ]

Hi all,

 

Could you please help: what is the ODS for the reports like ones below. Or should I use options of the Report function? Writtein in 'blue' is not the part of the report.Table1.jpgTable2.jpg

Contributor
Posts: 62

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

Hello and welcome to the forum!

 

You will probably need PROC REPORT to produce summary tables such as this. I have found this book to be very helpful:

 

https://www.sas.com/storefront/aux/en/spreportindpth/69155_excerpt.pdf

 

ODS specifies the output destination. For example, ODS RTF will generate a file that can be opened in Microsoft Word.

 

Good luck!

 

Norman.

Norman.
SAS 9.4 (TS1M0) X64_7PRO WIN 6.1.7601 Service Pack 1 Workstation

Occasional Contributor
Posts: 13

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

Thank you for the prompt reply! I actually need to prepare the Tables (as Repors) from 2 files - please see attached. Do I understand correctly that I have to prepare 2 datasets with descriptive statistics initially and then to use procedure report for both of them? So the SAS program will consist of: 1)Mean/Freq procedure steps for every statistic and receiving separate datasets for every variable; 2)Merging the datasets; 3) Transpose of the dataset; 4) Proc Report ?

Is it possible to unite steps 1) and 2)? I mean to use 'class' option for Mean, for example?

I have attached the learning datasets. Could you please have a look?

 

Contributor
Posts: 62

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

When I do this, I prepare a SAS file where each row corresponds to the row that you want to see in the final output. This file of pre-processed data is read into PROC REPORT.

 

To make the file, you might need to use the output from PROC MEAN or PROC FREQ, then "assemble" the text in a DATA step.

Norman.
SAS 9.4 (TS1M0) X64_7PRO WIN 6.1.7601 Service Pack 1 Workstation

SAS Super FREQ
Posts: 8,720

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

Hi:

  My older paper, from 2008 http://www2.sas.com/proceedings/forum2008/173-2008.pdf has 3 examples of creating this type of report -- basically your plan is correct -- you do the summarizing and getting the percentages, etc and then you use a REPORT procedure. In my paper, I show using some "helper" variables to guarantee row order and the ability to apply bold/underline at certain places and to do the indenting.

 

cynthia

Occasional Contributor
Posts: 13

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

[ Edited ]

Thank you, Cynthia! Reading it as well as the programs: http://support.sas.com/rnd/papers/sgf2008/complex_reports.zip. If you do not mind I put my code here later on.

 

And I have another question: what is the way to output the result in .txt file?

 

Here below are my drafts:

 

Clin.Trial  Report 1.

/*Calculation of descriptive statistics of Age*/

PROC MEANS data=status n mean std median min max maxdec=2;
	var Age;
	/*output out=AgeStat;*/
RUN;

/*Calculation of descriptive statistics of Age Group*/

PROC FORMAT;
	value AgeGroupFormat
		17<-35='>17-<=35'
		35<-50='>35-<=50'
		50<-65='>50-<=65'
		65-high='>65';
RUN;

PROC FREQ data=status;
	tables Age / nocum;
	format Age AgeGroupFormat.;
	/*output out=AgeGroup;???*/
RUN;

PROC FREQ data=status;
	table Sex / nocum;
RUN;

PROC FREQ data=status;
	table Childpot / nocum;
RUN;

/*Calculation of descriptive statistics of Childbearing Potential*/

PROC FREQ data=status;
	tables Ethnic / nocum;
RUN;

/*Calculation of descriptive statistics of Height*/

PROC MEANS data=status n mean std median min max maxdec=2;
	var Height;
	output out=HeightStat;
RUN;

/*Calculation of descriptive statistics of Weight*/

PROC MEANS data=status n mean std median min max maxdec=2;
	var Weight;
	output out=HeightStat;
RUN;

/*Calculation of descriptive statistics of Duration of MS*/

PROC MEANS data=status n mean std median min max maxdec=2;
	var Durms;
	output out=DurationStat;
RUN;

/*Calculation of descriptive statistics of Duration of MS in Groups*/

PROC FORMAT;
	value DurationFormat
		low-1='<1'
		>1-5='>=1-<=5'
		>5-10='5>-<=10'
		>10-15='10>-<=15'
		15-high='>15';
RUN;

PROC FREQ data=status;
	tables Durmscat / nocum;
	/*format Durmscat DurationFormat.;*/
	/*output out=DurationFormat???*/
RUN;

/*Calculation of descriptive statistics of EDSS*/

PROC MEANS data=status n mean std median min max maxdec=3;
	var edss;
	/*output out=AgeStat;*/
RUN;

/*Calculation of descriptive statistics of EDSS Groups*/

PROC FORMAT;
	value EDSSformat
		0     = '0'
		1-2.5 = '1-2.5'
		3-4.5 = '3-4.5'
		5-6.5 = '5-6.5'
		7-8.5 = '7-8.5'
		9-9.5 = '9-9.5'
		10    = '10';
RUN;
 
 /*if null then assign 0* - should I work through if/else?*/ 
PROC FREQ data=status;
	tables edsscat / nocum;
	format edsscat EDSSformat.;
	/*output out=DurationFormat???*/
RUN;






 

 

And the Clin.Trial Report 2:

PROC SQL;
   	create table status_temp as
  	select site,pt,safety
   	from status
   	where safety=2;   
 
DATA ConMed (keep=site pt verbatim prefterm atcterm presbase studstrt durstud cont);
	merge cmed_dvd status_temp;
	by site pt;
		  	 	
RUN;

PROC FORMAT;
	value YesNoFormat
		1='YES'
		2='NO';
RUN;


PROC PRINT data=ConMed noobs;
	   
	format presbase studstrt durstud cont YesNoFormat.;
RUN;

 

It is a little bit far from the desired solution but please comment on any step of my strains. Does any information can be missed after sql and data steps in the second programm? Does it contain fatal errors? 

 

 

 

 

 

 

 

SAS Super FREQ
Posts: 8,720

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

[ Edited ]

Hi:
Since I typically do not open Excel files to get data, I cannot run your program and tell you whether the program has fatal errors. However, one easy way to find out is for you to run and test your program on your data. When you run your second program, does it have errors?

As far as I can see, you are not using any of the techniques from my paper in your program, so I am not sure what you are asking when you ask if the output can be sent to a TXT file. The regular SAS listing destination is the way to make an ASCII text file. However, the file will not have any style, fonts, colors, bolding, underlining, etc. The TXT file is very plain and none of my techniques would work for LISTING output.

However, there are 2 ways to direct your output to the SAS LISTING destination:
1) PROC PRINTTO
2) ODS LISTING file=

Both of those methods can be found in the documentation.

cynthia

Occasional Contributor
Posts: 13

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

[ Edited ]

I have attached the sas7bdat files: patients and concmed. Do I understand correctly that the files need no more transformations (besided some FORMATs) for the PROC REPORT?

 

Here it is my new code for 'patients'.

PROC FORMAT;

*** age category ***;
  value agecatf 1="<=17"
                2=">17-<=35"
                3=">35-<=50"
                4=">50-<=65"
                5=">65";
                
*** sex ***;
  value sexf 1="Male"
             2="Female";
             
*** numeric yes/no format ***;
  value noyesf  1="No"
                2="Yes";
                
*** ethnicity ***;
  value ethnicf 1="Asian"
                2="Black"
                3="Caucasian"
                4="Hispanic"
                5="Other";
                
*** Duration of MS category ***;
  value mscatf 1="<1"
               2=">=1-<=5"
               3=">5-<=10"
               4=">10-<=15"
               5=">15";
               
               
     
  *** EDSS category ***;
  value edsscatf 1="0"
                 2="1-2.5"
                 3="3-4.5"
                 4="5-6.5"
                 5="7-8.5"
                 6="9-9.5"
                 7="10";
RUN;



DATA Patients1;
	set patients;
	format agecat agecatf.
	       sex sexf.
	       childpot noyesf.
	       ethnic ethnicf.
	       durmscat mscatf.
	       edsscat edsscatf.;
RUN;

%let DATETIME=%sysfunc(datetime(),datetime19.);
%put &DATETIME;

title1 height=0.7 color=Grey justify=left 'Schwarz Pharma, Inc.' justify=right 'DATE:'&DATETIME; 
title2 height=0.7 color=Grey justify=left 'Protocol SP843'       justify=right 'Page{page}of{page}'; 
title3 height=0.7 color=Grey justify=left 'KEMSTRO'              justify=right 'PGM:XXXXX.SAS'; 

title4 height=1.5 justify=c 'Demographic and Baseline Characterestics';
title5 height=1.5 justify=c 'Safety Population';
title6 height=1.5 justify=c color=Blue 'where STATUS.safety=2';

PROC REPORT data=patients1;

RUN;

title;
  		

 

And the secont one - for 'conmed'. 'Patients' and 'Conmed' are kept in library 'work'.

%let DATETIME=%sysfunc(datetime(),datetime19.);
%put &DATETIME;

title1 height=0.7 color=Grey justify=left 'Schwarz Pharma, Inc.' justify=right 'DATE:'&DATETIME; 
title2 height=0.7 color=Grey justify=left 'Protocol SP843'       justify=right 'Page{page}of{page}'; 
title3 height=0.7 color=Grey justify=left 'KEMSTRO'              justify=right 'PGM:XXXXX.SAS'; 

title4 height=1.5 justify=c 'Concomitant Medications';
title5 height=1.5 justify=c 'Safety Population';
title6 height=1.5 justify=c color=Blue 'where STATUS.safety=2';

title7 height=1.5 justify=c 'TREATMENT SEQUENCE = KEMSTRO/BACLOFEN';


PROC REPORT data=conmed;

RUN;

 

I am examining PROC REPORT now and would be grateful if you could say how to calculate MEANs and FREQ withing the procedure. And how to put right header in one vertical line?

Attachment
Attachment
SAS Super FREQ
Posts: 8,720

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

Hi:
  In my paper, I do NOT calculate MEANS and FREQ inside PROC REPORT. Instead, as I showed in my first example, I take the patient information file and calculate the necessary statistics using PROC FREQ and PROC MEANS and then it is the dataset from those 2 procedures that goes into the PROC REPORT step (after making some helper variables to guarantee the order).

  However, as I indicated in my other posting, if you are interested in LISTING output (a TXT file), then the PROC FREQ, PROC MEANS part of my paper would be the same, but the PROC REPORT step might have to change a bit, since underlining, indenting and making some text bold will not work in the LISTING window.

  If you have my zip file from the 2008 paper, you can compare the first patient dataset that I have in the zip file with the final file created by my program that is sent forward to PROC REPORT.

  I did look at your two datasets and the answer is that neither one of them is ready to create your report using PROC REPORT. For example, you do not have any of the counts or percents calculated yet. The PROC REPORT step really will be easier to do if you use PROC FREQ and PROC MEANS to calculate your summary statistics.

  My zip file had 2 different versions of a program to calculate the statistics you want to report on. There was one program with each variable calculated separately and a second program that "macro-ized" the whole process. I suggest you look at the first program before tackling the macro program.

  You cannot use the program from my paper on your data in the current structure of the data. My paper showed how to run PROC FREQ and PROC MEANS to get the statistics into an output dataset, then showed how to manipulate that data a bit more to make 1 dataset of all the summary data, along with some helper variables to use in PROC REPORT. I suggest that you review my program step by step to see what each step was doing. The program I think will be the most help to you is the one named complex1_demog.sas. You will need to submit the complex0 program after you unzip the zip file to your local drive so you get the LIBNAME and setup steps finished before running the complex1_demog.sas program. This program has the PROC FREQ and PROC MEANS examples you ask for.


Cynthia

Occasional Contributor
Posts: 13

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

[ Edited ]

 I  have become much closer to the decision yesterday and today. To avoid a mess I would like to re-formulate my issues. The main task is to prepare the reports in .TXT format (not pdf, rtf, etc..). You can see the view of the .txt reports in my first post of the topic. I have attached the templates of the reports - please see the file "TABLE 14.doc". I have prepared the program that compose the first report: Table1  (TABLE1.SAS - attached) . Please see below and attached (TABLE1.pdf).

Report1.jpg

Report2.jpg

Report3.jpg

              

               I faced folllowing issues at the moment and can not sort them out. Could you please help.

 

1. The table should be output in 'clear' .txt format. When I use simple ODS Listing 'File.txt' I loss measures of the columns and lines.

2. I lost some observations that have 0% - some Ethics Origins, Durations of MS (years): N (%), EDSS Score: N (%). You can see when run Format file: progfmt.fmt - attached.

3. I was not able to put titles in Listing, not pdf. What are the common rules to implement it? Should I simply measure my page and place the title exactly where I calculate it?

4. All dots of decimal shuld be alined in one line? How could it be realized?

5. How to orient the pages in Landscape orientation, not portrait?

 

Here attached are the following files:

1. Table 14 - what shoulb be received but in .txt format.

2. progfmt.fmt - the formats to be run first

3. status.7dbase - dataset to be review.

4. Table1.sas - my opus.

Please be aware that the files are just for training purposes and do not reflect any real trials.

I have attached my code here as well.

ods listing file='C:\Users\Dmytro\Documents\SAS exam\CS Update\sas\Table1.txt';

****EXTRACTING DstATA FROM ARCHIVED DATASET************************;
libname xpt xport 'C:\Users\Dmytro\Documents\SAS exam\CS Update\sas\status.xpt';

proc copy
	in=xpt out=work;
run;

libname xpt clear;

****SELECTING PATIENTS WITH SAFETY=2**********************************;
proc sql;
	create table safe as
    select *  
	from status
	where safety = 2;

proc sql;
	create table status as
    select *  
	from safe
	where safety = 2;

**** AGE STATISTICS PROGRAMMING ************************************;
***** GET AGE DESCRIPTIVE STATISTICS N, MEAN, STD, MEDIAN, MIN, MAX.;
proc univariate 
   data = status noprint;
      var age;
      output out = age 
             n = _n mean = _mean std = _std  median = _median    min = _min max = _max;
run;

**** FORMAT AGE DESCRIPTIVE STATISTICS FOR THE TABLE.;
data age;
   set age;

   format n mean std min max $14.;
   drop _n _mean _std _min _max;

   n = put(_n,5.);
   mean = put(_mean,7.1);
   std = put(_std,8.2);
   median = put(_median,7.1);
   min = put(_min,5.);
   max = put(_max,5.);
run;

**** TRANSPOSE AGE DESCRIPTIVE STATISTICS INTO COLUMNS.;
proc transpose 
   data = age 
   out = age 
   prefix = col;
      var n mean std median min max;
run; 

**** CREATE AGE FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   label = "#S={font_weight=bold} Age (years)";
run;
 
**** APPEND AGE DESCRIPTIVE STATISTICS TO AGE P VALUE ROW AND 
**** CREATE AGE DESCRIPTIVE STATISTIC ROW LABELS.; 
data age;
   length label $ 85 col1 $ 25 ;
   set label age;

   keep label col1 ;
   if _n_ > 1 then 
      select;
         when(_NAME_ = 'n')    label = "#{nbspace 6}N";
         when(_NAME_ = 'mean') label = "#{nbspace 6}Mean";
         when(_NAME_ = 'std')  label = "#{nbspace 6}SD";
		 when(_NAME_= 'median') label = "#{nbspace 6}Median";
         when(_NAME_ = 'min')  label = "#{nbspace 6}Min";
         when(_NAME_ = 'max')  label = "#{nbspace 6}Max";
         otherwise;
      end;
run;
**** END OF AGE STATISTICS PROGRAMMING *****************************;

**** AGE GROUP STATISTICS PROGRAMMING ******************************;
**** GET SIMPLE FREQUENCY COUNTS FOR AGE GROUP.;
proc freq 
   data = status 
  noprint;
      tables agecat / out = agecat;
run;

 **** FORMAT AGE GROUP N(%) AS DESIRED.;
data agecat;
      set agecat;
      length value $25;
	  value = put(count,4.) || ' (' || put(percent,5.1)||'%)'; 
run;

proc sort
   data = agecat ;
      by agecat;
run;

**** TRANSPOSE THE AGE GROUP SUMMARY STATISTICS.;
proc transpose 
   data = agecat 
   out = agecat (drop = _name_) 
   prefix = col;
      by agecat;
      var value;
run;

**** CREATE AGE GROUP FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   		label = "#S={font_weight=bold} Age Group: N (%)";
run;

data agecat;
   length label $ 85 col1 $ 25 ;
   set label agecat;

   keep label col1 ;
   if _n_ > 1 then 
        label= "#{nbspace 6}" || put(agecat,agecatf.);
run;
**** END OF AGE GROUP STATISTICS PROGRAMMING *****************************;

**** SEX STATISTICS PROGRAMMING ************************************;
**** GET SIMPLE FREQUENCY COUNTS FOR SEX.;
proc freq 
   data = status 
  noprint;
      tables sex / out = sex;
run;

 **** FORMAT SEX N(%) AS DESIRED.;
data sex;
   set sex;
      length value $25;
      value = put(count,4.) || ' (' || put(percent,5.1)||'%)';
run;

proc sort
   data = sex;
      by sex;
run;

**** TRANSPOSE THE SEX SUMMARY STATISTICS.;
proc transpose 
   data = sex 
   out = sex (drop = _name_) 
   prefix = col;
      by sex;
      var value;
run;

**** CREATE SEX FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   		label = "#S={font_weight=bold} Gender: N (%)";
run;

data sex;
   length label $ 85 col1 $ 25 ;
   set label sex;

   keep label col1 ;
   if _n_ > 1 then 
        label= "#{nbspace 6}" || put(sex,sexf.);
run;
**** END OF SEX STATISTICS PROGRAMMING *****************************;

**** CHILDBEARING POTENTIAL STATISTICS PROGRAMMING **************;
**** GET SIMPLE FREQUENCY COUNTS FOR CHILDBEARING POTENTIAL.;
proc freq 
   data = status 
  noprint;
  where sex=2;
      tables childpot / out = childpot;
run;

 **** FORMAT CHILDBEARING POTENTIAL N(%) AS DESIRED.;
data childpot;
   set childpot;
      length value $25;
      value = put(count,4.) || ' (' || put(percent,5.1)||'%)';
run;

proc sort
   data = childpot;
      by descending childpot;
run;

**** TRANSPOSE THE CHILDBEARING POTENTIAL SUMMARY STATISTICS.;
proc transpose 
   data = childpot 
   out = childpot (drop = _name_) 
   prefix = col;
      by descending childpot;
      var value;
run;

**** CREATE CHILDBEARING POTENTIAL FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   		label = "#S={font_weight=bold} Childbearing Potential: N (%) [a]";
run;

data childpot;
   length label $ 85 col1 $ 25 ;
   set label childpot;

   keep label col1 ;
   if _n_ > 1 then 
        label= "#{nbspace 6}" || put(childpot,noyesf.);
run;
**** END OF CHILDBEARING POTENTIAL STATISTICS PROGRAMMING ******; 

**** RACE STATISTICS PROGRAMMING ***********************************;
**** GET SIMPLE FREQUENCY COUNTS FOR RACE;
proc freq 
   data = status 
   noprint;
      tables ethnic / out = ethnic;
run;
 
**** FORMAT RACE N(%) AS DESIRED;
data ethnic;
      length value $ 25 ;
      value = put (count,4.) || ' (' || put(percent,5.1) || '%)' ; output;
	  ethnic=_n_; count=0; percent=0; value = '0 (00,0%)'; output;
run;

proc sort
   data = ethnic nodupkey;
      by ethnic;
run;
 
**** TRANSPOSE THE RACE SUMMARY STATISTICS;
proc transpose 
   data = ethnic 
   out = ethnic(drop = _name_) 
   prefix=col;
      by ethnic;
      var value;
run;
 
**** CREATE RACE FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   		label = "#S={font_weight=bold} Ethnic Origin: N (%)";
run;

**** APPEND RACE DESCRIPTIVE STATISTICS TO RACE P VALUE ROW AND 
**** CREATE RACE DESCRIPTIVE STATISTIC ROW LABELS.; 
data ethnic;
   length label $ 85 col1 $ 25 ;
   set label ethnic;

   keep label col1;
   if _n_ > 1 then 
        label= "#{nbspace 6}" || put(ethnic,ethnicf.);
run;
**** END OF RACE STATISTICS PROGRAMMING *******************************;

**** HEIGHT STATISTICS PROGRAMMING ************************************;
***** GET HEIGHT DESCRIPTIVE STATISTICS N, MEAN, STD, MEDIAN, MIN, MAX.;
proc univariate 
   data = status noprint;
      var height;
      output out = height 
             n = _n mean = _mean std = _std  median = _median    min = _min max = _max;
run;

**** FORMAT HEIGHT DESCRIPTIVE STATISTICS FOR THE TABLE.;
data height;
   set height;

   format n mean std min max $14.;
   drop _n _mean _std _min _max;

   n = put(_n,5.);
   mean = put(_mean,7.1);
   std = put(_std,8.2);
   median = put(_median,7.1);
   min = put(_min,5.);
   max = put(_max,5.);
run;

**** TRANSPOSE HEIGHT DESCRIPTIVE STATISTICS INTO COLUMNS.;
proc transpose 
   data = height 
   out = height 
   prefix = col;
      var n mean std median min max;
run; 

**** CREATE HEIGHT FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   label = "#S={font_weight=bold} Height (cm)";
run;
 
**** APPEND HEIGHT DESCRIPTIVE STATISTICS TO AGE P VALUE ROW AND 
**** CREATE HEIGHT DESCRIPTIVE STATISTIC ROW LABELS.; 
data height;
   length label $ 85 col1 $ 25 ;
   set label height;

   keep label col1 ;
   if _n_ > 1 then 
      select;
         when(_NAME_ = 'n')    label = "#{nbspace 6}N";
         when(_NAME_ = 'mean') label = "#{nbspace 6}Mean";
         when(_NAME_ = 'std')  label = "#{nbspace 6}SD";
		 when(_NAME_= 'median') label = "#{nbspace 6}Median";
         when(_NAME_ = 'min')  label = "#{nbspace 6}Min";
         when(_NAME_ = 'max')  label = "#{nbspace 6}Max";
         otherwise;
      end;
run;
**** END OF HEIGHT STATISTICS PROGRAMMING *****************************;

**** WEIGHT STATISTICS PROGRAMMING ************************************;
***** GET WEIGHT DESCRIPTIVE STATISTICS N, MEAN, STD, MEDIAN, MIN, MAX.;
proc univariate 
   data = status noprint;
      var weight;
      output out = weight 
             n = _n mean = _mean std = _std  median = _median    min = _min max = _max;
run;

**** FORMAT WEIGHT DESCRIPTIVE STATISTICS FOR THE TABLE.;
data weight;
   set weight;

   format n mean std min max $14.;
   drop _n _mean _std _min _max;

   n = put(_n,5.);
   mean = put(_mean,7.1);
   std = put(_std,8.2);
   median = put(_median,7.1);
   min = put(_min,5.);
   max = put(_max,5.);
run;

**** TRANSPOSE WEIGHT DESCRIPTIVE STATISTICS INTO COLUMNS.;
proc transpose 
   data = weight
   out = weight 
   prefix = col;
      var n mean std median min max;
run; 

**** CREATE WEIGHT FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   label = "#S={font_weight=bold} Weight (kg)";
run;
 
**** APPEND WEIGHT DESCRIPTIVE STATISTICS TO AGE P VALUE ROW AND 
**** CREATE WEIGHT DESCRIPTIVE STATISTIC ROW LABELS.; 
data weight;
   length label $ 85 col1 $ 25 ;
   set label weight;

   keep label col1 ;
   if _n_ > 1 then 
      select;
         when(_NAME_ = 'n')    label = "#{nbspace 6}N";
         when(_NAME_ = 'mean') label = "#{nbspace 6}Mean";
         when(_NAME_ = 'std')  label = "#{nbspace 6}SD";
		 when(_NAME_= 'median') label = "#{nbspace 6}Median";
         when(_NAME_ = 'min')  label = "#{nbspace 6}Min";
         when(_NAME_ = 'max')  label = "#{nbspace 6}Max";
         otherwise;
      end;
run;
**** END OF WEIGHT STATISTICS PROGRAMMING *****************************;

**** DURATION OF MS (DOMS) STATISTICS PROGRAMMING ************************************;
***** GET WEIGHT DESCRIPTIVE STATISTICS N, MEAN, STD, MEDIAN, MIN, MAX.;
proc univariate 
   data = status noprint;
      var durms;
      output out = durms 
             n = _n mean = _mean std = _std  median = _median    min = _min max = _max;
run;

**** FORMAT DOMS DESCRIPTIVE STATISTICS FOR THE TABLE.;
data durms;
   set durms;

   format n mean std min max $14.;
   drop _n _mean _std _min _max;

   n = put(_n,5.);
   mean = put(_mean,7.1);
   std = put(_std,8.2);
   median = put(_median,7.1);
   min = put(_min,5.);
   max = put(_max,5.);
run;

**** TRANSPOSE DOMS DESCRIPTIVE STATISTICS INTO COLUMNS.;
proc transpose 
   data = durms
   out = durms 
   prefix = col;
      var n mean std median min max;
run; 

**** CREATE DOMS FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   label = "#S={font_weight=bold} Duration of MS (years)";
run;
 
**** APPEND DOMS DESCRIPTIVE STATISTICS TO AGE P VALUE ROW AND 
**** CREATE DOMS DESCRIPTIVE STATISTIC ROW LABELS.; 
data durms;
   length label $ 85 col1 $ 25 ;
   set label durms;

   keep label col1 ;
   if _n_ > 1 then 
      select;
         when(_NAME_ = 'n')    label = "#{nbspace 6}N";
         when(_NAME_ = 'mean') label = "#{nbspace 6}Mean";
         when(_NAME_ = 'std')  label = "#{nbspace 6}SD";
		 when(_NAME_= 'median') label = "#{nbspace 6}Median";
         when(_NAME_ = 'min')  label = "#{nbspace 6}Min";
         when(_NAME_ = 'max')  label = "#{nbspace 6}Max";
         otherwise;
      end;
run;
**** END OF DOMS STATISTICS PROGRAMMING *****************************;

**** DOMS GROUP STATISTICS PROGRAMMING ******************************;
**** GET SIMPLE FREQUENCY COUNTS FOR DOMS GROUP.;
proc freq 
   data = status 
  noprint;
      tables durmscat / out = durmscat;
run;

 **** FORMAT DOMS GROUP N(%) AS DESIRED.;
data durmscat;
   set durmscat;
      length value $25;
      value = put(count,4.) || ' (' || put(percent,5.1)||'%)'; output;
	  durmscat=_n_; count=0; percent=0; value = ' 0 (00,0%)'; output;
run;

proc sort
   data = durmscat nodupkey;
      by durmscat;
run;

**** TRANSPOSE THE DOMS GROUP SUMMARY STATISTICS.;
proc transpose 
   data = durmscat 
   out = durmscat (drop = _name_) 
   prefix = col;
      by durmscat;
      var value;
run;

**** CREATE DOMS GROUP FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   		label = "#S={font_weight=bold} Duration of MS (years): N (%)";
run;

data durmscat;
   length label $ 85 col1 $ 25 ;
   set label durmscat;

   keep label col1 ;
   if _n_ > 1 then 
        label= "#{nbspace 6}" || put(durmscat,mscatf.);
run;
**** END OF DOMS GROUP STATISTICS PROGRAMMING *****************************;

**** EDSS STATISTICS PROGRAMMING ************************************;
***** GET EDSS DESCRIPTIVE STATISTICS N, MEAN, STD, MEDIAN, MIN, MAX.;
proc univariate 
   data = status noprint;
      var edss;
      output out = edss 
             n = _n mean = _mean std = _std  median = _median    min = _min max = _max;
run;

**** FORMAT EDSS DESCRIPTIVE STATISTICS FOR THE TABLE.;
data edss;
   set edss;

   format n mean std min max $14.;
   drop _n _mean _std _min _max;

   n = put(_n,5.);
   mean = put(_mean,7.1);
   std = put(_std,8.2);
   median = put(_median,7.1);
   min = put(_min,5.);
   max = put(_max,5.);
run;

**** TRANSPOSE EDSS DESCRIPTIVE STATISTICS INTO COLUMNS.;
proc transpose 
   data = edss 
   out = edss 
   prefix = col;
      var n mean std median min max;
run; 

**** CREATE EDSS FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   label = "#S={font_weight=bold} EDSS Score";
run;
 
**** APPEND EDSS DESCRIPTIVE STATISTICS TO AGE P VALUE ROW AND 
**** CREATE EDSS DESCRIPTIVE STATISTIC ROW LABELS.; 
data edss;
   length label $ 85 col1 $ 25 ;
   set label edss;

   keep label col1 ;
   if _n_ > 1 then 
      select;
         when(_NAME_ = 'n')    label = "#{nbspace 6}N";
         when(_NAME_ = 'mean') label = "#{nbspace 6}Mean";
         when(_NAME_ = 'std')  label = "#{nbspace 6}SD";
		 when(_NAME_= 'median') label = "#{nbspace 6}Median";
         when(_NAME_ = 'min')  label = "#{nbspace 6}Min";
         when(_NAME_ = 'max')  label = "#{nbspace 6}Max";
         otherwise;
      end;
run;
**** END OF EDSS STATISTICS PROGRAMMING *****************************;

**** EDSS GROUP STATISTICS PROGRAMMING ******************************;
**** GET SIMPLE FREQUENCY COUNTS FOR EDSS GROUP.;
proc freq 
   data = status 
  noprint;
      tables edsscat / out = edsscat;
run;

 **** FORMAT EDSS GROUP N(%) AS DESIRED.;
data edsscat;
   set edsscat;
      length value $25;
      value = put(count,4.) || ' (' || put(percent,5.1)||'%)'; output;
	  edsscat=_n_; count=0; percent=0; value = '0(0,0%)';output;
run;

proc sort
   data = edsscat nodupkey;
      by edsscat;
run;

**** TRANSPOSE THE EDSS GROUP SUMMARY STATISTICS.;
proc transpose 
   data = edsscat 
   out = edsscat (drop = _name_) 
   prefix = col;
      by edsscat;
      var value;
run;

**** CREATE EDSS GROUP FIRST ROW FOR THE TABLE.;
data label;
   length label $ 85 col1 $ 25;
   		label = "#S={font_weight=bold} EDSS Score: N (%)";
run;

data edsscat;
   length label $ 85 col1 $ 25 ;
   set label edsscat;

   keep label col1 ;
   if _n_ > 1 then 
        label= "#{nbspace 6}" || put(edsscat,edsscatf.);
run;
**** END OF EDSS GROUP STATISTICS PROGRAMMING *****************************;

**** CONCATENATE AGE, SEX, AND RACE STATISTICS AND CREATE GROUPING
**** GROUP VARIABLE FOR LINE SKIPPING IN PROC REPORT.;
data forreport;
   set age(in = in1)
   		 agecat(in = in2)
		 sex(in = in3)
		 childpot(in = in4)
         ethnic(in = in5)
		 height(in = in6)
		 weight(in = in7)
		durms(in = in8)
		durmscat(in = in9)
		edss(in = in10)
		edsscat(in = in11);

       group = sum(in1*1,in2*2,in3*3,in4*4,in5* 5,in6*6,in7*7,in8*8,in9*9,in10*10,in11*11);
run;

**** DEFINE THREE MACRO VARIABLES &N0 THAT  IS USED IN 
**** THE COLUMN HEADER: N;
data _null_;
   set status end=eof;

   **** CREATE COUNTER FOR N0;
   if age > 0 then
      n0 + 1;
   
	  **** CREATE MACRO VARIABLES &N0;
   if eof then
      do;     
         call symput("n0",compress('(N='||put(n0,4.)||')'));
      end;
run;

**** DATE AND TIME MACROS****************************************; 
%let DATE=%sysfunc(today(),date9.);
%put &DATE;
%let TIME=%sysfunc(time(),hhmm.);
%put &TIME;

**** USE PROC REPORT TO WRITE THE DEMOGRAPHICS TABLE TO FILE.; 
options nodate nonumber missing = ' ' orientation = landscape;
ods escapechar='#';
ods pdf style=journal file='Table1.pdf' ;

proc report
   data=forreport
   nowindows
   spacing=1
   headline
   headskip
   split = "|";

   columns (group label col1);

   define group   /order order = internal noprint;
   define label   /display "Parameter|Statistic";
   define col1    /display style (column)=[asis=on] "|&n0";
 
  compute after group;
      line '#{newline}';
   endcomp;

title1 h=1.3 j=l 'Schwarz Pharma, Inc.' j=r 'DATE:' &DATE &TIME; 
title2 h=1.3 j=l 'Protocol SP843'           j=r 'Page #{thispage} of #{lastpage}'; 
title3 h=1.3 j=l 'KEMSTRO'                  j=r 'PGM:Table1.SAS'; 

title5 h=1.3 j=c 'Table 14.1.4';
title6 h=1.3 j=c 'Demographics and Baseline Characteristics';
title7 h=1.3 j=c 'Safety Population';

   footnote1 j=l 'Note: Percentages are based on the number of subjects in the Safety population, unless specified otherwise.';
   footnote2 j=l "[a] Counts and percentages are based on the number of female subjects.";
   footnote4 j=l "Source: Appendix 16.2.5 and 16.2.6";  
run; 

ods pdf close;

proc datasets;
		delete age;
		delete agecat;
		delete childpot;
		delete durms;
		delete durmscat;
		delete edss;
		delete edsscat;
		delete ethnic;
		delete height;
		delete label;
		delete safe;
		delete sex;
		delete weight;
run; 

title;
footnote;
ods listing close;
ods pdf close;

 

Attachment
Attachment
Attachment
SAS Super FREQ
Posts: 8,720

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

Hi:

  Here are some observations about your posting. Your questions were:

 

1. The table should be output in 'clear' .txt format. When I use simple ODS Listing 'File.txt' I loss measures of the columns and lines.

ODS LISTING is not the same look and feel as ODS PDF or ODS RTF. So while I am not sure what you mean by the loss of measures of columns and lines, I suspect that you are finding that commands like #{thispage} and #{lastpage}, #{nbspace} and '#S={font_weight=bold} Age (years)' are ignored by ODS LISTING. Totally. Ignored. Not used. At all.

 

This is because the inline formatting commands that you use with ODS ESCAPECHAR of # are completely ignored by ODS LISTING. Those commands will ONLY work with PDF, RTF and HTML destinations -- destinations that support style (colors, fonts, bolding, etc). ODS LISTING is a plain ASCII text file, there are no colors, there are no fonts, there is no bold style in ODS LISTING outptut. So what you are trying might work for ODS PDF or ODF RTF but will NOT work for ODS LISTING.

 

2. I lost some observations that have 0% - some Ethics Origins, Durations of MS (years): N (%), EDSS Score: N (%). You can see when run Format file: progfmt.fmt - attached.

I don't understand "losing observations" if you mean that for example, the data only some missing categories -- for example. let's say that in some studies, you can have the possibility of 3 groups: Group1, Group2 and Group3. But in one dataset, you have all 3 groups and in another dataset you only have Group1 and Group3. If you need to see Group2 on the report with 0%, then that is something you can do using PRELOADFMT to get the 0% in your output dataset -- sometimes people will generate their summary data using the option so the 0% is automatically included sometimes people will "seed" the summarized data with the extra rows that they know are misting. I'm not sure what is needed in your case.

 

  

3. I was not able to put titles in Listing, not pdf. What are the common rules to implement it? Should I simply measure my page and place the title exactly where I calculate it?

I am not sure what you mean by "measure your page". If you consider my output (which is a revision of my demog1 program from my 2008 paper), I do see that titles are appearing in the TXT and the RTF output.

 

4. All dots of decimal shuld be alined in one line? How could it be realized?

My decimals are aligned in both outputs.

 

5. How to orient the pages in Landscape orientation, not portrait?

options orientation=landscape; Also, for listing, you may need to change LS and PS options.

 

Here is the output from my 2008 paper, redone using Courier New as the font and side by side with the ODS LISTING version of the same output. As you see, ODS style controls and ESCAPECHAR controls are ignored by ODS LISTING.

 

cynthia

compare_rtf_listing.png

 

(code is in attached program file, with a DATALINES section that makes data)

 

 

Attachment
Occasional Contributor
Posts: 13

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

[ Edited ]

Today I was working with the second table. Here it is the code. And I have added the original dataset.

****EXTRACTING DATA FROM ARCHIVED DATASETS************************;
libname xpt xport 'C:\Users\Dmytro\Documents\SAS exam\CS Update\sas\cmed_dvd.xpt';
proc copy
	in=xpt out=work;
run;
libname xpt clear;

libname xpt xport 'C:\Users\Dmytro\Documents\SAS exam\CS Update\sas\status.xpt';
proc copy
	in=xpt out=work;
run;
libname xpt clear;

****SORTING CMED_DVD**************************************************;
proc sort data=cmed_dvd;
		by site pt;
run;

****BUILDING DATASET WITH SEQNO=1 AND SAFETY=2**********************;
proc sql;
	create table kemstro_baklofen as
    select site, pt, verbatim, prefterm, atcterm, presbase, studstrt, durstud,cont  
	from cmed_dvd
	where pt in (select pt
						from status
						where safety=2 and seqno=1)
	order by site pt;

****BUILDING DATASET WITH SEQNO=2 AND SAFETY=2***********************;
proc sql;
	create table baklofen_kemstro as
    select site, pt, verbatim, prefterm, atcterm, presbase, studstrt, durstud,cont  
	from cmed_dvd
	where pt in (select pt
						from status
						where safety=2 and seqno=2)
order by site pt;

****BUILDING FILE KEMSTO/BAKLOFEN FOR LISTING****************************;
data kem_bak (drop=site pt medication presbase studstrt durstud cont verbatim prefterm atcterm);

	set kemstro_baklofen;
			
				site1=site; pt1=pt; medication1='V:'||verbatim;
				presbase1=put(presbase,noyesf.); studstrt1=put(studstrt,noyesf.);
				durstud1=put(durstud,noyesf.); cont1=put(cont,noyesf.); output;

					site1=''; pt1='';medication1='P:'||prefterm;
					presbase1=''; studstrt1='';
					durstud1=''; cont1=''; output;

						site1=''; pt1='';medication1='C:'||atcterm;
						presbase1=''; studstrt1='';
						durstud1=''; cont1=''; output;
	run; 

****BUILDING FILE BAKLOFEN/KEMSTO FOR LISTING****************************;
data bak_kem (drop=site pt medication presbase studstrt durstud cont verbatim prefterm atcterm);

	  set baklofen_kemstro;
		  
				site1=site; pt1=pt; medication1='V:'||verbatim;
				presbase1=put(presbase,noyesf.); studstrt1=put(studstrt,noyesf.);
				durstud1=put(durstud,noyesf.); cont1=put(cont,noyesf.); output;

					site1=''; pt1='';medication1='P:'||prefterm;
					presbase1=''; studstrt1='';
					durstud1=''; cont1=''; output;

						site1=''; pt1='';medication1='C:'||atcterm;
						presbase1=''; studstrt1='';
						durstud1=''; cont1=''; output;

****PRINTING REPORTS TO FILES***********************************************;
ods listing file='C:\Users\Dmytro\Documents\SAS exam\CS Update\sas\Table2.txt';

proc print data=kem_bak noobs; run; proc print data=bak_kem noobs; run; ods listing close; proc datasets; delete bak_kem; delete kem_bak; delete baklofen_kemstro; delete baklofen_kemstro; quit;

 

Attachment
SAS Super FREQ
Posts: 8,720

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

Hi:
I don't see any report code except for PROC PRINTS which you seem to be sending to ODS LISTING and also to ODS PDF. I expect that you will find the ODS PDF output and the ODS LISTING output look different. I am not sure why you do not have a FILE= option for the ODS PDF step.

You only posted your code and the zip file. Is there a problem or error in your code?

cynthia
Occasional Contributor
Posts: 13

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

[ Edited ]

I have removed 'ods pdf' as it was put by mistake. I faced two issues in Table 2:

 1. Headers are not placed 'right' and 'left'. Ones were placed correctly in pdf format, but in listing it was failed. What could be a reason?

 2. I am printing two datasets in one text file. The first part(from the first dataset) has to be headed as 'TREATMENT SEQUENCE = KEMSTRO/BACLOFEN', the second - as  'TREATMENT SEQUENCE = BACLOFEN/KEMSTRO'. The second part should begin from a new page. I have not found a decision. Could you please suggest?

 

As for the first Table - I failed with PRELOADFMT option but still am tryring. Plus the same issue with the titles - ones could not be placed right and left.

SAS Super FREQ
Posts: 8,720

Re: ODS for the clinical trial report (Appendix 16.2.5 and 16.2.6)

[ Edited ]

Hi:
About #1, as I illustrated in my previous post just because code produces one result when used with PDF does not mean you will get the same results in the ASCII text file created by ODS LISTING. In fact, in my screen shot, I highlighted places in the TXT output that showed some crucial differences. Which headers are not placed RIGHT or LEFT? When you are using ODS LISTING and PROC PRINT if you are trying to use j=r and j=l in your TITLE or FOOTNOTE statement, those are style attributes that do NOT work for ODS LISTING.

So, if you had a title statement like this:
title j=l 'Left' j=c 'Center' j=r 'Right';
In ODS LISTING output, you would see this:
LeftCenterRight

That is because ODS LISTING does not use ANY style attributes in the TITLE statement. If that's what you mean by Headers, then the ODS LISTING output is working as it should work.

For your question #2, you say that the first part, from the first dataset has to be "headed" a certain way and then the second page has to be "headed" a certain way. When I run a test using ODS LISTING, I do see titles in my output. The code that created the image is shown underneath the image. I did not use your data because to illustrate page breaks and titles, I can use any dataset with PROC PRINT. Notice how, when I view the TXT file in Notepad, I do not really see separate "pages" except for the fact that I explicitly turned numbering on so I would see a SAS page number in the output. And over on the right side of the page 2 line, you see a little squiggly character that represents the "page feed", "line feed" or "carriage return" or "carriage control" character that indicates that when you print or open this file in a word processor, that a page break should go at this location.

 

When I open the same TXT file in Microsoft Word and go into Reading View, you can see that Word has correctly interpreted this squiggly character as being the start of a new page.

 

So I am not sure what to advise, because, again, ODS LISTING is working as it is supposed to work. For more in-depth help you might want to work with Tech Support and reference this track. In my previous posting (before this one) I showed how you could get bold and titles and indentings with ODS RTF and a fixed pitch font like Courier. You cannot force ODS LISTING to behave like PDF or RTF.

options nodate number orientation=portrait pageno=1;
  
ods listing file='c:\temp\titletest.txt';
  
title 'TREATMENT SEQUENCE = KEMSTRO/BACLOFEN';
proc print data=sashelp.class noobs;
run;
  
title 'TREATMENT SEQUENCE = BACLOFEN/KEMSTRO';
proc print data=sashelp.shoes noobs;
run;
ods listing close;



cynthia

 

compare_txt_file_title_notepad_vs_word.png

Ask a Question
Discussion stats
  • 22 replies
  • 1504 views
  • 5 likes
  • 3 in conversation