*! version 4.2.0 December 19, 2003 @ 15:49:39 program define reshape8 /* 4.2.0 - swiched to modern syntax, more straightforward style, version 8 */ /* 4.1.5 - allows variable labels to be carried back and forth when going long to wide to long*/ version 8 global ReS_Clear "ReS_ver ReS_i ReS_j ReS_jv ReS_jv2 ReS_Xij ReS_Xi ReS_atwl ReS_str ReS_Xij_long" global ReS_Keep "ReS_j_lab ReS_Xij_lab ReS_Xi_lab" if "`1'"=="clear" { foreach name of global ReS_Clear { char _dta[`name'] } if "`2'"=="all" { foreach name of global ReS_Keep { char _dta[`name'] } } exit } if "`1'"=="wide" | "`1'"=="long" { DoNew `*' exit } local syntax : char _dta[ReS_ver] if index("query","`1'") { if "`syntax'"=="" | "`syntax'"=="v.2" { Query exit } local 1 "query" } if "`syntax'"=="" { IfOld `1' if `s(oldflag)' { DoOld `*' char _dta[ReS_ver] "v.1" } else { DoNew `*' char _dta[ReS_ver] "v.2" } exit } if "`syntax'"=="v.1" { DoOld `*' } else DoNew `*' end program define IfOld, sclass if "`1'"=="" { sret local oldflag 0 exit } sret local oldflag /// = index("groups","`1'") | index("vars","`1'") | index("cons","`1'") | index("query","`1'") end program define IfNew, sclass sret local newflag = "`1'"=="i" | "`1'"=="j" | "`1'"=="xij" | "`1'"=="xi" | "`1'"=="error" end program define DoNew local cmd "`1'" mac shift /* reshape w/o arguments */ if "`cmd'"=="" Query /* reshape mini-commands */ else if "`cmd'"=="i" { unab ivars : `*', min(1) name(i variable is required) char _dta[ReS_i] "`ivars'" } else if "`cmd'"=="j" J `*' else if "`cmd'"=="xij" Xij `*' else if "`cmd'"=="xi" { local xivars : unab `*', min(0) char _dta[ReS_Xi] `xivars' } /* reshape wide/long */ else if "`cmd'"=="long" { if "`1'" != "" Simple long `*' capture noisily Long `*' Macdrop exit _rc } else if "`cmd'"=="wide" { if "`1'" != "" Simple wide `*' else { /* stupid hack... */ global ReS_Xij : char _dta[ReS_Xij] global ReS_atwl : char _dta[ReS_atwl] reshape8 xij $ReS_Xij , atwl($ReS_atwl) global ReS_j : char _dta[ReS_j] local theLab: var lab $ReS_j char _dta[ReS_j_lab] `theLab' } capture noisily Wide `*' Macdrop exit _rc } /* reshape error */ else if "`cmd'"==substr("error",1,max(3,length("`cmd'"))) { capture noisily Qerror `*' Macdrop } else { IfOld `cmd' if `s(oldflag)' { di as err "may not mix old and new syntax;" di as err `"either use new syntax or "reshape8 clear" and start over using old syntax."' exit 198 } error 198 } end program define DoOld local cmd "`1'" local l = length("`cmd'") mac shift if "`cmd'"==substr("groups",1,`l') { if "`2'" == "" { error 198 } DoNew j `*' exit } if "`cmd'"==substr("vars",1,`l') { DoNew xij `*' exit } if "`cmd'"==substr("cons",1,`l') { DoNew i `*' exit } if "`cmd'"==substr("query",1,`l') { local cons : char _dta[ReS_i] local grpvar : char _dta[ReS_j] local values : char _dta[ReS_jv] local vars : char _dta[ReS_Xij] local car : char _dta[ReS_Xi] di "group var: `grpvar'" di "values: `values'" di "cons: `cons'" di "vars: `vars'" exit } if "`cmd'"=="wide" { DoNew wide `*' exit } if "`cmd'"=="long" { DoNew long `*' exit } IfNew `cmd' if `s(newflag)' { di as err "may not mix old and new syntax;" di as err `"either use old syntax or "reshape8 clear" and start over using new syntax."' exit 198 } error 198 end program define Simple /* {wide|long} , i(varlist) [j(varname [values])] */ syntax anything(name=xvarlist id="[Simple]:extended varlist") , i(varlist) [j(str) ATwl(passthru) String ] tokenize "`xvarlist'", parse(" ,") local cmd "`1'" mac shift local xvarlist `*' if "`xvarlist'"=="" { display as err "[Simple]: xvarlist empty" exit 198 } if "`j'" != "" { tokenize "`j'" local jvar "`1'" mac shift local jvals "`*'" } else { local jvar "_j" /* place-holder for error checking */ } if "`cmd'"=="wide" { /* When reshaping wide we can -unab- the variable list and the jvar*/ capture unab xvarlist : `xvarlist' /* ignore _rc, error caught later */ capture unab jvar : `jvar' , max(1) /* use -unab- not -ConfVar- here */ if _rc { if _rc==111 { di as error "`jvar' not found -- " _continue if "`jvar'"=="_j" { di as error "j() option needed" } else di as error "data already wide" exit 111 } display as error "i'm confused..." error _rc /* ConfVar `jvar' */ /* exit 198 */ /* just in case */ } } else { /* cmd is "long" */ capture confirm new var `jvar' if _rc { if _rc==110 { di as error "`jvar' already defined -- data already long" exit 110 } confirm new var `jvar' exit 666 /* should never happen */ } } reshape8 clear reshape8 i `i' reshape8 j `jvar' `jvals', `string' reshape8 xij `xvarlist' , `atwl' end program define Xi /* simple variable names */ syntax [varlist] /* foreach var of local varlist { */ /* local theLab : var lab `var' */ /* local lablist "`lablist' `"`theLab'"'" */ /* } */ char _dta[ReS_Xi] "`varlist'" char _dta[ReS_Xi_lab] `"`lablist'"' end program define Xij /* [, atwl(string) */ syntax anything(name=xvarlist id="[Xij]: extended varlist") [, ATwl(string)] if "`xvarlist'"=="" { display as result "[Xij]: Warning, xij list empty" } foreach item of local xvarlist { local item = cond(index("`item'","@"),subinstr("`item'","@","`atwl'",1),"`item'") capture local theLab : var lab `item' if !_rc { local lablist "`lablist' `"`theLab'"'" } } char _dta[ReS_Xij] "`xvarlist'" char _dta[ReS_Xij_lab] `"`lablist'"' char _dta[ReS_atwl] "`atwl'" end program define J /* reshape j [ #[-#] [...] | ...] [, string] */ syntax anything(name=jvals id="J value list") [, string] if "`jvals'"=="" { display as error "[J]: empty j value list" exit 198 } tokenize "`jvals'", parse(" -") local grpvar "`1'" mac shift local isstr 0 while "`1'"!="" { if "`2'" == "-" { local i1 `1' local i2 `3' confirm integer number `i1' confirm integer number `i2' if `i1' > `i2' { di as error "`i1'-`i2': invalid range" exit 198 } forvalues value = `i1'/`i2' { local values `values' `value' } mac shift 3 } else { capture confirm integer number `1' local isstr = `isstr' | _rc local values `values' `1' mac shift } } if `isstr' & "`string'"=="" { di as err "must also specify string option if string values are to be specified" exit 198 } if "`string'"!="" { local isstr 1 } Chkj `grpvar' `isstr' capture ConfVar `grpvar' if !_rc { local theLab: var label `grpvar' char _dta[ReS_j_lab] `"`theLab'"' } char _dta[ReS_j] "`grpvar'" char _dta[ReS_jv] "`values'" char _dta[ReS_str] `isstr' end program define Chkj /* j whether-string */ local grpvar "`1'" local isstr `2' /* grpvar already checked */ capture confirm string var `grpvar' if _rc==0 { if !`isstr' { di as error "`grpvar' is string; specify string option" exit 109 } } else { if `isstr' { di as error "`grpvar' is numeric but string option specified" exit 109 } } end program define Query if "`*'"!="" { error 198 } local cons : char _dta[ReS_i] local grpvar : char _dta[ReS_j] local values : char _dta[ReS_jv] local vars : char _dta[ReS_Xij] local car : char _dta[ReS_Xi] local atwl : char _dta[ReS_atwl] local isstr : char _dta[ReS_str] display if "`grpvar'"!="" { capture ConfVar `grpvar' if _rc { di as result " (dataset is wide)" } else di as result " (dataset is long)" } if "`cons'"=="" { local ccons "as text" local cons "" } if "`grpvar'"=="" { local cgrpvar "as text" local grpvar "" if "`values'"=="" { local values "[<#> - <#>]" } } else if `isstr' { local values "`values', string" } if "`vars'"=="" { local cvars "as text" local vars "" } else { if "`atwl'" != "" { local vars "`vars', atwl(`atwl')" } } if "`car'"=="" { local ccar "as result" local car "" } di in smcl as text "{c TLC}{hline 30}{c TT}{hline 46}{c TRC}" _n /// "{c |} Xij" _col(32) "{c |} Command/contents" _col(79) "{c |}" _n /// as text "{c LT}{hline 30}{c +}{hline 46}{c RT}" di in smcl as text /* */ "{c |} Subscript i,j definitions:" _col(32) "{c |}" _col(79) "{c |}" di in smcl as text /* */ "{c |} group id variable(s)" _col(32) "{c |} reshape8 i " _c Qlist 44 "`ccons'" `cons' di in smcl as text /* */ "{c |} within-group variable" _col(32) "{c |} reshape8 j< " _c Qlist 44 "`cgrpvar'" `grpvar' `values' di in smcl as text /* */ "{c |} and its range" _col(32) "{c |}" _col(79) "{c |}" di in smcl as text "{c |}" _col(32) "{c |}" _col(79) "{c |}" di in smcl as text /* */ "{c |} Variable X definitions:" _col(32) "{c |}" _col(79) "{c |}" di in smcl as text /* */ "{c |} varying within group" _col(32) "{c |} reshape8 xij " _c Qlist 46 "`cvars'" `vars' di in smcl as text /* */ "{c |} constant within group (opt) {c |} reshape8 xi " _c Qlist 46 "`ccar'" `car' di in smcl as text "{c BLC}{hline 30}{c BT}{hline 46}{c BRC}" local cons : char _dta[ReS_i] local grpvar : char _dta[ReS_j] local values : char _dta[ReS_jv] local vars : char _dta[ReS_Xij] local car : char _dta[ReS_Xi] if "`cons'"=="" { di as text `"First type ""' as input "reshape8 i" as text `"" to define the i variable."' exit } if "`grpvar'"=="" { di as text `"Type ""' as input "reshape8 j" as text `"" to define the j variable and, optionally, its values."' exit } if "`vars'"=="" { di as text `"Type ""' as input "reshape8 xij" as text `"" to define variables that vary within i."' exit } if "`car'"=="" { di as text `"Optionally type ""' as input "reshape8 xi" as text `"" to define variables that are constant within i."' } capture ConfVar `grpvar' if _rc { di as text `"Type ""' as input "reshape8 long" as text `"" to convert the data to long form."' exit } di as text `"Type ""' as input "reshape8 wide" as text `"" to convert the data to wide form."' end program define Qlist /* col stuff */ local col `1' local clr "`2'" mac shift 2 while "`1'" != "" { local l = length("`1'") if `col' + `l' + 1 >= 79 { local skip = 79 - `col' di in smcl as text _skip(`skip') "{c |}" _n /* */ "{c |}" _col(32) "{c |} " _c local col 34 } di as res `clr' "`1' " _c local col = `col' + `l' + 1 mac shift } local skip = 79 - `col' di in smcl as text _skip(`skip') "{c |}" end program define Qerror MacroSet1 MacroSet2 capture ConfVar $ReS_j if _rc==0 QerrorW else QerrorL end /* -------------------Wide Specific---------------------------------------- */ program define Wide /* reshape wide */ local oldobs = _N quietly describe, short local oldvars = r(k) MacroSet1 capture ConfVar $ReS_j if _rc { di as text "(already wide)" exit } confirm var $ReS_Xij_long $ReS_i $ReS_Xi MacroSet2 confirm var $ReS_j $ReS_Xi Veruniq * if "$ReS_Xi"!="" reshape8 xi $ReS_Xi preserve capture { if "$ReS_Xi" != "" { tempfile id2xi keep $ReS_i $ReS_Xi by $ReS_i, sort: keep if _n==1 save `id2xi' restore, preserve } tempfile dsvars dsnew hold keep $ReS_j $ReS_Xij_long $ReS_i sort $ReS_i $ReS_j save `dsvars' keep $ReS_i by $ReS_i: keep if _n==1 save "`dsnew'", replace /* datasets initialized, now step through each value: */ tempvar useless global ReS_jv2 local useflag 1 foreach jval of global ReS_jv { if `useflag' use "`dsvars'", clear if $ReS_str keep if $ReS_j=="`1'" else keep if $ReS_j == `jval' if _N==0 { local useflag 0 noi di as text "(note: no data for $ReS_j == `val')" } else { local useflag 1 global ReS_jv2 $ReS_jv2 `jval' drop $ReS_j local cnt 1 foreach xvarname of global ReS_Xij { local newvar = cond(index("`xvarname'","@"),subinstr("`xvarname'","@","`jval'",1),"`xvarname'`jval'") capture confirm new var `newvar' if _rc { capture confirm var `newvar' if _rc { n di as error "`newvar' invalid name" exit 198 } else { n di as error "`newvar' already defined" exit 110 } } local oldvar = cond(index("`xvarname'","@"),subinstr("`xvarname'","@","$ReS_atwl",1),"`xvarname'$ReS_atwl") rename `oldvar' `newvar' local theLab : word `cnt' of $ReS_Xij_lab if "`theLab'"!="" label var `newvar' "`theLab' - `jval'" else label var `newvar' "`oldvar' - `jval'" local cnt = `cnt' + 1 } save "`hold'", replace use "`dsnew'" merge $ReS_i using "`hold'", _merge(`useless') drop `useless' sort $ReS_i save "`dsnew'", replace } } if "`id2xi'" != "" { merge $ReS_i using "`id2xi'", _merge(`useless') drop `useless' } global S_FN global S_FNDATE } /* end big capture block */ if _rc { restore error _rc } restore, not if "`syntax'" != "v.1" { sort $ReS_i } local syntax: char _dta[ReS_ver] if "`syntax'" != "v.1" { ReportW `oldobs' `oldvars' } end program define Veruniq capture by $ReS_i $ReS_j, sort: assert _N==1 if _rc { di as err "$ReS_j not unique within $ReS_i;" di as err "there are multiple observations at the same $ReS_j within $ReS_i." di as err `"Type "reshape8 error" for a listing of the problem observations."' exit 9 } if "$ReS_Xi"=="" { exit } sort $ReS_i $ReS_Xi $ReS_j tempvar cnt1 cnt2 quietly by $ReS_i: gen long `cnt1' = _N quietly by $ReS_i $ReS_Xi: gen long `cnt2' = _N capture assert `cnt1' == `cnt2' if _rc==0 { exit } foreach xivar of global ReS_Xi { capture by $ReS_i: assert `xivar'==`xivar'[1] if _rc { di as err "`xivar' not constant within $ReS_i" } } di as err `"Type "reshape8 error" for a listing of the problem observations."' exit 9 end program define QerrorW ConfVar $ReS_j confirm var $ReS_j $ReS_Xij $ReS_i $ReS_Xi capture by $ReS_i $ReS_j, sort: assert _N==1 if _rc { QerrMsg1 di as text /* */ "The data are in long form; j should be unique within i." _n di as text /* */ "There are multiple observations for the same " /* */ as res "$ReS_j" as text " within " /* */ as res "$ReS_i" as text "." _n tempvar bad quietly by $ReS_i $ReS_j: gen `bad' = _N!=1 quietly count if `bad' di as text /* */ "The following " r(N) /* */ " out of " _N /* */ " observations have repeated $ReS_j values:" list $ReS_i $ReS_j if `bad' di as text _n "(data now sorted by $ReS_i $ReS_j)" exit } if "$ReS_Xi"=="" { di as text "$ReS_j is unique within $ReS_i;" di as text `"there is no error with which "reshape8 error" can help."' exit } sort $ReS_i $ReS_Xi $ReS_j tempvar cnt1 cnt2 quietly by $ReS_i: gen long `cnt1' = _N quietly by $ReS_i $ReS_Xi: gen long `cnt2' = _N capture assert `cnt1' == `cnt2' if _rc==0 { di as text "$ReS_j is unique within $ReS_i and" di as text `"all the "reshape8 xi" variables are constant within $ReS_j;"' di as text `"there is no error with which "reshape8 error" can help."' exit } QerrMsg1 local n : word count $ReS_Xij if `n'==1 { di as text "xij variable is " as res "$ReS_Xij" as text "." } else di as text "xij variables are " as res "$ReS_Xij" as text "." di as text "Thus, the following variable(s) should be constant within i:" di as res _col(7) "$ReS_Xi" sort $ReS_i $ReS_j tempvar bad parse "$ReS_Xi", parse(" ") while "`1'"!="" { capture by $ReS_i: assert `1'==`1'[1] if _rc { qui by $ReS_i: gen long `bad' = /* */ cond(_n==_N,sum(`1'!=`1'[1]),0) qui count if `bad' di _n as res "`1'" as text " not constant within i (" /* */ as res "$ReS_i" as text ") for " /* */ r(N) " value" _c if r(N)==1 { di as text " of i:" } else di as text "s of i:" qui by $ReS_i: replace `bad' = `bad'[_N] list $ReS_i $ReS_j `1' if `bad' drop `bad' } mac shift } di as text _n "(data now sorted by $ReS_i $ReS_j)" end program define QerrMsg1 di _n as text "i (" as res "$ReS_i" /// as text ") indicates the top-level grouping such as subject id." di as text "j (" as res "$ReS_j" /// as text ") indicates the subgrouping such as time." end /* ------------------------Long Specific----------------------------------- */ program define Long /* reshape long */ local oldobs = _N quietly d,s local oldvars = r(k) MacroSet1 confirm var $ReS_i $ReS_Xi capture confirm new var $ReS_j if _rc { di as text "(already long)" exit } MacroSet2 confirm var $ReS_i $ReS_Xi Verluniq TypeCk Longdo2 local syntax: char _dta[ReS_ver] if "`syntax'" != "v.1" { order $ReS_i $ReS_j sort $ReS_i $ReS_j } if "`syntax'" != "v.1" { ReportL `oldobs' `oldvars' } end program define Verluniq local id : char _dta[ReS_i] sort `id' capture by `id': assert _N==1 if _rc { di as err "i=`id' does not uniquely identify the observations;" di as err "there are multiple observations with the same value of `id'." di as err `"Type "reshape8 error" for a listing of the problem observations."' exit 9 } end program define QerrorL confirm var $ReS_i local id "$ReS_i" sort `id' tempvar bad quietly by `id': gen byte `bad' = _N!=1 capture assert `bad'==0 if _rc==0 { di as text "`id' is unique; there is no problem on this score" exit } di _n as text "i (" as res "`id'" as text /* */ ") indicates the top-level grouping such as subject id." di _n as text /* */ "The data are currently in the wide form; there should be be a single" /* */ _n "observation per i". quietly count if `bad' di _n as text r(N) " out of " _N /* */ " observations have duplicate i values:" list `id' if `bad' di as text _n "(data now sorted by `id')" end program define TypeCk /* optimization not needed any more, since it it built in to Stata */ /* --> just check that there is no mix of numeric and non-numeric */ foreach xijvar of global ReS_Xij { foreach val of global ReS_jv { local var = cond(index("`xijvar'","@"),subinstr("`xijvar'","@","`val'",1),"`xijvar'`val'") capture confirm var `var' if _rc==0 { capture confirm str var `var' if "`isanum'" =="" { local isanum = !_rc } else { if `isanum'!=!_rc { noi di as err "`var' has type mismatch with other `xijvar' variables" exit 198 } } } else { capture confirm new var `var' if _rc { di as err "`var' implied name too long" exit 198 } } } } end program define Longdo2 /* reshapes long */ preserve capture { if "$ReS_Xi"!="" { tempfile idxi keep $ReS_i $ReS_Xi sort $ReS_i save `idxi' restore, preserve drop $ReS_Xi tempfile idxij save `idxij' local useme "use `idxij'" local skipread 0 } else { local useme "restore, preserve" local skipread 1 } if $ReS_str { local type str } else { local type long } foreach val of global ReS_jv { foreach xijvar of global ReS_Xij { if `skipread' local skipread 0 else `useme' local newvar = cond(index("`xijvar'","@"),subinstr("`xijvar'","@","$ReS_atwl",1),"`xijvar'$ReS_atwl") local oldvar = cond(index("`xijvar'","@"),subinstr("`xijvar'","@","`val'",1),"`xijvar'`val'") capture confirm var `oldvar' if _rc { noi display as text "(note: `oldvar' not found)" } else { keep $ReS_i `oldvar' drop if missing(`oldvar') rename `oldvar' `newvar' gen `type' $ReS_j = `val' tempfile `newvar' local filelist `filelist' ``newvar'' save ``newvar'' } } } gettoken firstfile filelist : filelist use `firstfile' foreach file of local filelist { append using `file' } local theLab : char _dta[ReS_j_lab] label var $ReS_j `"`theLab'"' local theLabList : char _dta[ReS_Xij_lab] local vnum 1 foreach var of global ReS_Xij_long { local theLab : word `vnum' of `theLabList' label var `var' `"`theLab'"' } sort $ReS_i if "$ReS_Xi"!="" { tempname foo merge $ReS_i using `idxi', _merge(`foo') capture assert `foo'>1 if _rc { display as result "Hmmm... something messed up on the long remerge" } } global S_FN global S_FNDATE } if _rc { restore error _rc } else restore, not end program define MacroSet1 /* reshape macro check utility */ global ReS_j : char _dta[ReS_j] global ReS_jv : char _dta[ReS_jv] global ReS_jv2 global ReS_j_lab : char _dta[ReS_j_lab] global ReS_i : char _dta[ReS_i] global ReS_Xij : char _dta[ReS_Xij] global ReS_Xij_lab : char _dta[ReS_Xij_lab] global ReS_Xi : char _dta[ReS_Xi] global ReS_Xi_lab : char _dta[ReS_Xi_lab] global ReS_atwl : char _dta[ReS_atwl] global ReS_str : char _dta[ReS_str] local syntax : char _dta[ReS_ver] if "$ReS_j"=="" { if "`syntax'"=="v.1" { ErrNotDefd "reshape8 groups" } else ErrNotDefd "reshape8 j" } /* error indicates that $ReS_j is new */ capture ConfVar $ReS_j if _rc==0 { Chkj $ReS_j $ReS_str if $ReS_str==0 { capture assert $ReS_j<. if _rc { di as error "$ReS_j contains missing values" exit 498 } } else { capture assert trim($ReS_j)!="" if _rc { di as error "$ReS_j contains missing values" exit 498 } capture assert $ReS_j==trim($ReS_j) if _rc { di as error "$ReS_j has leading or trailing blanks" exit 498 } } } if "$ReS_jv"=="" { if "`syntax'"=="v.1" { ErrNotDefd "reshape8 groups" } } if "$ReS_i"=="" { if "`syntax'"=="v.1" { ErrNotDefd "reshape8 cons" } else ErrNotDefd "reshape8 i" } if "$ReS_Xij"=="" { if "`syntax'"=="v.1" { ErrNotDefd "reshape8 vars" } else ErrNotDefd "reshape8 xij" } foreach xijvar of global ReS_Xij { local newname = cond(index("`xijvar'","@"),subinstr("`xijvar'","@","$ReS_atwl",1),"`xijvar'$ReS_atwl") local vlist `vlist' `newname' } global ReS_Xij_long `vlist' end program define MacroSet2 /* determine what to do */ capture ConfVar $ReS_j local islong = !_rc local dovalW 0 local dovalL 0 local docar 0 if "$ReS_jv"=="" { if `islong' local dovalL 1 else local dovalW 1 } if "$ReS_Xi"=="" { local syntax : char _dta[ReS_ver] if "`syntax'"=="v.2" { local docar 1 } } if `dovalL' { FillvalL } if `dovalW' { FillvalW } if `docar' { FillXi `islong' } end program define ErrNotDefd /* */ di as err `""`*'" not defined"' exit 111 end program define FillXi /* {1|0} */ /* 1 if islong currently */ local islong `1' unab varlist : _all local varlist : list varlist - global(ReS_j) local varlist : list varlist - global(ReS_i) if `islong' { local usednamelist $ReS_Xij_long } else { /* wide */ foreach xijvar of global ReS_Xij { foreach jval of global ReS_jv { local var= cond(index("`xijvar'","@"),subinstr("`xijvar'","@","`jval'",1),"`xijvar'`jval'") local usednamelist `usednamelist' `var' } } } local varlist : list varlist - usednamelist global ReS_Xi `varlist' end program define FillvalL Tab $ReS_j end program define Tab /* varname */ /* puts values of j variable in $ReS_jv */ local v "`1'" global ReS_jv capture confirm string variable `v' if _rc { tempname rows capture tabulate `v', matrow(`rows') if _rc { if _rc==1 { exit 1 } local bad 1 } else { capture mat list `rows' local bad = _rc } if `bad' { /* theoretically cannot happen */ di as err "$ReS_j contains all missing values" exit 498 } local n = rowsof(`rows') forvalues row=1/`n' { local el = `rows'[`row',1] global ReS_jv $ReS_jv `el' } } else { /* string ReS_j */ quietly { tempvar one by `v', sort: gen byte `one' = _n>1 sort `one' `v' local i 1 while `one'[`i']==0 { local el = `v'[`i'] global ReS_jv $ReS_jv `el' local i = `i' + 1 } } } di as text "(note: j = $ReS_jv)" end program define FillvalW foreach xvar of global ReS_Xij { local l = index("`xvar'","@") local l = cond(`l'==0, length("`xvar'")+1,`l') local left = substr("`xvar'",1,`l'-1) local right = substr("`xvar'",`l'+1,.) local newname "`left'`right'" capture confirm new var `newname' if _rc { display as error "variable `newname' already defined" } unab varlist : `left'*`right' foreach var of local varlist { local value = substr("`var'",length("`left'")+1,length("`var'")-length("`left'")-length("`right'")) local valuelist `valuelist' `value' } } if "`valuelist'"=="" { di as err "no xij variables found" exit 111 } global ReS_jv `valuelist' di as text "(note: j = $ReS_jv)" end /*-------------------- reporting programs --------------------*/ program define ReportL /* old_obs old_vars */ Report1 `1' `2' wide long local n : word count $ReS_jv di as text "j variable (`n' values)" _col(43) "->" _col(48) /* */ as result "$ReS_j" di as text "xij variables:" foreach xijvar of global ReS_Xij { RepF "`xijvar'" local skip = 39 - length("`r(start)'") di as result _skip(`skip') "`r(start)'" _col(43) /// as text "->" /// as result _col(48) "`r(last)'" mac shift } di in smcl as text "{hline 77}" end program define RepF, rclass /* element from ReS_Xij */ local v "`1'" if "$ReS_jv2" != "" { local n : word count $ReS_jv2 tokenize "$ReS_jv2" } else { local n : word count $ReS_jv tokenize "$ReS_jv" } if `n'>=1 local list=cond(index("`v'","@"),subinstr("`v'","@","`1'",1),"`v'`1'") if `n'>=2 { local next = cond(index("`v'","@"),subinstr("`v'","@","`2'",1),"`v'`2'") local list `list' `next' } if `n'==3 { local next = cond(index("`v'","@"),subinstr("`v'","@","``n''",1),"`v'``n''") local list `list' `next' } else if `n'>3 { local next = cond(index("`v'","@"),subinstr("`v'","@","``n''",1),"`v'``n''") local list `list' ... `next' } return local last = cond(index("`v'","@"),subinstr("`v'","@","$ReS_atwl",1),"`v'$ReS_atwl") return local start `list' end program define Report1 /* <#oobs> <#ovars> {wide|long} {long|wide} */ local oobs "`1'" local ovars "`2'" local wide "`3'" local long "`4'" di in smcl _n as text /* */ "Data" _col(36) "`wide'" _col(43) "->" _col(48) "`long'" /* */ _n "{hline 77}" di as text "Number of obs." _col(32) as res %8.0g `oobs' /* */ as text _col(43) "->" as res %8.0g _N quietly desc, short di as text "Number of variables" _col(32) as res %8.0g `ovars' /* */ as text _col(43) "->" as res %8.0g r(k) end program define ReportW /* old_obs old_vars */ Report1 `1' `2' long wide local n : word count $ReS_jv2 local col = 31+(9-length("$ReS_j")) di as text "j variable (`n' values)" /* */ _col(`col') as res "$ReS_j" as text _col(43) "->" /* */ _col(48) "(dropped)" di as text "xij variables:" foreach xijvar of global ReS_Xij { RepF "`xijvar'" local skip = 39 - length("`r(start)'") di as res _skip(`skip') "`r(start)'" _col(43) as text "->" /* */ as res _col(48) "`r(last)'" } di in smcl as text "{hline 77}" end /* utility programs */ /* ConfVar confirms a variable exists and is not an abbreviation */ program define ConfVar capture syntax varname if _rc == 0 & (`"`1'"' == "`varlist'") exit 0 di as error `"`0' not found literally -- abbreviations not allowed"' exit 111 end program define Macdrop foreach gmac in $ReS_Clear $ReS_Keep { global `gmac' } global ReS_Clear global ReS_Keep end program define FixName, rclass /* */ local name "`1'" local sub "`2'" local l = index("`name'","@") local l = cond(`l'==0, length("`name'")+1,`l') local a = substr("`name'",1,`l'-1) local c = substr("`name'",`l'+1,.) return local newname "`a'`sub'`c'" return local left `a' return local right `c' end