LISTSERV at the University of Georgia
Menubar Imagemap
Home Browse Manage Request Manuals Register
Previous messageNext messagePrevious in topicNext in topicPrevious by same authorNext by same authorPrevious page (September 2009, week 4)Back to main SAS-L pageJoin or leave SAS-L (or change settings)ReplyPost a new messageSearchProportional fontNon-proportional font
Date:         Sat, 26 Sep 2009 21:47:02 -0700
Reply-To:     xlr82sas <xlr82sas@AOL.COM>
Sender:       "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From:         xlr82sas <xlr82sas@AOL.COM>
Organization: http://groups.google.com
Subject:      Re: Who has got a clinical reporting system that runs from a
Comments: To: sas-l@uga.edu
Content-Type: text/plain; charset=ISO-8859-1

On Sep 25, 10:39 pm, RolandRB <rolandbe...@hotmail.com> wrote: > On Sep 26, 3:50 am, "Lou" <lpog...@hotmail.com> wrote: > > > > > > > ""Data _null_;"" <iebup...@GMAIL.COM> wrote in message > > >news:ce1fb7450909251350j15e6bc52g15836c37f4fa2783@mail.gmail.com... > > > > On 9/25/09, RolandRB <rolandbe...@hotmail.com> wrote: > > > > But if you > > > > have, say, a "core" macro to do descriptive stats and category counts > > > > with percentages and it is flexible enough to supply its output in a > > > > dataset then that gives you the chance to "validate" that macro and > > > > then the other reporting macros can call on its services.and avoid the > > > > complexity. It then allows you to have different sets of sas code/ > > > > reporting macros for different clients that call these "core" macros > > > > to do the work for them. > > > > Your "core" macros are called PROCS. PROC SUMMARY, FREQ and REPORT > > > come to mind. You will also need FORMAT and probably TRANSPOSE. > > > > No macros required. > > > It will probably come as no surprise that I agree with Data _null_ on this - > > I've said repeatedly here and elsewhere that 90% or more of the macros I've > > run up against in pushing 30 years using SAS are rubbish. They're > > overcomplicated, slow to execute, impossible to debug, etc. > > That matches with my own experience. > > > As far as validating a core set of macros is concerned, in theory I suppose > > that's possible. In practice, what I've seen is a set of validated macros > > in a global library. For a particular project, the global library is copied > > into the project macro library. And then happily amended to the point where > > there are dozens of versions of each macro, all with the same name, all > > doing something slightly different, and of course none of these variants > > were ever "validated". In some cases, the validated version is never used. > > I've seen that done. > > > And when the organization updates the SAS version, or adopts a new release > > of MS Office, or upgrades the OS, or worse yet makes a platform change (e.g. > > from Windows to Unix) the macros have to be validated all over again because > > all of these changes in the background can and do cause macros that worked > > fine to fail, or worse yet to appear to function but give results different > > from those before the change. > > They really need a test platform such that if any changes to SAS or > the platform software occur then the test suite is run again and > compared directly against the results of the previous run.- Hide quoted text - > > - Show quoted text -

Over the last few years I have moved away from complicated macros and set up what I call program templates. A program template is code designed so that a programmer can update the code and wrap the code in a macro. Wrapping is sometmes needed for mutiple reports. I alslo make a concerted effort to never write a macro over 60 lines long(I don't always succeed). If more than 60 lines consider a program template, FCMP or rarely two macros.

Even with 10,000 lines standard macros often cannot do these simple functions, which my program templates can easily do:

1. Different footnotes on each page. 2. Customized page splits (you decide manually or programatically when to create a new page. 3. Nesting with categories (multilabel) 4. Subscripting within cells 5. Easily change the oder or position of any item on any page. I could even put the Mean with the N(PCT) section

I have seen pharma demographic macros that generate 10,000 lines of code when mprint is turned on.

For a cleaner version of the code below see:

http://homepage.mac.com/magdelina/.Public/utl.html

UTL_TIPWEB

T000130 EASY WAY TO DO N(PCT) MEAN STD MEDIAN MIN MAX REPORTS - NOTE PRELOADFMT AND MULTILABEL FORMATS DUE TO RACE 48 LINES OF CODE

I do use macros for ods templates, so that output is standardized. Incidentall I strongly suggest programmers use the 100% width (outputwidth=100%) macro templates for landscape and portrait reports. I think a set of reports that do not constantly change width more esthetic. 100% width allows alignment of ods rtf text= or pretext= with the body of your report. The code below could be simplified using proc report line statements, however I had to box the body of the report and the titles and footnotes had to be outside of report. SAS does not provide a frame for boxing just the body of the report. Also it is very frustrating because compute blocks in proc report can only have one justification.

I wish I could make this easier to read. This is instructional code. I do use the hidden dragon, but you can work around that.

/* DUAL INDENTAION AND WHITE/NON-WHITE PLUS ALL OTHER RACE CODES (ZERO FILL FOR MISSING RACES) */ /* PAGE = THE PAGE WHERE RACE APPEARS */ /* ORDER= THE ORDER IS THE RANK ON THE PAGE */ /* THIS IS FOR INSTRUCTIONAL PURPOSES - CAN BE SIMPLIFIED */ /* THIS CAN BE SIMPLIFIED BY NORMALIZING THE DATA EARLIER SEE OTHER TEMPLATES */ options validvarname=upcase; /* important for some program templates that use transpose */ proc format; value sex 1 ='Page @01 @Order @01 @Sex - n (%) @\li360 Male' 2 ='Page @01 @Order @02 @Sex - n (%) @\li360 Female' ; /* race code note the dual indentation */ value rcd (multilabel) 1 ="Page @01 @Order @03 @Race - n (%) @\li360 White or Caucasian" 2, 3, 4, 5, 6, 7, 88 ="Page @01 @Order @04 @Race - n (%) @\li360 Non-White or Caucasian" 2 ="Page @01 @Order @05 @Race - n (%) @\li720 Black or African American" 3 ="Page @01 @Order @06 @Race - n (%) @\li720 Hispanic or Latino" 4 ="Page @01 @Order @07 @Race - n (%) @\li720 Asian" 5 ="Page @01 @Order @08 @Race - n (%) @\li720 Japanese" 6 ="Page @01 @Order @09 @Race - n (%) @\li720 American Indian or Alaska Native" 7 ="Page @01 @Order @10 @Race - n (%) @\li720 Native Hawaiian or Other Pacific Islander" 88 ="Page @01 @Order @11 @Race - n (%) @\li720 Other" ; value $univ 'WEIGHT_MEAN_STD' ="Page @02 @Order @01 @Weight @\li360 Mean(SD)" 'WEIGHT_MEDIAN' ="Page @02 @Order @02 @Weight @\li360 Median" 'WEIGHT_MIN_MAX' ="Page @02 @Order @03 @Weight @\li360 Min, Max"; ;run;

/* COMPUTE THE BIG Ns AND USE TABULATE TO GET N AND PERCENT AND UNIVARIATE STATISTICS */ proc sql;select resolve(catx(' ','%let',trt,'=%str({',trt,'} \line { N =',put(count(pat),2. -l),'});')) from utlinp.T000120_demog group by trt;quit;

ods output table(match_all=matall) =TabOut; proc tabulate data=utlinp.T000120_demog; format sex sex. rcd rcd.; var weight; class trt; class sex rcd/ preloadfmt mlf; tables trt sex rcd,trt*(n='Count'*f=7. colpctn='Percent'*f=pctfmt9.); tables trt*weight*(mean median std min max) / printmiss; run;quit;

/* CLEAN UP FOR PROC RDrgRT */ data Fix; retain Pge 0; keep Pge Odr Trt Mjr Mnr Ans; /* THIS IS ALL WE NEED FOR PROC REPRORT */ length Mjr Mnr Que Ans $100; set &matall end=dne; if dne then call symputx('MaxPge',put(Pge, 1.)); if _table_=1 then do; /* Count and Percent */ Que=coalescec(sex,rcd); /* Question */ Ans=catx(' ',put(n,5.),compress('('!!put(pctn_100,4.)!!')')); /* Answer */ Ans=translate (Ans,'0','.'); Link MjrMnr;

end; else if _table_=2 then do; /* univariate statistics */ Que=put('WEIGHT_MEAN_STD', $univ.); Ans=cats(put(WEIGHT_MEAN,7.1),' (',put(WEIGHT_STD, 8.2),')'); Link MjrMnr; Que=put('WEIGHT_MEDIAN', $univ.); Ans=put(WEIGHT_MEDIAN, 7.1); Link MjrMnr; Que=put('WEIGHT_MIN_MAX', $univ.); Ans=cats('(',put(WEIGHT_MIN,5.),', ',put(WEIGHT_MAX,5.),')'); /* hidden dragon */ Link MjrMnr;

end;

return;

MjrMnr: if lengthn(Que) >0; Odr=input(scan(Que,2,'@'),2.)*100+input(scan(Que,4,'@'), 2.); Pge=int(Odr/ 100); Mjr=left(scan(Que, 5,'@')); Mnr=left(scan(Que, 6,'@'));

Output;

return; run; proc sort data=Fix out=FixSrt; by Odr Mjr Mnr Trt; run; proc transpose data=FixSrt out=FixXpo(drop=_name_); by Pge Odr Mjr Mnr; var Ans; id Trt; run; ods rtf file="/home/regusers/local/utl/rtf/&sysuserid._t000130.rtf" style=amg_rtflan100; ods escapechar='^'; %macro twopge (PgeMax); %do Pge=1 %to &PgeMax; ods rtf prepage="^S={outputwidth=100% just=c font_size=11pt font_face=arial} {\tc Title line} ^R/RTF'\line' {(Safety Set)}";

proc rDrgrt data=FixXpo(where=(Pge=&Pge)) missing split='#'; cols Pge Mjr Mnr Drg Placebo; define Pge / order noprint order=data; define Mjr / order noprint order=data; define Mnr / display "\ql\li180 {Category}" style (column)={just=l cellwidth=40%}; define Drg / display "\qc {&Drg}" style (column)={just=c cellwidth=29%}; define Placebo/ display "\qc {&Placebo}" style (column)={just=c cellwidth=29%}; compute before Mjr / style={just=l pretext="\li180"}; ;

Lyn=Mjr; line Lyn $88.;

endcomp;

run;quit; ods rtf text="^S={outputwidth=100% just=r font_size=9pt} Page &Pge of &PgeMax"; %if &pge=2 %then %do; ods rtf text="^S={outputwidth=100% just=l font_size=9pt} {This footnote only appears on page two}";

%end; ods rtf text="^S={outputwidth=100% just=l font_size=8pt font_style=italic} {Standard Next to Last Footnote}"; ods rtf text="^S={outputwidth=100% just=l font_size=8pt font_style=italic} {Standard Last Footnote}";

%end; %mend twopge; %twopge (&MaxPge); ods rtf close;

There are other templates on my site.


Back to: Top of message | Previous page | Main SAS-L page