*! bihist graphs bihistograms: histograms for two categories shown in opposite directions from the abscissa *! bihist 1.3 19 Apr 2010 Austin Nichols added tw1 option * bihist 1.2 3 Dec 2008 Austin Nichols added support for string by var * bihist 1.1 26 Nov 2008 Austin Nichols fixed labels, added options * bihist 1.0 26 Aug 2008 Austin Nichols prog bihist, rclass version 8.2 syntax varname [fw aw pw] [if] [in], by(string) [FREQuency FRACtion DENSity percent name(passthru) tw(string) tw1(string) otol(int 2) SUPpress * ] * note undocumented otol sets tolerance for order (power of ten) above which to convert units to integers * and option tw passes options to the final twoway graph--all other options * are passed to twoway__histogram_gen gettoken by byopt: by loc by: subinstr local by "," "", all marksample touse cap conf numeric var `by' if _rc { tempvar b encode `by', gen(`b') loc byvar "`by'" loc by "`b'" di as smcl as err "Variable `by' not numeric;" di as smcl as err "using {help encode} to make a numeric variable" di as smcl as err "which may change the ordering of categories." } else loc byvar "`by'" markout `touse' `by' tempvar nvals qui bys `touse' `by' : gen byte `nvals' =(_n == 1)*`touse'*(`by'<.) su `nvals' if `touse', meanonly if r(sum)!=2 { di as err "Variable `by' should have two distinct values but has " r(sum) err 198 } loc v `varlist' tempvar x y wt sum wtvar loc u = 1 qui if "`weight'"!="" { loc wtvar: subinstr local exp "=" "", all capture assert float(`v') == float(round(`v',1)) if `touse' if _rc == 0 { while _rc == 0 { loc u = `u'*10 capture assert float(`v') == float(round(`v',`u')) if `touse' } loc u = `u'/10 } else { while _rc { loc u = `u'/10 capture assert float(`v') == float(round(`v',`u')) if `touse' } } qui g `wt'`exp'/`u' loc tempwt "fw=`wt'" markout `touse' `wt' } else g `wtvar'=1 if "`percent'"!="" loc fraction="fraction" if "`frequency'`fraction'`density'"=="" loc frequency "frequency" twoway__histogram_gen `v' if `touse' [`tempwt'],gen(`x' `y') `frequency' `fraction' `density' `options' loc s=r(min) loc w=r(width) loc b=r(bin)+1 return local min=`s' return local width=`w' return local bin=`b'-1 qui { replace `x'=. replace `x'=`s'+`w'/2 if (`v'>=`s')&(`v'<=`s'+`w') forv i=2/`b' { replace `x'=`s'+(2*`i'-1)*`w'/2 if (`v'>=`s'+(`i'-1)*`w')&(`v'<`s'+(`i')*`w') } replace `x'=`s'+(2*`b'-1)*`w'/2 if float(`v')==float(`s'+(`b')*`w') } qui replace `y'=(`v'<.) loc xl=cond(`"`:var lab `v''"'=="","`v'",`"`:var lab `v''"') preserve qui keep if `touse' cap drop `y' la val `x' `: value label `v'' qui egen double `y'=sum(`wtvar'), by(`by' `x') collapse `y', by(`by' `x') fast bys `by': g double `sum'=sum(`y') if "`fraction'"!="" qui by `by': replace `y'=`y'/`sum'[_N] if "`percent'"!="" qui by `by': replace `y'=`y'*100 if "`density'"!="" qui by `by': replace `y'=`y'/`sum'[_N]/`w' qui levelsof `by', loc(bl) tokenize `bl' su `y', meanonly loc m=r(max) tempname matrix mat forv ni=1/`=_N' { matrix `mat'=(`=`by'[`ni']',`=`x'[`ni']',`=`y'[`ni']') matrix `matrix'=nullmat(`matrix')\ `mat' } loc frac=cond("`percent'"=="","`fraction'","`percent'") matrix `matrix'=`mat' matrix colnames `matrix'=`byvar' `v' `frequency'`frac'`density' return matrix b=`matrix' qui replace `y'=-`y' if `by'==`1' loc o: di int(log10(`m'))-1 if abs(`o')>`otol' { loc M=ceil(`m'/10^`o') qui replace `y'=`y'/10^`o' } else loc M=ceil(`m'/10^`o')*10^`o' loc p=cond(length("`:di `M'/3'")`otol' loc l `"`l'in `=trim("`: di %20.0gc `:di 10^(`o')''")'s")"' if `o'<-`otol' loc l `"`l'in `=trim("`: di %20.0gc `:di 10^-(`o')''")'ths")"' if abs(`o')<=`otol' loc l `"`l'")"' if `"`xl'"'!="" loc l `"`l' xti(`xl')"' loc l `"`l' leg(label(1 "`=cond("`suppress'"=="","`=cond("`:var lab `by''"=="","","`:var lab `by'' = ")'","")'`:label (`by') `1''")"' loc l `"`l' label(2 "`=cond("`suppress'"=="","`=cond("`:var lab `by''"=="","","`:var lab `by'' = ")'","")'`:label (`by') `2''"))"' loc byopt `"barw(`=`w'/2') `byopt'"' cap tw bar `y' `x' if `by'==`1', `tw1' `byopt'|| bar `y' `x' if `by'==`2', `l' `byopt' `tw' `name' if _rc!=0 tw bar `y' `x' if `by'==`1', `byopt'|| bar `y' `x' if `by'==`2', `l' `byopt' `tw' `name' end