sa2tex

Michael Friendly (friendly@hotspur.psych.yorku.ca)
Mon, 26 Jan 98 17:15:09 -0500


Here's a simple sas macro which produces a LaTeX table from a SAS data set.
You usually have to edit the result, but it does most of the hard work.
-Michael

/*-------------------------------------------------------------------*
* Name: sas2tex.sas *
* Title: Generate a LaTeX table from a SAS dataset *

*-------------------------------------------------------------------*
* Author: Michael Friendly <friendly@yorku.ca>;
* Created: 25 Jan 1998 12:00:27
* Revised: 26 Jan 1998 17:11:24
* Version 1.0
* -- Handles only simple tables (no multicolumn, cline, etc)
* -- Determines reasonable formats, column labels, justification
* from the data set info.
* -- Added where= option to select observations
* -- Added by= option for multiple tables
*-------------------------------------------------------------------*/

%macro sas2tex(
data=_last_, /* name of input dataset */
vars=, /* list of variables to be printed */
just=, /* var justification: rrrlllcc */
miss=, /* what to print for missing data */

where=, /* where clause, use where=%str(var=val) */
by=, /* separate tables for each by value */
out=FILE, /* output fileref: FILE, PRINT, STDOUT */
outdir=./, /* directory for output file */
outfile=, /* name of output TeX file */
tabid=tab:&data, /* table \label{} value */
tabpos=htb, /* table float position */
tabenv=, /* table environment, eg, \small */
id=, /* ID variable, or _NULL_ */

caption=, /* table caption text */

ls=80 /* output linesize */

);

%*-- Output is either to a file (fileref TeXOUT) or to the listing
(fileref PRINT). If FILE, try to assign default name based on
operating system. Not very general here (due to wide variety of
values that &sysscp can take on);

%if %nrbquote(%upcase(&out))=FILE %then %do;
%if &outfile eq %str() %then %do;
%let outfile = &data..tex;
%put NOTE: Output File Name was not specified, so writing to
&outfile.;
%end;
filename texout "&outdir.&outfile";
%let out=texout;
%end;

%*-- Get variable name, type, label & format info;
data _tmp_;
set &data;
stop;

%*** use summary to reorder the variables in order of var list;
proc summary data=_tmp_(firstobs=1 obs=1);
id &vars &id;
output out=_tmp1_(drop=_TYPE_ _FREQ_);

proc contents data=_tmp1_(keep=&vars &id) noprint

out=_vars_(keep=name type length label format formatl formatd npos);
run;
%*** sort by position of variables in the list;
proc sort data=_vars_;
by npos;
*proc print;

data _null_;
set _vars_ end=eof;
length aligni alignv align $100;
retain aligni alignv;

%*-- Store variable info in macro variables: name1, type1, etc;
call symput("name"||left(put(_n_,5.)),trim(name));
call symput("type"||left(put(_n_,5.)),put(type,1.));
call symput("len"||left(put(_n_,5.)),put(length,3.));
call symput("lab"||left(put(_n_,5.)),trim(label));

vars = upcase("&vars");
if type=1 /* numeric */
then if index(vars,trim(name))

then alignv=trim(alignv) || 'r';
else aligni=trim(aligni) || 'r';
else /* character */
if index(vars,trim(name))

then alignv=trim(alignv) || 'l';
else aligni=trim(aligni) || 'l';
put name= type= label= aligni= alignv= vars=;

if format=' ' then do;
if type=1 then format=" ";
else format="CHAR.";
end;
else do;
if formatl>0 then format = trim(format)
||trim(left(put(formatl,3.)));
format = trim(format)||'.';
if formatd>0 then format = trim(format)
||trim(left(put(formatd,3.)));
end;
call symput("fmt"||left(put(_n_,5.)),trim(format));
if eof then do;
call symput('nv', trim(left(put(_n_,5.))));
align = trim(aligni) || alignv;
call symput('align', trim(left(align)));
put align=;
end;
run;

data _null_;
set &data end=last;
length tabid $30;
%if &where ^= %str() %then %do;
where (&where);
%end;
%if &by ^= %str() %then %do;
by &by;
%end;

file &out notitle noprint lrecl=&ls;

%* -- Table header --;
%if &by ^= %str() %then %do;
if first.&by then do;
_by_+1;
tabid = trim("&tabid" || '-' || left(put(_by_,3.)));
%end;
%else %do;
if _n_=1 then do;
tabid = "&tabid";
%end;
put "\begin{table}[&tabpos]";
%if (%length(&tabenv)) %then %do;
put " {&tabenv";
%end;
put " \caption{&caption}";
put ' \label{' tabid +(-1) '}';
put ' \begin{center}';
put " \begin{tabular}{&align}";

%if &by ^= %str() %then %do;
put _by_;
%end;
%header(&id,&vars);
end; /* end first.&by or _n_=1 */

%*-- Print the table rows;
%row(&id,&vars);

%*-- Finish up;
if last

%if &by ^= %str() %then %do;
| last.&by
%end;
then do;
put ' \hline';
put ' \end{tabular}';
put ' \end{center}';
%if (%length(&tabenv)) %then %do;
put " }";
%end;
put '\end{table}';
end;
run;
%done:;

%mend;

%macro row(id,varlist);
%global cols;
%*-- Use <th> for ID variable --> font=bold;
%if &id ^= _NULL_ %then %do;
%if &id = %str() %then %do;
put @6 _n_ '& ' @;
%end;
%else %do;
put @6 &id '& ' @;
%end;
%end;

%do i = 1 %to &cols;
%let var = %scan(&varlist, &i);
type = &&type&i;
if type=1 then do;
if &var = .

then put &miss @;
else put &var &&fmt&i @;
end;
else do;
put &var &&fmt&i @;
end;
%if &i < &cols %then %do;
put '& ' @;
%end;
%end;
put ' \\';
%mend;

%macro header(id, varlist);
%global cols;
%let cols = %numwords(&varlist);
length var $40;
%*-- Output header cells for variable names or labels;
put @6 '\hline';
%if &id ^= _NULL_ %then %do;
%if &id = %str() %then %do;
put @6 'Obs &' @;
%end;
%else %do;
%let i=%eval(&cols+1);
var = "&&lab&i";
if var = ' ' then /* only
handles one id var */
var = "&id";
put @6 var '&' @;
%end;
%end;

%do i = 1 %to &cols;
%* -- Use variable label if it exists;
var = "&&lab&i";
if var = ' ' then
var = "%scan(&varlist, &i)";
put ' ' var @;
%if &i < &cols %then %do;
put '& ' @;
%end;
%end;
put ' \\';
put @6 '\hline';
%mend;

%macro numwords(lst,wordchar);
%let i = 1;
%if (%length(&wordchar)) %then %do;
%let v = %scan(&lst,&i,&wordchar);
%do %while (%length(&v) > 0);
%let i = %eval(&i + 1);
%let v = %scan(&lst,&i,&wordchar);
%end;
%end;
%else %do;
%let v = %scan(&lst,&i);
%do %while (%length(&v) > 0);
%let i = %eval(&i + 1);
%let v = %scan(&lst,&i);
%end;
%end;
%eval(&i - 1)
%mend;