program def hbox
*! NJC 1.2.0 2 April 2002
* NJC 1.1.0 27 April 2000
* NJC 1.0.1 26 May 1999
* NJC 1.0.0 3 May 1999
        version 6.0
        syntax varlist(min=1) [if] [in] [aweight fweight] /*
	*/ [, BY(varname) TOtal TItle(str) Qsort(str) SOrt(str) PEn(str) /*
	*/ shown * ]

	if "`sort'" != "" {
		di in r "sort( ) not allowed"
		exit 198
	}

        tokenize `varlist'
	local nvars : word count `varlist'

	if `nvars' > 1 & "`by'" != "" {
		di in r /*
		*/ "by( ) may not be combined with more than one variable"
		exit 198
	}

	if "`qsort'" != "" {
		if index("`qsort'","-") == 1 {
			local sign "-"
			local qsort = substr("`qsort'",2,.)
		}
		local valid 0
		if "`qsort'" == "min" { local valid 1 }
		else if "`qsort'" == "p25" { local valid 1 }
		else if "`qsort'" == "p50" { local valid 1 }
		else if "`qsort'" == "med" {
			local valid 1
			local qsort "p50"
		}
		else if "`qsort'" == "p75" { local valid 1 }
		else if "`qsort'" == "max" { local valid 1 }
		else if "`qsort'" == "n" { local valid 1 }
		else if "`qsort'" == "N" {
			local qsort "n"
			local valid 1
		}
		if !`valid' {
			di in r "qsort: invalid syntax"
			exit 198
		}
	}

	if `"`title'"' == `""' & `nvars' == 1 {
		local title : variable label `varlist'
		if `"`title'"' == `""' { local title "`varlist'" }
	}
	local title `"ti("`title'")"'

	marksample touse, novarlist

	qui if "`by'" != "" {
		sort `touse' `by'
		tempvar group
		by `touse' `by' : gen byte `group' = _n == 1 & `touse'
		replace `group' = sum(`group')
		local ngroup = `group'[_N]
		count if !`touse'
		local vallbl : value label `by'
		local j = 1 + r(N)
		local i = 1
		while `i' <= `ngroup' {
			tempvar by`i'
			gen `by`i'' = `varlist' if `group' == `i'
			local vlbl = `by'[`j']
			if "`vallbl'" != "" {
				cap local vlbl : label `vallbl' `vlbl'
			}
			label var `by`i'' "`vlbl'"
			local newlist "`newlist' `by`i''"
			count if `group' == `i'
			local j = `j' + r(N)
			local i = `i' + 1
		}
		if "`total'" != "" {
		 	tempvar copy
			gen `copy' = `varlist'
			label var `copy' "Total"
			local newlist "`newlist' `copy'"
		}
		local varlist "`newlist'"
		tokenize `varlist'
		local nvars : word count `varlist'
	}

        tempvar min p25 p50 p75 max n names d1 d2 d3 d4
        tempname stat
        qui {
                univstat `varlist' [`weight' `exp'] if `touse', /*
		*/ s(min p25 p50 p75 max n) m(`stat')
                svmat2 `stat', n(`min' `p25' `p50' `p75' `max' `n')
                gen `d1' = `p25' - `min'
                gen `d2' = `p50' - `p25'
                gen `d3' = `p75' - `p50'
                gen `d4' = `max' - `p75'
		gen str1 `names' = ""
		local i = 1
		while `i' <= `nvars' {
			local name "``i''"
			local label : variable label ``i''
			if "`label'" != "" { local name "`label'" }
			replace `names' = "`name'" in `i'
			local i = `i' + 1
		}
        }

	if "`qsort'" != "" { local sort "sort(`sign'``qsort'')" }

	if "`pen'" == "" { local pen "pen(22222)" }
	else {
		local pen = substr("`pen'",1,1)
		local pen : di _dup(5) "`pen'"
		local pen "pen(`pen')"
	}

	if "`shown'" != "" { local options "`options' rl(`n')" }

        Hbar `min' `d1' `d2' `d3' `d4' in 1/`nvars', `sort' showzero /*
        */ `pen' `options' t2(" ") l(`names') `title' sh(nl..r)
end

* Hbar 1.0.0 NJC 2 April 2002
* hbar 1.4.4 NJC 8 November 1999
program define Hbar
    version 6.0

    #delimit ;
    syntax varlist( numeric) [if] [in]
    [ , BOrder SOrt(str) noXaxis noYaxis PEn(str)
    SHading(str) T1title(str) T2title(str) TItle(str asis) TTIck VALLBL(varname)
    XLAbel(numlist) XLIne(numlist) XSCale(str) XTIck(numlist) Axtol(int 600)
    Barfrac(real 0.6) BLank flipt Format(str) FONTC(int 290) FONTR(int 570)
    FONTCB(int 444) FONTRB(int 923) GAPMag(real 1) GAPs(numlist int)
    GLegend(str) gllj GLPos(int -1) t2m(int 0) LAP Legend(varname) NIT2
    Openbar(str) RLegend(varname) rllj RLPos(int 31500) tim(int 0)
    Vat(str) VATFmt(str) VATPos(int 31500) Cstart(int -1) SAving(str) VAP
    t1m(int 0) PENText(int 1) SHOWZERO ] ;
    #delimit cr

    qui {
        tempvar touse order gleg gap dpos dpos2 dmax
        mark `touse' `if' `in'
        Markout2 `touse' `varlist'
        gen `order' = _n
        gsort - `touse' `sort' `order'
        count if `touse'
        loc nuse = r(N)

	tokenize `varlist'
	args dmin d1 d2 d3 d4

        * legend on left
        if "`legend'" == "" {
            tempvar legend
            g str1 `legend' = " "
            if "`blank'" == "" {
                replace `legend' = string(_n) if `touse'
            }
        }
        else {
            capture confirm string variable `legend'
            if _rc == 7 {
                tempvar legend2
                capture decode `legend', g(`legend2')
                if _rc {
                    gen str1 `legend2' = ""
                    replace `legend2' = string(`legend')
                }
                else {
                    replace `legend2' = string(`legend') /*
                    */ if missing(`legend2')
                }
                loc legend "`legend2'"
            }
        }
        loc leglen : type `legend'
        loc leglen = substr("`leglen'",4,.)
        if `cstart' == -1 {
            loc cstart = 2000 + int(9000 * `leglen' / 25)
        }

	* legend on right
        if "`rlegend'" != "" {
            capture confirm string variable `rlegend'
            if _rc == 7 {
                tempvar rleg2
                capture decode `rlegend', g(`rleg2')
                if _rc == 0 {
                    replace `rleg2' = string(`rlegend') /*
                    */ if missing(`rleg2')
                    loc rlegend "`rleg2'"
                }
	    }
	}

        * axis scale
        if "`xscale'" != "" {
            tokenize "`xscale'", parse(",")
            if "`4'" != "" | "`2'" != "," {
                di in r "invalid xscale( ) option"
                exit 198
            }
            loc xscmin `1'
            loc xscmax `3'
        }

        if "`xscmin'" == "" { loc min 0 }
        else loc min `xscmin'
        if "`xscmax'" == "" { loc max 0 }
        else loc max `xscmax'

        * xlabel xtick xline might extend graph range beyond data range
        if "`xlabel'`xtick'`xline'" != "" {
            numlist "`xlabel' `xtick' `xline'", sort
            loc nn : word count `r(numlist)'
            loc xmin : word 1 of `r(numlist)'
            loc xmax : word `nn' of `r(numlist)'
            loc min = min(`min', `xmin')
            loc max = max(`max', `xmax')
        }

        * gap legend?
        g str1 `gleg' = " "
        loc glj = cond("`gllj'" != "", -1, 1)
        if "`glegend'" != "" {
            tokenize "`glegend'", parse("!")
            loc j 1
            while "`1'" != "" {
                if "`1'" != "!" {
                    if "`1'" == "." { loc 1 " " }
                    loc gleg`j' "`1'"
                    loc j = `j' + 1
                }
                mac shift
            }
        }

        * gaps between bars?
        g byte `gap' = 0
        if "`gaps'" != "" {
            loc j 1
            numlist "`gaps'", int range(>=0)
            tokenize `r(numlist)'
            while "`1'" != "" {
                if "`1'" == "0" {
                    loc gleg0 "`gleg`j''"
                    if "`gleg0'" == "" { loc gleg0 " " }
                }
                else {
                    replace `gap' = 1 in `1' if `1' <= `nuse'
                    replace `gleg' = "`gleg`j''" in `1' if `1' <= `nuse'
                }
                loc j = `j' + 1
                mac shift
            }
        }
        count if `gap'
        loc ngaps = r(N) + ("`gleg0'" != "")

        * data range
        g `dmax' = `dmin'
        local i = 1
        while `i' <= 4 {
            replace `dmax' = `dmax' + `d`i''
	    local i = `i' + 1
        }
        su `dmin' if `touse', meanonly
        loc dminmin = r(min)
        su `dmax' if `touse', meanonly
        loc dmaxmax = r(max)
        loc min = min(`min', `dminmin')
        loc max = max(`max', `dmaxmax')
        loc drange = `max' - `min'
        loc zero = cond(`min' >= 0, max(0,`min'), min(0,`max'))
        g `dpos2' = `zero'
        g `dpos' = 0
    }

    * show zeros?
    loc showz = "`showzero'" != ""

    * start of parameter block

    loc t1start 1000       /* row for t1title */
    loc t2start 1900       /* row for t2title */
    loc ybeg 2400          /* start of y-axis */
    loc ylength 17600

    * `axtol' is space at ends of y-axis
    * axtol too large => ystep negative FW
    if `axtol' > `ylength' / 2 {
        di in bl "axtol too large: reset to default 600"
        loc axtol 600
    }

    * row where first bar starts
    loc ystart = `ybeg' + `axtol'

    * step between bars: one gap defaults to one bar
    loc ystep = (`ylength' - 2 * `axtol')
    loc ystep = `ystep' / (`nuse' - 1 + `barfrac' + `ngaps' * `gapmag')

    loc yend = `ybeg' + `ylength'
    loc ynudge = 200 * (`fontr'/570)^2
                               /* text displaced downwards from bars */
    loc ytick 400          /* tick length */
    loc yleg 1000          /* labels down from axis */
    loc yleg = `yend' + `yleg'
    loc ytitle 1400        /* title down from labels */
    loc ytitlef 900        /* title down from labels, flip titles */
    loc xstart `cstart'    /* col where first bar begins */
    loc xgap 400           /* gap between left legend and body of plot */
    loc xbeg = `xstart' - `xgap'
    if `glpos' == -1 { loc glpos `xbeg' }
    loc xlength = 30000 - `xstart'
                               /* horizontal extent of data region */
    loc xend = `xbeg' + `xgap' + `xlength'
    loc xz = `xbeg' + `xgap' + `xlength' * (`zero' - `min') / `drange'
    loc mcent = (`cstart' + 30000)/2 + `tim'
                               /* col where main title centred */
    loc keyb1 300              /* dimensions of key box */
    loc keyb2 300

    if "`format'" == "" { loc format "%1.0f" }
    if "`vatfmt'" == "" { loc vatfmt "%1.0f" }

    * end of parameter block

    * start gph
    if "`saving'" != "" { loc saving ", saving(`saving')" }
    gph open `saving' /* FW */
    gph pen `pentext'
    gph font `fontr' `fontc'

    * y-axis
    if "`yaxis'" == "" { gph line `ybeg' `xstart' `yend' `xstart' }

    * ttick => top ticks
    loc ttick = "`ttick'" == "ttick"
    * ttick should => border FW
    if `ttick' { loc border "border" }

    * x-axis and labels
    if "`xaxis'" == "" {
        gph line `yend' `xstart' `yend' `xend'
        loc ytick2 = `ybeg' - `ytick'/2
        loc ytick = `yend' + `ytick'
        if "`xlabel'" == "" {
            gph line `yend' `xstart' `ytick' `xstart'
            gph line `yend' `xend' `ytick' `xend'
            if `ttick' {
                gph line `ybeg' `xstart' `ytick2' `xstart'
                gph line `ybeg' `xend' `ytick2' `xend' /* FW */
            }
            loc text = cond("`lap'" == "lap", abs(`min'), `min')
            loc text : di `format' `text'
            gph text `yleg' `xstart' 0 0 `text'
            loc text = cond("`lap'" == "lap", abs(`max'), `max')
            loc text : di `format' `text'
            gph text `yleg' `xend' 0 0 `text'
        }
        else {
            numlist "`xlabel'"
            tokenize `r(numlist)'
	    if "`vallbl'" != "" {
	    	local vallbl : value label `vallbl'
	    }
            while "`1'" != "" {
                loc xtickp = /*
                */ `xbeg' + `xgap' + `xlength' * (`1' - `min')/`drange'
                gph line `yend' `xtickp' `ytick' `xtickp'
                if `ttick' {
                    gph line `ybeg' `xtickp' `ytick2' `xtickp'
                }
                loc text = cond("`lap'" == "lap", abs(`1'), `1')
		if "`vallbl'" != "" {
		    local label : label `vallbl' `text'
		    if "`label'" != "" { local text "`label'" }
		}
                else loc text : di `format' `text'
                gph text `yleg' `xtickp' 0 0 `text'
                mac shift
            }
        }
    }

    * x-ticks
    if "`xtick'" != "" {
        numlist "`xtick'"
        tokenize `r(numlist)'
        while "`1'" != "" {
            loc xtickp = /*
            */ `xbeg' + `xgap' + `xlength' * (`1' - `min')/`drange'
            gph line `yend' `xtickp' `ytick' `xtickp'
            if `ttick' {
                gph line `ybeg' `xtickp' `ytick2' `xtickp'
            }
            mac shift
        }
    }

    * x-lines
    if "`xline'" != "" {
        numlist "`xline'"
        tokenize `r(numlist)'
        while "`1'" != "" {
            loc xli = `xbeg' + `xgap' + `xlength' * (`1' - `min')/`drange'
            gph line `yend' `xli' `ybeg' `xli'
            mac shift
        }
    }

    * border
    if "`border'" != "" {
        gph line `ybeg' `xstart' `ybeg' `xend'
        gph line `ybeg' `xend' `yend' `xend'
        if "`xaxis'" != "" { gph line `yend' `xstart' `yend' `xend' }
    }

    * gap legend above first data point
    if "`gleg0'" != "" {
        loc y2 = `ystart' - (1 - 0.5 * `barfrac') * `ystep' + `ynudge'
        gph text `y2' `glpos' 0 `glj' `gleg0'
    }

    tokenize `varlist'
    loc nvars : word count `varlist'
    loc nv = 1 + int(`nvars' / 5)

    if "`pen'" == "" { loc pen : di _dup(`nv') "23451" }
    if "`shading'" == "" { loc shading : di _dup(`nv') "01234" }
    else if length("`shading'") == 1 & `nvars' > 1 {
            loc shading : di _dup(`nvars') "`shading'"
    }
    if "`openbar'" == "" { loc openbar: di _dup(`nvars') "n" }
    if "`vat'" == "" { loc vat : di _dup(`nvars') "." }
    else if length("`vat'") == 1 & `nvars' > 1 {
            loc vat : di _dup(`nvars') "`vat'"
    }

    loc l = length("shading")
    loc nshow = `nvars'
    loc i 1
    while `i' <= `l' {
        loc char = substr("`shading'",`i',1)
        if "`char'" == "n" { loc nshow = `nshow' - 1 }
        loc i = `i' + 1
    }

    * for each variable
    loc j 1

    while "`1'" != "" {

        loc data "`1'"
        loc sh = substr("`shading'",`j',1)
        loc pe = substr("`pen'",`j',1)
        loc open = substr("`openbar'",`j',1)
        loc v = substr("`vat'",`j',1)
        loc y `ystart'
        if "`gleg0'" != "" { loc y = `y' + `ystep' * `gapmag' }
        qui replace `dpos' = `dpos' + `data'

        * for each observation
        loc i 1
        while `i' <= `nuse'  {

            * bars
            gph pen `pe'
            loc y1 = `y' + `barfrac' * `ystep'
            loc y2 = `y' + 0.5 * `barfrac' * `ystep' + `ynudge'
            loc value = `data'[`i']
            loc x = `xbeg' + `xgap' + /*
            */ `xlength' * (`dpos'[`i'] - `min') / `drange'
            loc x1 = `xbeg' + `xgap' + /*
            */ `xlength' * (`dpos2'[`i'] - `min') / `drange'
	    loc show = `showz' & `value' == 0 & "`sh'" != "n"
	    loc show = `show' + (`value' != 0 & `value' != . & "`sh'" != "n")
            if `show' {
                if "`sh'" == "." {
                    gph line  `y' `x' `y' `x1'
                    if "`open'" != "y" { gph line  `y' `x1' `y1' `x1' }
                    gph line  `y1' `x1' `y1' `x'
                    gph line  `y1' `x' `y' `x'
                }
                else if index("-rRlLbB","`sh'") {
                    loc ym = (`y' + `y1') / 2
                    gph line `ym' `x' `ym' `x1'
                    if index("rRlLbB", "`sh'") {
                        loc xmin = min(`x',`x1')
                        loc xmax = max(`x',`x1')
                        loc yu = (3 * `y' + `y1') / 4
                        loc yl = (3 * `y1' + `y') / 4
                        if index("rb", "`sh'") {
                            gph line `yu' `xmax' `yl' `xmax'
                        }
                        else if index("RB", "`sh'") {
                            gph line `y1' `xmax' `y' `xmax'
                        }
                        if index("lb", "`sh'") {
                            gph line `yu' `xmin' `yl' `xmin'
                        }
                        else if index("LB", "`sh'") {
                            gph line `y1' `xmin' `y' `xmin'
                        }
                    }
                }
                else gph box `y' `x' `y1' `x1' `sh'
            }

            * values as text
            gph pen `pentext'
            if "`v'" != "." & `value' != . {
                Hbar_v `value' `v' `x' `x1' `vatpos'
                loc vatpos $S_1
                loc jus $S_2
                if "`vap'" != "" { loc text = abs(`value') }
                else loc text = `value'
                loc text : di `vatfmt' `text'
                gph text `y2' `vatpos'  0 `jus' `text'
            }

            * legend
            if `j' == 1 {
                loc text = `legend'[`i']
                gph text `y2' `xbeg'  0 1 `text'
            }

	    * right legend
	    if `j' == 1 & "`rlegend'" != "" {
	    	local text = `rlegend'[`i']
		local rlj = cond("`rllj'" != "", -1, 1)
		gph text `y2' `rlpos' 0 `rlj' `text'
	    }

            * gap
            if `gap'[`i'] {
                loc y = `y' + `ystep' * `gapmag'
                if `j' == 1 {
                    loc text = `gleg'[`i']
                    loc y2 = `y' + 0.5 * `barfrac' * `ystep' + `ynudge'
                    gph text `y2' `glpos'  0 `glj' `text'
                }
            }

            loc y = `y' + `ystep'
            loc i = `i' + 1
        }
        * next observation

        qui replace `dpos2' = `dpos'
        loc j = `j' + 1
        mac shift
    }
    * next variable

    * t2title, left justified (defaults to key for 2 or more variables)
    if "`t2title'" != "" & trim("`t2title'") == "" {
        loc t2title
    }
    else if "`t2title'" != "" {
        loc xl = `xstart' + `t2m'
        gph text `t2start' `xl' 0 -1 `t2title'
    }
    else if `nvars' >= 2 {
        loc t2l = `t2start' - `ynudge' + `keyb1'
        loc t2u = `t2start' - `ynudge' - `keyb2'
        loc xjump =  `xlength' / `nshow'
        loc xjump2 = `xjump' / 50
        loc xl = `xstart' + `t2m' + `xjump2' - `keyb1'
        loc xr = `xstart' + `t2m' + `xjump2' + `keyb2'
        loc j 1
        while `j' <= `nvars' {
            loc sh = substr("`shading'",`j',1)
            if "`sh'" == "n" {
                loc j = `j' + 1
                loc sh = substr("`shading'",`j',1)
            }
            loc pe = substr("`pen'",`j',1)
            gph pen `pe'
            if "`sh'" == "." {
                gph line  `t2l' `xl' `t2u' `xl'
                gph line  `t2u' `xl' `t2u' `xr'
                gph line  `t2u' `xr' `t2l' `xr'
                gph line  `t2l' `xr' `t2l' `xl'
            }
            else if index("01234","`sh'") {
                gph box `t2l' `xr' `t2u' `xl' `sh'
            }
            loc x2 = `xr' - `fontc'/2
            loc var : word `j' of `varlist'
            if "`nit2'" == "" {
                loc text : variable label `var'
                if "`text'" == "" { loc text "`var'" }
            }
            else loc text "`var'"
            gph pen `pentext'
            gph text `t2start' `x2' 0 -1 `text'
            loc xl = `xl' + `xjump'
            loc xr = `xr' + `xjump'
            loc j = `j' + 1
        }
    }

    * title and t1title
    if `"`title'"' == `""' & `nvars' == 1 {
        loc title : variable label `data'
        if "`title'" == "" { loc title "`data'" }
    }
    else if `"`title'"' != `""' { loc title `title' }

    loc xL = `xstart' + `t1m'
    if "`flipt'" == "" { /* default */
        * t1title, left justified
        gph text `t1start' `xL' 0 -1 `t1title'

        * main title at bottom, centred
        gph font `fontrb' `fontcb'
        loc ytitle = `yleg' + `ytitle'
        gph text `ytitle' `mcent' 0 0 `title'
    }
    else { /* flip titles from default */
        * bottom title, centred (and closer to axis than default)
        loc ytitle = `yleg' + `ytitlef'
        gph text `ytitle' `mcent' 0 0 `t1title'

        * main title at top, left justified
        gph font `fontrb' `fontcb'
        gph text `t1start' `xL' 0 -1 `title'
    }

    gph close
end

program def Hbar_v  /* values as text */
version 6.0
args val v x x1 vbp

if index("Lre","`v'") { loc jus 1 }
else if index("lR", "`v'") { loc jus -1 }
else if "`v'" == "m" { loc jus 0 }
else if index("Nf", "`v'") { loc jus = cond(`val' > 0, 1, -1) }
else if index("nF", "`v'") { loc jus = cond(`val' > 0, -1, 1) }
else loc jus 1

if index("rR", "`v'") { loc vp `x' }
else if index("lL", "`v'") { loc vp `x1' }
else if "`v'" == "m" { loc vp = (`x' + `x1')/2 }
else if index("Nn", "`v'") { loc vp = cond(`val' > 0, `x1', `x') }
else if index("Ff", "`v'") { loc vp = cond(`val' > 0, `x', `x1') }
else if "`v'" == "e" { loc vp `vbp' }

global S_1 `vp'
global S_2 `jus'

end

program def Markout2 /* marks out obs with all missing values */
* 1.0.2 NJC 16 February 1999
* 1.0.1 NJC 25 March 1998
    version 6.0
    syntax varlist(min=1) [, Strok ]
    tokenize `varlist'
    loc nvars : word count `varlist'
    if `nvars' == 1 { exit 0 }
    loc nvars = `nvars' - 1
    loc markvar `1'
    mac shift
    tempvar nmiss
    gen `nmiss' = 0
    qui {
        while "`1'" != "" {
            loc type : type `1'
            if substr("`type'",1,3) == "str" {
                if "`strok'" != "" { replace `nmiss' = `nmiss' + (`1' == "") }
                else replace `nmiss' = `nmiss' + 1
           }
           else replace `nmiss' = `nmiss' + (`1' == .)
           mac shift
        }
        replace `nmiss' = `nmiss' == `nvars'
        replace `markvar' = 0 if `nmiss'
    }
end