*! 22dec2012 * @@ Written by Elliott Lowy, mostly on the US government's dime (17 US Code ยง 105). program tstats, sortpreserve version 11 mata: DoIt() end version 11 mata: void DoIt() { //>>def func class statgrid scalar sg class tspoof scalar t syntaxl(st_local("0"),(&(explist="anything"),&(ifin="ifin")),(&(by="by="),&(swap="swap"), &(nest="nest"),&(nlab="nl:abels="),&(vlab="vl:abels="),&(out="out="))) syntaxl(by,&(by2="anything"), (&(fm="f:irstvar"),&(lm="l:astvar"),&(ov="o:verall"),&(byc="c:olumns"))) sg.defaults="Nobs() N() Mean() SD() Min() Med(,d(Med)) Max()" sg.by(by2) bytypes="" if (length(sg.by_vars)) { if (length(sg.by_vars)>1) { if (fm) { sg.bys=sg.bys\&sg.by_vars[1] bytypes=bytypes,"fm" } if (lm) { sg.bys=sg.bys\&cut(sg.by_vars,-1) bytypes=bytypes,"lm" } } if (ov) { sg.bys=sg.bys\&"" bytypes=bytypes,"om" } } sg.setup(explist,ifin) sg.set_flabels() sg.dseval() b_n=sg.b_n k_n=sg.k_n cross=sg.cross*!nest if (any(bytypes:=="fm")) { mn=J(1,4,0) for (m=1;m<=length(sg.bys);m++) mn[m]=*sg.bys[m] mf=&(J(mn[1],1,0)\J(mn[2],1,1)\J(mn[3]+mn[4],1,0)) ml=&(J(mn[1]+mn[2],1,0)\J(mn[3],1,1)\J(mn[4],1,2)) cosort_((ml,sg.ds.data[1],mf,sg.ds.data[2..sg.ds.nvars]),1::sg.ds.nvars+2) } t.labset("n",2,nlab,"u,u") t.labset("v",2,vlab,"l,l",(1,0)) dnames=t.dsspoof(sg.ds) if (!cross) { xstub=J(1,0,"") xhead=t.getn(sg.k_vars)'\cut(sg.ds.nlabels,b_n+1) } else { xstub=t.getn(dedup(sg.k_vars')) xhead=sg.ds.nlabels[b_n+1..b_n+k_n/cross] } data=t.getv(cut(dnames,b_n+1),sg.ds.strdat(.,b_n+1..b_n+k_n),1) allby=b_n?t.getv(cut(dnames,1,b_n),sg.ds.strdat(.,1..b_n),2):J(0,rows(data),"") byhead=byheadh=bystub=J(0,0,"") if (b_n>byc) bystub=dedup(cut(allby,1,(b_n-byc)*t.vl_n[2],.,"cols")) if (byc) { byhead=dedup(cut(allby,b_n,b_n*byc,.,"cols"))' byheadh=t.getn(dnames[b_n],2)' if (b_n>1) { del=charsubs(allby) x=pairs(bystub,byhead') rmap=vmap(concat(x,del),concat(allby,del),"both") ndata=J(rows(x),cols(data),"") ndata[rmap[,1],]=data[rmap[,2],] data=ndata } } if (swap&cross) data=riffle(data,k_n/cross) if (byc) data=colshape(data,cols(data)*cols(byhead)) if (swap&cross) data=kaleid(data,cross,k_n/cross) else if (swap) data=kaleid(data,1,k_n) else if (cross) data=kaleid(data,k_n/cross,cross) if (swap) { sw=xstub xstub=xhead' xhead=sw' } head=pad(byheadh,pairs(byhead',xhead')',"\") stub=pairs(bystub,xstub) sthead=J(0,cols(stub),"") if (b_n>byc) sthead=expand(colshape(t.getn(dnames[b_n-byc..1],2),1),cols(stub),1) if (b_n-byc>1) { guide=t.defChar("{c |}","│","↓") sthead[,rangel(2*t.vl_n[2],(b_n-byc)*t.vl_n[2],t.vl_n[2])]=J(rows(sthead),b_n-byc-1,guide) } t.body=pad(sthead,head,",","bottom")\stub,data t.head=rows(t.body)-rows(data) t.stub=cols(stub) t.altrows=1 xhn=cols(xhead) span=t.stub-cols(xstub) for (r=1;r<=rows(sthead);r++) { t.set(t._span,t.head-rows(sthead)+r,1,span) span=span-t.vl_n[2]*!mod(r,t.nl_n[2]) t.set(t._align,t.head-rows(sthead)+r,1,t.right) } if (byc) { hr1=1+pmax(b_n-byc-rows(head),0) t.set(t._span,hr1..hr1+t.nl_n[2]-1,t.stub+1,cols(data)) t.set(t._span,hr1+t.nl_n[2]..hr1+t.nl_n[2]+t.vl_n[2]-1,rangel(t.stub+1,cols(t.body),xhn),xhn) t.set(t._vline,.,rangel(t.stub+xhn,cols(t.body),xhn),t.Lminor) } stspcol=t.stub-cols(xstub)-!cols(xstub)*t.vl_n[2]-(t.vl_n[2]==2) for (c=stspcol;c>0;c=c-t.vl_n[2]) { t.set(t._hline,toindices(differ(stub[,c])):+t.head,(c..cols(t.body)),c==stspcol?t.Lsp1:t.Lminor) } if (!cross&!swap) { vbrk=J(1,pmax(1,cols(byhead)),differ(sg.k_vars,"bef","true")) vix=toindices(vbrk):+t.stub vsp=(cut(vix,2),length(vbrk)+1+t.stub):-vix for (v=1;v<=length(vix);v++) t.set(t._span,t.head-t.nl_n[1]..t.head-1,vix[v],vsp[v]) if (length(vix=select(vix,vix:>t.stub+1):-1)) t.set(t._vline,.,vix,t.Lminor) } t.set(t._vline,.,cols(t.body),t.Lmajor) if (length(sg.bys)>1) { //margins if (byc&(bytypes[2]=="fm"|b_n==1)) t.set(t._vline,.,cols(t.body)-xhn,t.Lmajor) if (b_n>byc) { if (length(sg.bys)>2|bytypes[2]!="fm") t.set(t._hline,cut(toindices(differ(t.body[,1])),-1),1..cols(t.body),t.Lmajor) //because earlier hlines are set by cell if (cut(bytypes,-1)=="om") t.set(t._hline,rows(t.body),1..cols(t.body),t.Lmajor) //sometimes rendundant } } t.present(out) } end