*! Write a matrix of statistics to a formatted table *! version 1.15 29apr2012 by John Luke Gallup jlgallup@pdx.edu * version 1.15: - changed version to keep in sync w/-outreg- 1.15 * version 1.14: - changed version to keep in sync w/-outreg- 1.14 * version 1.13: - recompiled l_cfrmt.mlib in Stata 10 for compatibility * version 1.12: - make table w/o -statmat- or -replay- (e.g. using -addrows-) * version 1.11: - allow -merge- and -append- with -replay- * version 1.10: - fixed bug when -ctitles- or -rtitles- too big in -replay- * version 1.09: - fixed bug where I forgot I had commented out BegTex() * version 1.08: - fixed bug in AddTitle to reset rows for ctitles or rtitles * version 1.07: - added help documentation for -landscape- and -a4- options * version 1.06: - fixed bug in MakeRCodes() * (maxdecpos was undefined if no decimal justification) * version 1.05: - fixed bug in BegTex() * version 1.04: - added -landscape- and -a4- options * version 1.03: - fixed bug to allow overwriting of file w/merge option * version 1.02: - fixed bug in Merge() when more than 1 column of new statistics * - removed typo in syntax statement for -vlstyle- & -spacebef- * options (in v1.01 only) program define frmttable version 10.1 syntax [using/], [Statmat(string) /// matrix of data for table SUBstat(int 0) /// # cols statmat that are substats Doubles(string) /// cols of statmat that're dbl stats DBLdiv(string) /// symbol dividing double stats ("-") SDec(string) /// decimal places of stats SFmt(string asis) /// numerical format of stats SQuarebrack /// square brackets, not parentheses BRackets(string asis) /// symbols to bracket substats noBRKet /// put no brackets on substats ANnotate(string) /// matrix of annotation locations ASymbol(string asis) /// symbols for annotations CTitles(string asis) /// headings at top of columns noCOltitl /// no ctitles RTitles(string asis) /// headings on left of each row noROwtitl /// no rtitles BLankrows /// allow blank rows of T.Body (don't drop them) FIndcons /// put _cons in separate sect. of tbl VArlabels /// use variable labels as rtitles Title(string asis) /// put title above table Note(string asis) /// put note below table PRetext(string asis) /// text placed before the table POsttext(string asis) /// text placed after the table ADdrows(string asis) /// add rows of data on bottom of tbl ADDRTc(int 0) /// no. of rtitle columns in addrows ADDCols(string asis) /// add cols of data to right of tbl Plain /// plain text: 1 font size, no just. noCEnter /// don't center table within page COLJust(string) /// column justification: left, center, or right HLines(string) /// horizontal lines between rows VLines(string) /// verticle lines between columns BAsefont(string asis) /// change the base font for all text TITLFont(string asis) /// change font for table title CTITLFont(string asis) /// change font for column titles RTITLFont(string asis) /// change font for row titles STATFont(string asis) /// change font for stats in table NOTEFont(string asis) /// change font for notes below table ADDTable /// place table below existing table MUlticol(string) /// ctitles span multiple columns ADDFont(string) /// add a new font type (word only) HLStyle(string) /// change style of horizontal lines VLStyle(string) /// change style of verticle lines SPACEBef(string) /// put space above cell* SPACEAft(string) /// put space below cell* SPACEHt(real 1) /// change space height COLWidth(numlist) /// change column widths (word only) LAndscape /// landscape page orientation A4 /// A4 paper size TEX /// write TeX format file FRagment /// create TeX fragment (tex only) Eq_merge /// merge rows w/same rtitles (eqns) Merge /// merge to previous frmttable Merge1(string) /// merge to frmttable `tblname' APpend /// append below previous frmttable APpend1(string) /// append below frmttable `tblname' STOre(string) /// store in Mata struct "tblname" REplay /// replay previous _FrmtT table REplay1(string) /// replay _FrmtT"tblname" table CLear /// clears _FrmtT - for loops w/merge CLear1(string asis) /// clears tblname - for loops w/merge replace /// replace previous file noDisplay /// no display tbl in results window DWide] // display all cols however wide * (word only) if ("`clear'`clear1'"!="") { if (`"`clear1'"'!="") local clear1 `"clear(`clear1')"' Clear `0' // clear _FrmtT } else { if (`"`merge'`merge1'`append'`append1'"') != "" { if ("`merge1'"!="") local merge = "merge" if ("`append1'"!="") local append = "append" if (("`merge'"!="") & ("`append'"!="")) { di as err "can specify either merge or append options, not both" exit 198 } if (`"`merge'`append'"'!="") local replace = "replace" } local wordoptv = `"`addfont'`colwidth'`hlstyle'`vlstyle'"' if ("`tex'"!="" & `"`wordoptv'"'!="") { // if (`"`addfont'`colwidth'"'!="") /// local wordopts = "addfont and/or colwidth" if (`"`hlstyle'`vlstyle'"'!="") /// local wordopts = "`wordopts' hlstyle and/or vlstyle" di as err `"option `wordopts' not allowed with tex option"' // exit 198 } if ("`tex'"=="" & "`fragment'"!="") { // di as err `"option fragment not allowed without tex option"' // exit 198 } // check table names for illegal characters local mrgappname = `"`merge1'`append1'"' foreach tbl in `store' `merge1' `append1' `replay1' { if (indexnot(`"`tbl'"', /// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_")| /// length(`"`tbl'"')>24) { di as err `"tblname `tbl' in option merge, replay, store, or append may only contain up to 24 letters, numbers, or "_""' exit 198 } } mata: _pFrmtTold = findexternal("_FrmtT`mrgappname'") // before FrmtFill // or AdjTitl creates pointer if ("`statmat'"!="") { if ("`store'"!="") local tblname "_FrmtT`store'" else local tblname "_FrmtT`mrgappname'" mata: `tblname' = FrmtFill("`statmat'",`substat',"`doubles'", /// "`dbldiv'",`"`sdec'"',`"`sfmt'"',("`squarebrack'"!=""), /// `"`brackets'"',("`brket'"!=""),`"`annotate'"',`"`asymbol'"', /// `"`ctitles'"',("`coltitl'"!=""),`"`rtitles'"',("`rowtitl'"!=""), /// ("`findcons'"!=""),("`varlabels'"!=""),`"`title'"',`"`note'"', /// `"`pretext'"',`"`posttext'"',`"`addrows'"',`addrtc', /// `"`addcols'"',("`eq_merge'"!=""),_pFrmtTold,("`merge'"!=""), /// ("`append'"!=""),("`tex'"!="")) } else { // i.e. replay or non-statmat content mata: _pFrmtT = findexternal("_FrmtT`replay1'") if ("`store'"!="") local tblname "_FrmtT`store'" else local tblname "_FrmtT`replay'" mata: `tblname' = Replay(_pFrmtT,("`replay'"!=""),"`replay1'", /// `"`title'"',`"`note'"',`"`ctitles'"',("`coltitl'"!=""), /// `"`rtitles'"',("`rowtitl'"!=""),`"`annotate'"',`"`asymbol'"', /// `"`pretext'"',`"`posttext'"',`"`addrows'"',`addrtc', /// `"`addcols'"',_pFrmtTold,("`merge'"!=""),("`append'"!=""), /// "`mrgappname'","`store'") mata: mata drop _pFrmtT } mata: mata drop _pFrmtTold if (`"`using'"'!="") mata: FrmtOut(`tblname',("`tex'"!=""), /// `"`using'"',("`replace'"!=""),("`plain'"!=""),("`center'"==""), /// `"`coljust'"',"`colwidth'",`"`multicol'"',("`blankrows'"==""), /// `"`hlines'"',`"`vlines'"',`"`hlstyle'"',`"`vlstyle'"', /// `"`spacebef'"',`"`spaceaft'"',`spaceht',`"`addfont'"', /// `"`basefont'"',`"`titlfont'"',`"`ctitlfont'"',`"`rtitlfont'"', /// `"`statfont'"',`"`notefont'"',("`landscape'"!=""),("`a4'"!=""), /// ("`addtable'"!=""),("`fragment'"!="")) // display table in Stata results window if ("`display'"=="") mata: FrmtDisplay(`tblname',("`dwide'"!=""), /// ("`blankrows'"=="")) } end // end of frmttable program define Clear version 10.1 // clear _FrmtT (for use with merge in loops) syntax , [CLear CLear1(string)] local tblname = "_FrmtT`clear1'" mata: _pFrmtT = findexternal("`tblname'") mata: st_local("nonull", strofreal(_pFrmtT!=NULL)) if `nonull' mata: mata drop `tblname' end // end of Clear version 10.1 mata: struct FrmtTabl { // structure holding table data string colvector Pretext string colvector Title string matrix Body real rowvector SectRows // # of rows in each (row) section of Body real rowvector SectSubstats // # of substats in (row) Sections real scalar ConsSect // has a (row) section for "_cons" from regressions real rowvector SectCols // # of columns in each (col) section of Body string colvector Note string colvector Posttext } /* struct FrmtBegEnd { // structure holding formatting codes (TeX, doc, etc) string colvector Title string matrix Body real rowvector SectRows // last row of sections in Body real rowvector SectCols // last column of sections in Body string colvector Note string colvector Top // codes before table text string colvector Tabular // codes for tabular structure string colvector EndTabular // codes at end of tabular structure string colvector Bottom // codes after table text } */ struct FrmtTabl scalar FrmtFill(string scalar statmat, real scalar substat, string scalar doubles, string scalar dbldiv, string scalar sdec, string scalar sfmt, real scalar squarebrack, string scalar brackets, real scalar nobrcket, string scalar annotate, string scalar asymbol, string scalar ctitles, real scalar noctitl, string scalar rtitles, real scalar nortitl, real scalar findcons, real scalar vlabels, string scalar title, string scalar note, string scalar pretext, string scalar posttext, string scalar addrows, real scalar addrtc, string scalar addcols, real scalar eq_merge, pointer(struct FrmtTabl scalar) scalar pTold, real scalar merge, real scalar append, real scalar tex) { // fill in FrmtTabl structure with data and text (returned as _FrmtT) struct FrmtTabl scalar T smat = st_matrix(statmat) sr = rows(smat); scd = cols(smat) // including double columns ns = substat+1 if (doubles!="") { dblmat = st_matrix(doubles); notdbl = !dblmat dbls = sum(dblmat) if (cols(dblmat)==0) { errprintf(`"matrix "%s" not found in doubles option\n"',doubles) exit(198) } if (cols(dblmat)!=scd) { errprintf(`"number of columns in "%s" not equal to columns in "%s"\n"', /// doubles,statmat) exit(198) } } else dbls = 0 sc = scd-dbls // without double columns tc = sc/ns // number of data columns in formatted table if (mod(sc,ns)>0) { // check that substat consistent with cols of statmat errprintf("number of statmat columns (ignoring doubles) not divisible") errprintf(" by 1+substat\n") exit(198) } // apply sdec and sfmt and convert smat to string matrix smatstr smatstr = strofreal(smat, FmtStr(sdec, sfmt, sr, sc, ns, dblmat)) // combine doubles columns, so smatstr becomes sr x sc if (dbls) smatstr = JoinDbl(smatstr, dblmat, dbldiv, sr, scd) // add brackets empty = J(sr,sc,".") // get rid of missing: "." if (!nobrcket & ns>1) { MakeBrac(squarebrack,brackets, sr, sc, ns, tex, lbracket="", rbracket="") smatstr = lbracket+smatstr+rbracket empty = lbracket+empty+rbracket } smatstr = subinword(smatstr,empty,J(sr,sc,"")) // add annotation symbols (e.g. asterisks for confidence levels) if (annotate!="") /// smatstr = smatstr + MakeSymb(annotate, asymbol, sr, sc) // rearrange multiequation results into multiple columns L=""; H="" // L & H may be filled by Eq_Merge if (eq_merge) smatstr = Eq_Merge(smatstr, statmat, findcons, L, H) // make left and column titles; findcons returned w/# rows of _cons T.ConsSect = findcons MakeRCTitles(rtitles, nortitl, ctitles, noctitl, /// statmat, vlabels, substat, findcons, dbls, notdbl, /// L,H,lc=0,hr=0) // fill T.Body with H, L, smatstr, addrows, and addcols FillBody(T,smatstr,substat,findcons,L,H,lc,hr, addrows,addrtc,addcols) if (pretext!="") T.Pretext = StrToCVec(pretext, "pretext") if (title!="") T.Title = StrToCVec(title, "title") if (note!="") T.Note = StrToCVec(note, "note") if (posttext!="") T.Posttext = StrToCVec(posttext, "posttext") if (merge | append) { if (pTold==NULL) printf("{txt}warning: no existing table found for merge or append\n") else if (merge) T = Merge((*pTold),T) else T = Append((*pTold),T) } return(T) } struct FrmtTabl scalar Replay(pointer(struct FrmtTabl scalar) scalar pT, real scalar replay, string scalar rpyname, string scalar title, string scalar note, string scalar ctitles, real scalar noctitl, string scalar rtitles, real scalar nortitl, string scalar annotate, string scalar asymbol, string scalar pretext, string scalar posttext, string scalar addrows, real scalar addrtc, string scalar addcols, pointer(struct FrmtTabl scalar) scalar pTmrgapp, real scalar merge, real scalar append, string scalar mrgappname, string scalar store) { // change titles in FrmtTabl for -replay- option, // merge or append with named table, and/or store w/ new name struct FrmtTabl scalar T if (mrgappname=="") mrgappname = "existing table" else mrgappname = "table named "+mrgappname if (pT==NULL) { if (pTmrgapp==NULL) { if (replay) { if (rpyname=="") /// printf(`"{err}error: no table exists for replay option\n"') else printf(`"{err}error: no table named "%s" exists for replay option\n"', /// rpyname) exit(198) } } else { printf("{txt}warning: no %s found with which to merge or append\n", /// mrgappname) T = *pTmrgapp } } else { T = *pT if (merge | append) { if (pTmrgapp==NULL) { printf("{err}error: no %s found to merge or append\n",mrgappname) exit(198) } else if (merge) T = Merge(T,(*pTmrgapp)) else T = Append(T,(*pTmrgapp)) } } if (pretext!="") T.Pretext = StrToCVec(pretext, "pretext") if (title!="") T.Title = StrToCVec(title, "title") if (note!="") T.Note = StrToCVec(note, "note") if (posttext!="") T.Posttext = StrToCVec(posttext, "posttext") if (ctitles!="" | rtitles!="" | noctitl | nortitl | annotate!="") { if (length(T.Body)==0) { // if _FrtmT is empty if (rtitles!="") L = StrToMat(rtitles, "rtitles") else L = "" if (ctitles!="") H = StrToMat(ctitles, "ctitles") else H = "" T.Body = _CRowJoin(H,L) br = rows(T.Body); bc = cols(T.Body) T.SectRows = (rows(H),br-rows(H)) T.SectCols = (cols(L),bc-cols(L)) if (annotate!="" & (T.SectRows[2]*T.SectCols[2]>0)) T.Body = T.Body + /// (J(T.SectRows[1],bc,"") \ (J(T.SectRows[2],T.SectCols[1],""), /// MakeSymb(annotate,asymbol,T.SectRows[2],T.SectCols[2]))) } else { SplitT(T,H="",L="",Stat="",s=.,fr=.,lr=.) lco = cols(L) // lco = old left columns if (rtitles!="") { lro = rows(L) // lro = old left rows L = StrToMat(rtitles, "rtitles") lrn = rows(L) if (lrn>lro) { // add additional rows on last row section if L is bigger lrs = cols(T.SectRows) T.SectRows[lrs] = T.SectRows[lrs]+lrn-lro } } else if (nortitl) L = "" lcn = cols(L) // lcn = new left columns T.SectCols[1] = lcn if (ctitles!="") { H = StrToMat(ctitles, "ctitles") T.SectRows[1] = rows(H) } else if (noctitl) { H = ""; T.SectRows[1] = 0 } else if (lcn!=lco & H!="") { hc = cols(H); hr = rows(H) if (lcn>lco) { if (lco>0) UL = H[1..lco],J(hr,lcn,"") else UL = J(hr,lcn,"") } else if (lcn>0) UL = H[1..lcn] H = UL,H[lco+1..hc] T.SectRows[1] = hr } if (annotate!="") Stat = Stat + /// MakeSymb(annotate,asymbol,rows(Stat),cols(Stat)) T.Body = _CColJoin(L,Stat) if (rows(L)>rows(Stat)) { // if too many rtitles ls = cols(T.SectRows) T.SectRows[ls] = T.SectRows[ls] + (rows(L)-rows(Stat)) } if (cols(H)>cols(T.Body)) { // if too many ctitles ls = cols(T.SectCols) T.SectCols[ls] = T.SectCols[ls] + (cols(H)-cols(T.Body)) } T.Body = _CRowJoin(H,T.Body) } } if (addrows!="" | addcols!="") AddRowsCols(T,addrows,addrtc,addcols) return(T) } void _CRedim(real matrix A, real scalar r, real scalar c) { // redimension A to r rows & c columns, adding 0's if needed rA = rows(A); cA = cols(A) if (cA!=c) { if (cA1) { errprintf("option %s should specify a vector, not a %fx%f matrix\n", /// opt,sr,sc) exit(198) } else if (sc>1) sm = sm' //transpose to make column vector return(sm) } string matrix FmtStr(string scalar sdec, string scalar sfmt, real scalar sr, real scalar sc, real scalar ns, real matrix dblmat) { // vet, resize, and combine sdec and sfmt // process sdec into dec if (sdec=="") dec = 2 else { dec = strtoreal(editvalue(StrToMat(sdec,"sdec"),"","0")) if (dec!=trunc(dec)| any(dec:<0) | any(dec:>15)) { errprintf(`"sdec contains elements other than 0,1,..,15\n"') exit(198) } } // process sfmt into fmt if (sfmt=="") fmt = ("fc") else { fmt = StrToMat(sfmt,"sfmt") legal_fmt = ("e","f","g","fc","gc") leg = 0 for (i=1;i<=cols(legal_fmt);i++) leg = leg + sum(fmt:==legal_fmt[i]) if (leg1) { // both 1x1 is OK ExpandFmt(dec,tr,tc,ns) ExpandFmt(fmt,tr,tc,ns) } dp = (st_strscalar("c(dp)")=="comma" ? "," : ".") decfmt = J(rows(dec),cols(dec),"%16"+dp) + strofreal(dec) + fmt if (ns>1 & length(decfmt)>1) { // reshape decfmt for sr x sc statmat newf = J(0,sc,"") for (i=1;i<=tr;i=i+ns) newf = newf\(vec(decfmt[i..i+ns-1,])') decfmt = newf } if (sum(dblmat) & length(decfmt)>1) { // duplicate columns for double stats maxindex(dblmat,1,mi=.,w=.) // column locations of 1's put in "mi" lc = cols(decfmt) for (i=1;i<=rows(mi);i++) { dc = mi[i] if (dc<=lc) decfmt = decfmt[,1..dc-1],decfmt[,dc-1],decfmt[,dc..lc] else decfmt = decfmt[,1..dc-1],decfmt[,dc-1] // repeat column lc++ } } return(decfmt) } void ExpandFmt(transmorphic matrix fmt, real scalar tr, real scalar tc, real scalar ns) { // resize either fmt to size of tr x tc fr = rows(fmt); fc = cols(fmt) if (fr>tr) { if (tr==0) fmt = J(0,fc,"") else fmt=fmt[(1..tr),] // delete rows if fmt has more than tr rows } else { // add rows if needed if (fr<=ns) { // fill in fmt rows w/ repeats up to ns, then copy to tr if (frtc) { if (tc==0) fmt = J(fr,0,"") else fmt=fmt[,(1..tc)] // delete cols if fmt has more than tc cols } else if (fc1) { errprintf("doubles (%fx%f) in not a row vector", /// rows(dblmat), cols(dblmat)) exit(198) } if (cols(dblmat)!=sc) { errprintf("option doubles (1x%f) has fewer columns than statmat (%fx%f)\n", /// cols(dblmat), sr, sc) exit(198) } for (j=1;j<=sc;j++) { // combine double columns if (dblmat[j]) { // don't include dbldiv or j column if ci estimate missing smatstr[,j-1] = smatstr[,j-1] + (dbldiv:+smatstr[,j]):*(smatstr[,j-1]:!=".") } } return(select(smatstr,!dblmat)) // delete double columns } void MakeBrac(real scalar squarebrack, string scalar brackets, real scalar sr, real scalar sc, real scalar ns, real scalar tex, string matrix lbracket, string matrix rbracket) { // vet and resize brackets; return results in lbracket and rbracket if (squarebrack) brack23 = "[","]"\"(",")" else brack23 = "(",")"\"[","]" if (brackets=="") { if (tex) brack4_ = "$<$","$>$"\"$|$","$|$" else brack4_ = "<",">"\"|","|" brackets = ("",""\brack23\brack4_) } else brackets = StrToMat(brackets, "brackets") // convert to string matrix br = rows(brackets) bc = cols(brackets) // pare down brackets if too many if (br>ns) brackets = brackets[(1..ns),] // fill in blank rows of brackstr if fewer brackets than statistics (ns) if (br2) { errprintf(`"option "brackets" (%fx%f) has more than two columns\n"', /// br,bc) exit(198) } // fill all columns brackcol = brackets' for (j=2;j<=sc/ns;j++) brackcol = brackcol,brackets' // split into left and right brackets and replicate for all rows lbrack = brackcol[1,] rbrack = brackcol[2,] lbracket = lbrack rbracket = rbrack for (i=2;i<=sr;i++) { lbracket = lbracket\lbrack rbracket = rbracket\rbrack } } string matrix MakeSymb(string scalar annotate, string scalar asymbol, real scalar sr, real scalar sc) { // convert annotation codes to symbols and return as string matrix annote = st_matrix(annotate) if (annote!=trunc(annote) | min(annote)<0) { errprintf("the matrix in annotate() can only contain non-negative integers") exit(198) } if (rows(annote)!=sr | cols(annote)!=sc) _CRedim(annote,sr,sc) symb = tokens(subinstr(asymbol,","," ")) // fill in enough of symb for # of values in annote if (cols(symb)0) cr = cr*(subs+1) findcons = cr } return(L) } string matrix MakeCtitl(string scalar ctitles, string scalar statmat, real scalar vlabels, real scalar substat, real scalar dbls, real matrix notdbl, string matrix H, // from Eq_Merge if not "" real scalar Lcols) { // take column names from statmat, or use ctitles to make column titles. if (ctitles=="") { if (H=="") { H = st_matrixcolstripe(statmat)' // transpose to a row vector if (allof(H[1,],"")) { if (H[2,1]=="c1") H = "" // "c1" is the default column name else { H = H[2,] // eliminate blank equation names // eliminate column headings for double & substat columns if (dbls) H = select(H,notdbl) if (substat) H = H[,range(1,cols(H)-substat,substat+1)] } } } else if (!substat) { // H from Eq_Merge; redim H for substat columns hr = rows(H) ns_1 = cols(st_matrix(statmat))-1 // number of statistics - 1 Hnew = J(hr,0,"") for (j=1;j<=cols(H);j++) Hnew = Hnew,H[,j],J(hr,ns_1,"") H = Hnew } if (H!="") { // could be "" if was "c1" if (vlabels) { // get variable name labels lastrow = rows(H) for (j=1;j<=cols(H);j++) { if (_st_varindex(H[lastrow,j])!=.) { // check if var exists vl = st_varlabel(H[lastrow,j]) if (vl!="") H[lastrow,j] = vl // check if varlabel empty } } } H = J(rows(H),Lcols,""),H // add blanks above leftcols } } else H = StrToMat(ctitles, "ctitles") return(H) } string matrix Eq_Merge(string matrix smat, string scalar statmat, real scalar findcons, string matrix L, string matrix H) { // merge multiequation results into separate columns for each equation L = st_matrixrowstripe(statmat) lr = rows(L) sc = cols(smat) eqnames = L[,1] vnames = L[,2] H = eqnames[1] // keep only unique names in H for (i=2;i<=lr;i++) if (eqnames[i]!=eqnames[i-1]) H = H,eqnames[i] eqnum = cols(H) if (eqnum==1) { errprintf("option eq_merge: no multiple equations to merge\n") exit(198) } pb = J(1,eqnum,NULL) // pointer array for name vectors for each equation ps = pb // pointer array for stat vectors for each equation for (e=1;e<=eqnum;e++) { pb[e] = &(J(0,1,"")) ps[e] = &(J(0,sc,"")) for (i=1;i<=lr;i++) { if(eqnames[i]==H[e]) { *pb[e] = *pb[e]\vnames[i] *ps[e] = *ps[e]\smat[i,] } } } L = *pb[1] smat = *ps[1] for (e=2;e<=eqnum;e++) { // merge multiple equations if (L==*pb[e]) smat = smat,*ps[e] else { L = MergeL(L,*pb[e],sortr=.) lr = rows(L); nsmat = J(lr,sc,"") for (i=1;i<=lr;i++) if (sortr[i]!=.) nsmat[i,]=(*ps[e])[sortr[i],] smat = _CColJoin(smat,nsmat) if (findcons) { minindex((L:=="_cons"),lr,in=.,w=.) // put "_cons" rows last L = L[in]; smat = smat[in,] } } } return(smat) } void AddRowsCols(struct FrmtTabl scalar T, string matrix addrows, real scalar atc, /// = addrtc string matrix addcols) { // attach addrows and addcols to T.Body if (addrows!="") { addrowm = StrToMat(addrows,"addrows") ac = cols(addrowm) if (length(T.Body)==0) { // if no _FrmtT yet T.Body = addrowm if (atc) T.SectCols = (atc,ac-atc) else T.SectCols = (0,ac) T.SectRows = (0,rows(addrowm)) } else { lc = T.SectCols[1] if (atc) { //join left columns separately (to accommodate outreg summstat) if (lc) L = T.Body[.,1..lc] else L = J(rows(T.Body),0,"") T.Body = _CRowJoin(L,addrowm[.,1..atc]), /// _CRowJoin(T.Body[.,lc+1..cols(T.Body)],addrowm[.,atc+1..ac]) if (atc>lc) T.SectCols[1] = atc } else { T.Body = _CRowJoin(T.Body,addrowm) atc = T.SectCols[1] } if (ac-atc>T.SectCols[2]) T.SectCols[2] = ac-atc T.SectRows = (T.SectRows,rows(addrowm)) T.SectSubstats = (T.SectSubstats,0) } } if (addcols!="") { if (length(T.Body)==0) { // if no _FrmtT yet T.Body = addcolm T.SectCols = (0,cols(addcolm)) T.SectRows = (0,rows(addcolm)) } else { addcolm = StrToMat(addcols,"addcols") T.Body = _CColJoin(T.Body,addcolm) if (rows(addcolm)>rows(T.Body)) T.SectRows[rows(T.SectRows)] = /// T.SectRows[rows(T.SectRows)]+rows(addcolm)-rows(T.Body) T.SectCols[2] = T.SectCols[2]+cols(addcolm) } } } void FillBody(struct FrmtTabl scalar T, string matrix smatstr, real scalar substat, real scalar findcons, string matrix L, /// Left (Row Titles) string matrix H, /// Headers (Column Titles) real scalar lc, /// left columns real scalar hr, /// header rows string matrix addrows, real scalar atc, /// = addrtc string matrix addcols) { // fill T.Body with H, L, smatstr, addrows, and addcols // reorganize rows of smatstr (within each ns) to put substats // below first statistics (e.g. t-stats below regression coefficients) ns = substat+1 tc = cols(smatstr)/ns // number of data columns in formatted table if (ns>1) { T.Body = vec(smatstr[,(1..ns)]') for (t=2;t<=tc;t++) { c1 = (t-1)*ns+1 c2 = c1+ns-1 T.Body = T.Body,vec(smatstr[.,(c1..c2)]') } } else T.Body = smatstr // attach L and H to T.Body and set section rows and columns if (L!="") T.Body = _CColJoin(L,T.Body) if (T.ConsSect) { T.SectRows = (hr,rows(T.Body)-findcons,findcons) T.SectSubstats = (0,substat,findcons-1) } else { T.SectRows = (hr,rows(T.Body)) T.SectSubstats = (0,substat) } if (H!="") T.Body = _CRowJoin(H,T.Body) T.SectCols = (lc,cols(T.Body)-lc) if (addrows!="" | addcols!="") AddRowsCols(T,addrows,atc,addcols) } void AddSeq(string matrix m) { // fill in blank rows with row above // and create new column with sequence number if blank rows // for use by MergeL r = rows(m); c = cols(m) blank = (m:=="") seq = J(r,1,0) for (i=2;i<=r;i++) { if (blank[i,1]) { m[i,1] = m[i-1,1] // use text of previous row if (c>1) { // fill in other blank columns j = 2 while (blank[i,j]) { // as long as columns to left are blank m[i,j] = m[i-1,j] // use text of previous row if (j==c) break j++ } } if (m[i,]==m[i-1,]) seq[i] = seq[i-1]+1 // if dups, incr. seq # } } m = (m,strofreal(seq)) // join on seq # } string matrix MergeL(string matrix Lo, string matrix Ln, real matrix sortr) { // return merged L matrix and row sort order for Ln after merge in sortr or = rows(Lo); nr = rows(Ln) oc = cols(Lo); nc = cols(Ln) Lof = Lo; Lnf = Ln // "f" for filled in if (oc!=nc) { if (oc>nc) { Lof = Lof[.,oc-nc+1..oc] // only use matching columns for merge if (Lof=="") Lof = Lo[.,1..oc-nc] // match may be leading columns Ln = J(nr,oc-nc,""),Ln // add columns of spaces to conform w/Lo } else { Lnf = Lnf[.,nc-oc+1..nc] if (Lnf=="") Lnf = Ln[.,1..nc-oc] Lo = J(or,nc-oc,""),Lo } } if (any(Lo:=="") | any(Ln:=="")) { // if blank cells in either AddSeq(Lof); AddSeq(Lnf) } sortr = J(or,1,.) for (j=1;j<=nr;j++) { // Find # of each Lnf row = Lof row nrow = Lnf[j,]; i = 1 while (isn) { frn = frn,J(1,so-sn,1) // make last row (lr) < first row (fr) lrn = lrn,J(1,so-sn,0) // as a flag for not rows in section } else { fro = fro,J(1,sn-so,1) lro = lro,J(1,sn-so,0) sm = sn } printf("{txt}(note: tables being merged have different numbers of row sections)\n") } Statm = J(0,1,"") for (s=1;s<=sm;s++) { // loop over sections if (lro[s]>=fro[s]) { // rows of old section Los = Lo[fro[s]..lro[s],]; Statos = Stato[fro[s]..lro[s],] } if (lrn[s]>=frn[s]) { // rows of new section Lns = Ln[frn[s]..lrn[s],]; Statns = Statn[frn[s]..lrn[s],] } if (lro[s]cols(Lo)) /// Uppero = J(rows(Uppero),cols(Ln)-cols(Lo),""),Uppero Upper = _CColJoin(Uppero,Uppern) } To.SectRows[1] = rows(Upper) To.Body = _CRowJoin(Upper,Statm) } else To.Body = Statm // no headers // update cols of Col Sections if (Tn.SectCols[1]>To.SectCols[1]) To.SectCols[1] = Tn.SectCols[1] lco = cols(To.SectCols); lcn = cols(Tn.SectCols) To.SectCols[lco] = To.SectCols[lco] + Tn.SectCols[lcn] if (rows(Tn.Title)) To.Title = Tn.Title // use new Title and Note if (rows(Tn.Note)) To.Note = Tn.Note // if they exist return(To) } struct FrmtTabl scalar Append(struct FrmtTabl scalar To, struct FrmtTabl scalar Tn) { // append new T (Tn) below old T (To) bro = rows(To.Body); brn = rows(Tn.Body) bco = cols(To.Body); bcn = cols(Tn.Body) lco = To.SectCols[1]; lcn = Tn.SectCols[1] sr1n = Tn.SectRows[1]+1 // first Stats row in Tn To.SectCols[1] = max((lco,lcn)) To.SectCols[2] = max((bco-lco,bcn-lcn)) // only allow 2 column sections if (!To.SectCols[1]) L = J(0,0,"") // no row titles else if (!lcn) L = To.Body[,1..lco] // old row titles only else if (!lco) L = J(bro,lcn,"")\Tn.Body[sr1n..brn,1..lcn] // new rtitles only else L = _CRowJoin(To.Body[,1..lco],Tn.Body[sr1n..brn,1..lcn]) Stat = _CRowJoin(To.Body[,lco+1..bco],Tn.Body[sr1n..brn,lcn+1..bcn]) To.Body = _CColJoin(L,Stat) ls = cols(To.SectRows) if (ls<3) { To.SectRows = (To.SectRows,brn-sr1n+1) To.SectSubstats = (To.SectSubstats,Tn.SectSubstats[2]) } else To.SectRows[ls] = To.SectRows[ls]+brn-sr1n+1 if (rows(Tn.Title)) To.Title = Tn.Title // use new Title and Note if (rows(Tn.Note)) To.Note = Tn.Note // if they exist return(To) } struct Page_Width { real scalar firstcol real scalar lastcol real scalar width } void FrmtDisplay(struct FrmtTabl scalar T, real scalar wide, real scalar noblankrows) { // display table to Stata output screen real scalar colpad struct Page_Width colvector page struct Page_Width scalar apage real rowvector tablwidth string scalar line colpad = 2 // spaces between columns displayed bod = T.Body // eliminate completely blank rows if (noblankrows) bod = select(bod,rowsum(bod:==""):!=cols(bod)) // calculate column widths of left columns and stat columns tablwidth = colmax(strlen(bod)) :+ colpad totwidth = sum(tablwidth) + colpad lc = T.SectCols[1] // left columns if (lc) totleft = sum(tablwidth[,1..lc]) + colpad else totleft = 0 winwidth = c("linesize") // "linesize" is width of user's result window // split up table into multiple pages if table too wide for result window // and !wide and left columns won't take up whole result window width if ((totwidth>winwidth) & !wide & (totleft+max(tablwidth)winwidth | j0) spaceaft = spaceaft+"{"+ /// T.SectSubstats[i]*"0"+"1};" else if (i==ns) spaceaft = spaceaft+"{0}1;" else spaceaft = spaceaft+"{0};" } spaceaft = spaceaft+"{0}1" } } if (spacebef!=""|spaceaft!="") { tr = rows(T.Title) br = rows(T.Body) nr = rows(T.Note) sects = (tr,T.SectRows,nr) spacebefv = strtoreal(ParseLines(spacebef,"spacebef",sects,"01"))' spaceaftv = strtoreal(ParseLines(spaceaft,"spaceaft",sects,"01"))' spbefstr = spbefstr[1,]:*J(tr,2,1)\ /// expand to size of table rows spbefstr[2,]:*J(br,2,1)\ /// spbefstr[3,]:*J(nr,2,1) spaftstr = spaftstr[1,]:*J(tr,2,1)\ /// expand to size of table rows spaftstr[2,]:*J(br,2,1)\ /// spaftstr[3,]:*J(nr,2,1) spaces = (spbefstr[,1]:*!spacebefv + spbefstr[,2]:*spacebefv) , /// (spaftstr[,1]:*!spaceaftv + spaftstr[,2]:*spaceaftv) if (tr) titlspaces = spaces[1..tr,] trbr = tr+br bodyspaces = spaces[tr+1..trbr,] if (nr) endspaces = spaces[trbr+1..trbr+nr,] } } void TitlNoteDoc(string matrix Ttitl_note, real scalar fh, string scalar fonts, string scalar opt, real scalar plain, real scalar center, string matrix spaces, real scalar deffs, real scalar nfcount) { // write T.Title or T.Note to file with Word formatting titl_note = Ttitl_note // don't modify T.Title or T.Note r = rows(titl_note) if (center) qc = "\qc" else qc = "" if (fonts!="") ParseFMDoc(fonts,opt,begm="",endm="",1,r,1,1,nfcount) else { begm = J(r,1,""); endm = begm if (!plain) { if (opt=="titlfont") { begm = "\fs"+strofreal(round(deffs*1.2)) if (r>1) begm = begm\J(r-1,1,"\fs"+strofreal(round(deffs*1.125))) } else begm=J(r,1,"\fs"+strofreal(round(deffs*0.79))) // for T.Note } } if (!plain) pard = "\pard"+qc:+spaces else pard = "\pard"+qc begm = pard:+begm:+" " if (!plain&opt=="notefont") /// make "p" italic titl_note[1] = subinstr(titl_note[1]," p<0."," {\i p}<0.") titl_note = begm:+titl_note:+endm:+"\par" for (i=1;i<=r;i++) fput(fh,titl_note[i]) } string matrix ParseFDoc(string scalar font, // font info string string scalar opt, // calling option name (for err message) real scalar nfcount, // new font count |real scalar deffs) // default font size { // check contents of font and convert fs values to points*2; // return deffs if included in args allowf = ("roman","arial","courier") if (nfcount & nfcount!=.) /// add fnew# for user-specified fonts allowf = allowf,"fnew":+strofreal(range(1,nfcount,1)') fnum = range(0,cols(allowf)-1,1) allowch = ("plain","b","i","scaps","ul","uldb","ulw") fontvec = tokens(font) for (i=1;i<=cols(fontvec);i++) { // check elements of font afont = fontvec[i]; err = 0 if (substr(afont,1,2)=="fs") { fsN = strtoreal(substr(afont,3)) if (fsN!=. & fsN>0) { deffs = round(fsN*2) // return deffs if passed as parameter fontvec[i] = "fs"+strofreal(deffs) } else err = 1 } else { an_f = allowf:==afont if (any(an_f)) fontvec[i] = "f"+strofreal(an_f*fnum) else if (!any(allowch:==afont)) err = 1 } if (err) { errprintf(`"font "%s" not allowed in %s option\n"', /// fontvec[i], opt) exit(198) } } return("\":+fontvec) } void ParseFMDoc(string scalar font, // font string string scalar opt, // name of calling option (for err message) string matrix begm, // matrix of codes before string matrix endm, // matrix of codes before real scalar colvec, // colvector instead of matrix real scalar fr, // font rows real scalar fc, // font columns real scalar ns, // number of substats real scalar nfcount) // new font count { // parse font options into a string matrix: titlfont, notefont, & statfont if (colvec) fontm = StrToCVec(font,opt) else fontm = StrToMat(font,opt) r = rows(fontm); c = cols(fontm) begm = J(r,c,""); endm = J(r,c,"") for (i=1;i<=r;i++) { for (j=1;j<=c;j++) { fontcell = ParseFDoc(fontm[i,j],opt,nfcount) begf = "" for (k=1;k<=cols(fontcell);k++) begf = begf+fontcell[k] if (begf!="") { begm[i,j] = "{"+begf+" "; endm[i,j] = "}" } } } ExpandFmt(begm,fr,fc,ns); ExpandFmt(endm,fr,fc,ns) } void StatFDoc(struct FrmtTabl scalar T, real scalar plain, string scalar statfont, string matrix begm, string matrix endm, real scalar deffs, real scalar nfcount) { // fill in font codes for statistics (not ctitles or rtitles) r = rows(T.Body)-T.SectRows[1] // subtract off header rows c = cols(T.Body)-T.SectCols[1] // subtract off left columns if (statfont!="") { FontSect(statfont,T,sr=.,ns=.) // sr is # rows in each stat row section begm=J(0,c,""); endm=begm // ns = # substats in each stat row section for (i=1;i<=cols(statfont);i++) { ParseFMDoc(statfont[i],"statfont",bm="",em="",0,sr[i],c,ns[i],nfcount) begm = (begm\bm); endm = (endm\em) } } else if (!plain & T.SectSubstats[2]) { rs = cols(T.SectRows) // rs = row sections if (rs>=3) er = sum(T.SectRows[2..3]) // er = estimates rows else if (T.ConsSect) er = r // no addrow else er = T.SectRows[2] // no ConsSect xr = r - er font = "fs"+strofreal(deffs/2)+"\fs"+strofreal(round(deffs/2*0.85)) ParseFMDoc(font,"statfont",begm,endm,0,er,c,T.SectSubstats[2]+1,nfcount) begm = (begm\J(xr,c,"")); endm = (endm\J(xr,c,"")) } else { begm=J(r,c,""); endm=begm } } string matrix MakeRCodes(struct FrmtTabl scalar T, real scalar deffs, string matrix hlines, string scalar hlstyle, string matrix vlines, string scalar vlstyle, real scalar center, string scalar colwidth, string scalar multicol, string scalar coljust, string matrix bodyspaces) { // parse hlines, vlines, & coljust and create table row codes for RTF document br = rows(T.Body); bc = cols(T.Body) hr = T.SectRows[1] // last ctitle (header) row if (coljust=="") coljust = "l;." coljust = ParseLines(coljust,"coljust",T.SectCols,"lcr.") calcwidth = colmax(strlen(T.Body)) deccol = (coljust:==".") if (any(deccol)) { // calculate width of cols w/ decimal justification dp = (st_strscalar("c(dp)")=="comma" ? "," : ".") decpos = strpos(T.Body[hr+1..br,],dp):-1 // location of decimal point in column maxdecpos = colmax(decpos) // max width to left of decimal + max width to right of decimal maxdecwidth = maxdecpos + /// (colmax((strlen(T.Body[hr+1..br,])-decpos):*(decpos:>0))) // add in padding if calcwidth>maxdecwidth (e.g. wide ctitles) maxdecpos = maxdecpos + 0.5:*(colmax((maxdecwidth\calcwidth))-maxdecwidth) calcwidth = (calcwidth:*deccol) + (colmax((maxdecwidth\calcwidth)):*!deccol) } else maxdecpos = calcwidth if (colwidth!="") { cwidth = strtoreal(tokens(colwidth)) // convert to real matrix // if cwidth not long enough, fill in with calcwidth if (cols(cwidth)1) { rs = cols(T.SectRows)-1 // row sections, not including header fr = T.SectRows[2..rs+1] // remove header row section if (fs>rs) { font = font[1..rs] fs = rs } else if (fssc) lvec = lvec[1..sc] else if (sc>lc) sr = sr[1..lc-1],sum(sr[lc..sc]) newl = "" for (i=1;i<=cols(lvec);i++) { if (sr[i]>0) { // if no rows (or columns) in section, ignore lsec = tokens(lvec[i],"{}") lsc = cols(lsec) strp = select(lsec, lsec:!="{"); strp = select(strp, strp:!="}") if (lsc - cols(strp) > 2) { errprintf("more than one {} per section of %s: %s\n", /// opt, lvec[i]) exit(198) } if (lsc==1) { slen = strlen(lsec[1]) if (slen>1) begl = substr(lsec[1],1,slen-1) else begl = "" midl = substr(lsec[1],slen) endl = "" } else { if (lsec[1]=="{") { begl = "" midl = lsec[2] gap = 1 } else { begl = lsec[1] gap = sr[i]-strlen(begl) // if length(begl)>sr[i], pare down if (gap<0) begl = substr(begl,1,sr[i]) midl = lsec[3] } if (lsec[lsc]!="}" & gap>0) { // if length(begl)>sr[i], no endl endl = lsec[lsc] sp = sr[i] - strlen(begl) gap = sp - strlen(endl) // if len(endl)>sr[i]-len(begl), if (gap<0) endl = substr(endl,-sp,sp) // take from end back } else endl = "" } gap = sr[i] - strlen(begl) - strlen(endl) midl = substr(ceil(gap/strlen(midl))*midl,1,gap) newl = newl + begl + midl + endl } } nlvec = J(1,0,"") for (i=1;i<=strlen(newl);i++) nlvec = nlvec,substr(newl,i,1) return(nlvec) } real matrix VetMulti(string scalar multicol, real scalar br, real scalar bc) { // vet multicolumn coordinates and convert to real matrix mcol = tokens(multicol,";") mcol = select(mcol,mcol:!=";") // remove ";" msm = J(0,3,"") maxb = max((br,bc)) allowed = strofreal(range(1,maxb,1)) for (i=1;i<=cols(mcol);i++) { ms = tokens(mcol[i],",") ms = select(ms,ms:!=",") // remove "," if (cols(ms)!=3) { errprintf("option multicol requires three coordinates per cell\n") exit(198) } if (any(colmin(indexnot(ms,allowed)))) { errprintf("option multicol coordinates have characters other than 1,..,%f\n", /// maxb) exit(198) } if (ms[3]=="1") { errprintf("option multicol(r,c,numcol) needs more than 1 column (numcol>1) to combine\n") exit(198) } msm = msm\ms } m = strtoreal(msm) // convert to real if (brbr) { errprintf("option multicol row coordinate (%f) is out of table range", /// m[i,1]) exit(198) } } mc = m[,2]+m[,3]:-1 minindex(mc,-1,i,w); i = i[1] // get rid of dupes if (mc[i]>bc) { errprintf("option multicol column coordinates (%f..%f) are out of table range (1..%f)\n", /// m[i,2],mc[i],bc) exit(198) } return(m) } void BegTex(struct FrmtTabl scalar T, real scalar fh, string scalar basefont, real scalar lscape, real scalar a4, real scalar addtable, real scalar plain, real scalar center, string scalar titlfont, string scalar spacebef, string scalar spaceaft, real scalar spaceht, string scalar bodyspaces, string scalar endspaces, real scalar fragment) { // write docbeg, pretext, center, Title to file if (!addtable & !fragment) { docbeg = "" setlength = "" if (basefont!="") { // ParseFTex also puts font size back in basefont fontvec = ParseFTex(basefont, "basefont", 0) if (cols(fontvec)>0) docbeg = "\"+subinstr(invtokens(fontvec)," ","\") if (lscape | a4) basefont = basefont+"," } if (lscape) { if (a4) { basefont = basefont+"landscape,a4paper" setlength = "\setlength{\pdfpagewidth}{297mm}"+ /// "\setlength{\pdfpageheight}{210mm}" } else { basefont = basefont+"landscape" setlength = "\setlength{\pdfpagewidth}{11in}"+ /// "\setlength{\pdfpageheight}{8.5in}" } } else if (a4) { basefont = basefont+"a4paper" setlength = "" } dp = (st_strscalar("c(dp)")=="comma" ? "," : ".") docbeg = "\documentclass["+basefont+"]{article}\pagestyle{empty}" /// +setlength+"\begin{document}"+docbeg fput(fh,docbeg) } for (i=1;i<=rows(T.Pretext);i++) { fput(fh,""); fput(fh,T.Pretext[i]) // insert blank line to end paragraph } if (center) fput(fh,"\begin{center}") if (!anyof((1,2,3),spaceht)) { errprintf(`"spaceht option must = 2 or 3 with tex option\n"') exit(198) } sht = ("\smallskip","\medskip","\bigskip")[spaceht] spbefstr = ("",sht\"","\noalign{"+sht+"}"\"",sht) spaftstr = spbefstr MakeSpaces(T,spacebef,spaceaft,plain,spbefstr,spaftstr, /// titlspaces="",bodyspaces,endspaces) if (rows(T.Title)) TitlNoteTex(T.Title,fh,titlfont,"titlfont",plain,titlspaces) } void BodyTex(struct FrmtTabl scalar T, real scalar fh, string scalar coljust, string matrix hlines, string scalar vlines, real scalar plain, string scalar ctitlfont, string scalar rtitlfont, string scalar statfont, string matrix multicol, real scalar noblankrows, string matrix spaces) { // write T.Body to file w/ Tex formatting bod = subinstr(T.Body,"_","\_") // don't alter T.Body itself; put "\" before "_" br = rows(bod) bc = cols(bod) fput(fh,"\begin{tabular}{"+TabularCols(vlines,coljust,T)+"}") // table begin lastspace = spaces[br,2] // separate last aft space frstcol = (""\spaces[1..br-1,2])+ParseHLines(hlines,T)+spaces[,1] // offset bef & aft spaces if (!plain) { for (i=1;i<=br;i++) { // prettify R^2 & N if (bod[i,1]=="R2") bod[i,1] = "\$R^2$" if (bod[i,1]=="N") bod[i,1] = "\$N$" } } hr=T.SectRows[1] // last ctitle (header) row if (ctitlfont!="") ParseFMTex(ctitlfont,"ctitlfont", /// ctbegm="",ctendm="",0,hr,bc,1) else { ctbegm=J(hr,bc,""); ctendm=ctbegm } lc=T.SectCols[1] // left columns if (rtitlfont!="") { FontSect(rtitlfont,T,lr=.,ns=.) // converts rtitlfont to colvector ltbegm = J(0,lc,""); ltendm=ltbegm for (i=1;i<=cols(rtitlfont);i++) { ParseFMTex(rtitlfont[i],"rtitlfont",bm="",em="",0,lr[i],lc,ns[i]) ltbegm = (ltbegm\bm); ltendm = (ltendm\em) } } else { ltbegm=J(br-hr,lc,""); ltendm=ltbegm } StatFTex(T,plain,statfont,stbegm="",stendm="") begfont = (ctbegm\(ltbegm,stbegm)) endfont = (ctendm\(ltendm,stendm)) bod = begfont+bod+endfont // add spacer characters for tabular delim = (J(br,bc-1," & "),J(br,1,"\\")) if (multicol!="") { mc = VetMulti(multicol,br,bc) for(r=1;r<=rows(mc);r++) { i = mc[r,1]; c1 = mc[r,2]; c2 = mc[r,2]+mc[r,3]-1 bod[i,c1] = "\multicolumn{"+strofreal(mc[r,3])+"}{c}{"+bod[i,c1]+"}" for (j=c1+1;j<=c2;j++) { bod[i,j] = ""; delim[i,j] = "" } if (c2==bc) delim[i,c1] = "\\" } } bod = bod+delim bodrows = frstcol for (j=1;j<=bc;j++) bodrows = bodrows+bod[,j] // eliminate completely blank rows if (noblankrows) bodrows = select(bodrows, /// rowsum(T.Body:==""):!=cols(T.Body)) for (i=1;i<=rows(bodrows);i++) fput(fh, bodrows[i]) lastline = lastspace + (hlines[br+1]=="1")*"\hline" + "\end{tabular}\\" fput(fh,lastline) // table end } void EndTex(struct FrmtTabl scalar T, real scalar fh, real scalar plain, real scalar center, string scalar notefont, string matrix endspaces, real scalar fragment) { // write Note, center, posttext, and \end to file if (rows(T.Note)) TitlNoteTex(T.Note,fh,notefont,"notefont",plain,endspaces) if (center) fput(fh,"\end{center}") for (i=1;i<=rows(T.Posttext);i++) { fput(fh,""); fput(fh,T.Posttext[i]) // insert blank line to end paragraph } if (!fragment) fput(fh,"\end{document}") } void TitlNoteTex(string matrix Ttitl_note, real scalar fh, string scalar fonts, string scalar opt, real scalar plain, string matrix spaces) { // write T.Title or T.Note to file with TeX formatting titl_note = Ttitl_note // don't modify T.Title or T.Note if (opt=="notefont") { // avoid initial "*" and make "<" appear properly if (substr(titl_note[1],1,1)=="*") titl_note[1] = "\ "+titl_note[1] titl_note[1] = subinstr(titl_note[1]," p<0"," \$p<0$") } // pseudocode for default values of formatting (not set up yet) // else if _FrmtTexBegTitl _FrmtTexEndTitl _FrmtTexTitlFont (use ExpandFmt) // check if default TeX formatting exists; if not, create it // pLeft = findexternal("_FrmtTeXLeft") // if (pLeft!=NULL) { // Left = *pLeft // go through *pLeft and fill in empty parts // } r = rows(titl_note) if (fonts!="") ParseFMTex(fonts,opt,begm="",endm="",1,r,1,1) else if (!plain) { if (opt=="titlfont") { begm="\begin{large}"; endm="\end{large}" if (r>1){ begm=(begm\J(r-1,1,"")); endm=(endm\J(r-1,1,"")) } } else { // for T.Note begm=J(r,1,"\begin{footnotesize}") endm=J(r,1,"\end{footnotesize}") } } else { begm=J(r,1,""); endm=begm } titl_note = titl_note + (strtrim(titl_note):==""):*"\hfil" // make blank lines appear lastspace = spaces[r,2] // separate last aft space offset = "" if (r>1) offset = offset\spaces[1..r-1,2] spaces = spaces[,1]+offset // offset bef & aft spaces titl_note = spaces+begm+titl_note+endm:+"\\" for (i=1;i<=r;i++) fput(fh,titl_note[i]) if (lastspace!="") fput(fh,lastspace) } string scalar TabularCols(string scalar vlines, string scalar coljust, struct FrmtTabl scalar T) { // convert vlines and coljust into column code for Tex {tabular} command if (vlines=="") vlines = "0" if (coljust=="") coljust = "l;c" sects = T.SectCols sects[cols(sects)] = sects[cols(sects)]+1 // vline after last column vlines = ParseLines(vlines,"vlines",sects,"01") vlines = subinstr(subinstr(vlines,"0",""),"1","|") // convert 1's to "|" coljust = ParseLines(coljust,"coljust",T.SectCols,"lcr.") tabcol = vlines[1] for (i=2;i<=cols(vlines);i++) tabcol = tabcol+coljust[i-1]+vlines[i] return(tabcol) } string colvector ParseHLines(string matrix hlines, struct FrmtTabl scalar T) { // convert hlines to hlcol column vector if (hlines=="") hlines = "1{0};1{0}1" sects = T.SectRows sects[cols(sects)] = sects[cols(sects)]+1 // hline after last row hlines = ParseLines(hlines,"hlines",sects,"01") return((subinstr(subinstr(hlines,"0",""),"1","\hline ")[1..cols(hlines)-1])') } string matrix ParseFTex(string scalar font, string scalar opt, real scalar none) { // check contents of font and change font "none" to "" retfont = ("fs11", "fs12", "a4paper") // characteristics returned in "font" if (none) retfont = (retfont, "none") allowed = (retfont, "Huge", "huge", "LARGE", "Large", "large", /// "normalsize", "small", "footnotesize", "scriptsize", "tiny", /// "rm", "it", "em", "bf", "sl", "sf", "sc", "tt", "underline") fontvec = tokens(font) font = ""; fsel = J(1,cols(fontvec),1) for (i=1;i<=cols(fontvec);i++) { // check elements of font if (!anyof(allowed,fontvec[i])) { errprintf(`"font "%s" not allowed in %s option\n"',fontvec[i],opt) exit(198) } if (anyof(retfont,fontvec[i])) { fsel[i] = 0 if (substr(fontvec[i],1,2)=="fs") { // return font size value in font if (font=="a4paper") font = font+","+substr(fontvec[i],3,.)+"pt" else font = substr(fontvec[i],3,.)+"pt" } else if (fontvec[i]=="a4paper") { // return a4paper size in font if (substr(font,-2,.)=="pt") font = font+","+fontvec[i] else font = fontvec[i] } } } fontvec = select(fontvec,fsel) return(fontvec) } void ParseFMTex(string scalar font, string scalar opt, string matrix begm, string matrix endm, real scalar colvec, real scalar fr, real scalar fc, real scalar ns) { // parse font options into a string matrix: titlfont, notefont, & statfont if (colvec) fontm = StrToCVec(font,opt) else fontm = StrToMat(font,opt) r = rows(fontm); c = cols(fontm) begm = J(r,c,""); endm = J(r,c,"") for (i=1;i<=r;i++) { for (j=1;j<=c;j++) { fontcell = ParseFTex(fontm[i,j], opt, 1) begf = ""; endf = "" for (k=1;k<=cols(fontcell);k++) { if (fontcell[k]!="") { if (fontcell[k]=="underline") { begf = begf + "\underline{" endf = "}" + endf } else { begf = begf + "\begin{" + fontcell[k] + "}" endf = "\end{" + fontcell[k] + "}" + endf } } } begm[i,j] = begf; endm[i,j] = endf } } ExpandFmt(begm,fr,fc,ns); ExpandFmt(endm,fr,fc,ns) } void StatFTex(struct FrmtTabl scalar T, real scalar plain, string scalar statfont, string matrix begm, string matrix endm) { // fill in font codes for statistics (not ctitles or rtitles) r = rows(T.Body)-T.SectRows[1] // subtract off header rows c = cols(T.Body)-T.SectCols[1] // subtract off left columns if (statfont!="") { FontSect(statfont,T,sr=.,ns=.) begm=J(0,c,""); endm=begm for (i=1;i<=cols(statfont);i++) { ParseFMTex(statfont[i],"statfont",bm="",em="",0,sr[i],c,ns[i]) begm = (begm\bm); endm = (endm\em) } } else if (!plain & T.SectSubstats[2]) { rs = cols(T.SectRows) // rs = row sections if (rs>=3) er = sum(T.SectRows[2..3]) // er = estimate rows else if (T.ConsSect) er = r // no addrow else er = T.SectRows[2] // no ConsSect xr = r - er ParseFMTex("none\footnotesize","statfont", /// begm,endm,0,er,c,T.SectSubstats[2]+1) begm = (begm\J(xr,c,"")); endm = (endm\J(xr,c,"")) } else { begm=J(r,c,""); endm=begm } } end // end mata: