*! version 1.2.4 TJS 31aug98 STB-46 gr33 program define violin version 5.0 local varlist "req ex min(1)" local if "opt" local in "opt" local weight "fweight aweight" #delimit ; local options "N(integer 50) Width(real 0.0) TRUncat(str) BIweight COSine EPan GAUss RECtangle PARzen TRIangle BY(str) Gap(integer 0) ROund(real 0.0) SAving(str) B2title(str) *" ; #delimit cr parse "`*'" parse "`varlist'", parse(" ") * trap bad options if index("`options'","tr") > 0 { di in re "option tr ambiguous, " _c error 199 } if "`b2title'" != "" { di in bl "b2title not allowed; option ignored." } * -> Kernel Density code stolen from kdensity.ado local kflag = ( ("`epan'" != "") + ("`biweigh'" != "") + /* */ ("`triangl'" != "") + ("`gauss'" != "") + /* */ ("`rectang'" != "") + ("`parzen'" != "") ) if `kflag' > 1 { di in red "specify only one kernel" exit 198 } if "`biweigh'" != "" { local kernel = "Biweight" } else if "`cosine'" != "" { local kernel = "Cosine" } else if "`triangl'" != "" { local kernel = "Triangle" } else if "`gauss'" != "" { local kernel = "Gaussian" } else if "`rectang'" != "" { local kernel = "Rectangular" } else if "`parzen'" != "" { local kernel = "Parzen" } else { local kernel = "Epanechnikov" } tempvar use quietly { mark `use' [`weight'`exp'] `if' `in' markout `use' `varlist' count if `use' } if _result(1) == 0 { error 2000 } if "`by'" != "" { confirm var `by' unabbrev `by' local by $S_1 } if "`if'" != "" {ifexp "`if'"} preserve /* Note: data preserved here */ keep `by' `varlist' `use' local n1 = `n' + 1 local n2 = `n' * 2 + 1 if `n2' > _N { qui set obs `n2' } * Generate BY groups tempvar kk byg bylabel sort `use' `by' qui by `use' `by': gen byte `byg' = _n == 1 if `use' if "`by'" != "" { qui gen `kk' = _n if `byg' == 1 } qui replace `byg' = sum(`byg') if "`by'" != "" { local byn = `byg'[_N] sort `kk' if `use'[`byn'] == . { local byn = `byn' - 1} } else { local byn = 1 } * Generate `by' labels -- if required if "`by'" != "" { capture decode `by', gen(`bylabel') if _rc != 0 { local type : type `by' qui gen `type' `bylabel' = `by' } } tempname t2flg b1flg global t2flg = 0 global b1flg = 0 * Do calculations * get # of vars local i 1 while "``i''" != "" { local i = `i' + 1 } local nvars = `i' - 1 if `nvars' > 1 & "`by'" != "" { di in red "by() cannot be used with /* */ multi-variable varlist" exit } * Note: `k' loops over multiple individual variables * `j' loops over the levels of a -by- variable local k 1 while "``k''" != "" { local ix "``k''" local ixl: variable label ``k'' if "`ixl'" == "" | `nvars' > 1 { local ixl "``k''" } local j = 1 while `j' <= `byn' { /* start of loop for each `by' group */ if "`by'" != "" { sort `kk' local byl : di "`by': " `bylabel'[`j'] } * boxplot stats qui centile `ix' if `use' & `byg' == `j', c(25 50 75) local q25 = $S_7 local q50 = $S_8 local q75 = $S_4 * compute additional boxplot info tempvar xi local uav = `q75' + 1.5 * (`q75' - `q25') qui egen `xi' = max(`ix') /* */ if `ix' <= `uav' & `use' & `byg' == `j' local uav = `xi' drop `xi' local lav = `q25' - 1.5 * (`q75' - `q25') qui egen `xi' = min(`ix') /* */ if `ix' >= `lav' & `use' & `byg' == `j' local lav = `xi' drop `xi' if `j' == 1 { quietly summ `ix' [`weight'`exp'] if `use', detail local ismin = _result(5) local ismax = _result(6) if "`by'" != "" { local isn = _result(1) local ismn = _result(5) local ismx = _result(6) local ism = _result(10) local is25 = _result(9) local is75 = _result(11) local iss = 0 local isw = 0 } } if `j' == 1 & "`by'" != "" { if `width' <= 0 { tempname wwidth local ismin = `ism' local ismax = `ism' local jj 1 while `jj' <= `byn' { quietly summ `ix' [`weight'`exp'] /* */ if `use' & `byg' == `jj', detail scalar `wwidth' = 0.9 * min(sqrt(_result(4)), /* */ (_result(11) - _result(9)) / 1.349) /* */ / (_result(1)^.2) local ismin = min(`ismin', _result(5) - `wwidth') local ismax = max(`ismax', _result(6) + `wwidth') local jj = `jj' + 1 } } else { local ismin = `ismn' - `width' local ismax = `ismx' + `width' } } quietly summ `ix' [`weight'`exp'] if `use' & `byg' == `j', detail local ixmin = _result(5) local ixmax = _result(6) local ixn = _result(1) if `gap' == 0 { local gp = 1 + max( /* */ length(string(round(`ixmin', `round'))), /* */ length(string(round(_result(10),`round'))), /* */ length(string(round(`ixmax', `round')))) } else { local gp = `gap' } tempname wwidth scalar `wwidth' = `width' if `wwidth' <= 0.0 { scalar `wwidth' = 0.9 * min(sqrt(_result(4)),(_result(11) /* */ - _result(9)) / 1.349) / (_result(1)^.2) } local ww = `wwidth' tempvar d m qui gen double `d' = . qui gen double `m' = . kd `ix' `d' `m' `use' `byg' [`weight'`exp'], n(`n') /* */ ww(`ww') j(`j') `biweight' `cosine' `epan' /* */ `gauss' `rectangle' `parzen' `triangle' label var `d' "density" label var `m' "`ixl'" * truncat option if "`truncat'" != "" { if "`truncat'" == "*" { local tn = `ixmin' local tx = `ixmax' } else { quietly summ `m' [`weight'`exp'] if `use', detail local ismn = _result(5) local ismx = _result(6) local nc 1 while `nc' > 0 { local nc = index("`truncat'",",") if `nc' > 0 { local truncat = substr("`truncat'",1, /* */ `nc' - 1) + " " + substr("`truncat'",`nc' + 1,.) } } local tn: word 1 of `truncat' local tx: word 2 of `truncat' local tn = real("`tn'") local tx = real("`tx'") if `tn' > `ismn' { local tn = min(`tn',`ixmin') } if `tx' < `ismx' { local tx = max(`tx',`ixmax') } } qui replace `m' = . if `m' < `tn' | `m' > `tx' } qui summ `d' in 1/`n' local scale = 1 / (`n' * _result(3)) qui replace `d' = `d' * `scale' in 1/`n' local n21 = `n' * 2 + 1 qui replace `d' = -`d'[`n21' - _n] in `n1'/`n2' qui replace `m' = `m'[`n21' - _n] in `n1'/`n2' qui replace `d' = `d'[1] in `n2' qui replace `m' = `m'[1] in `n2' if "`truncate'" != "" { tempvar tm1 tm2 qui gen `tm2' = _n qui gen `tm1' = sign(`d') gsort -`tm1' `m' local tm = `m'[1] local td = `d'[1] sort `tm2' qui replace `d' = `td' in `n2' qui replace `m' = `tm' in `n2' } if "`by'" != "" { local iss = `iss' + `scale' local isw = `isw' + `wwidth' } * saving option if `j' * `k' == 1 & "`saving'" != "" { local c = index("`saving'",",") local cs " " if index("`saving'",", ") != 0 { local cs "" } if `c' != 0 { local saving = substr("`saving'",1,`c' - 1) /* */ + "`cs'" + substr("`saving'",`c' + 1, .) } local savfile : word 1 of `saving' local replace : word 2 of `saving' if "`replace'" == "replace" { capture erase "`savfile'.gph" } capture confirm new file "`savfile'.gph" if _rc == 0 { local saving ", saving(`savfile')" } else { local rc = _rc di in re "file `savfile'.gph exists." di in bl "use another filename or add 'replace' option." exit `rc' } } if "`byl'" != "" { local bylbyl byl("`byl'") } tempname ixlixl global ixlixl "`ixl'" * do plot if `j' * `k' == 1 { gph open `saving' } viogph `d' `m', j(`j') k(`k') byn(`byn') ixmin(`ixmin') /* */ ixmax(`ixmax') q50(`q50') ismin(`ismin') ismax(`ismax') /* */ nvars(`nvars') gp(`gp') `bylbyl' uav(`uav') lav(`lav') /* */ q75(`q75') q25(`q25') rou(`round') `options' if `j' >= `byn' & `k' >= `nvars' { gph close } * display stats if `byn' == 1 { di _n in gr "Statistics for ``k'':" di in gr " LAV: " in ye `lav' _c di in gr " Q25: " in ye `q25' _c di in gr " Q75: " in ye `q75' _c di in gr " UAV: " in ye `uav' di in gr " Min: " in ye `ixmin' _c di in gr " Median: " in ye `q50' _c di in gr " Max: " in ye `ixmax' _c di in gr " n: " in ye `ixn' di _n in gr "For ``k'', density computed using:" di in gr " Kernel: " in ye "`kernel'" _c di in gr " N: " in ye `n' _c di in gr " Scale: " in ye %6.2f `scale' _c di in gr " Width: " in ye %6.2f `wwidth' } local j = `j' + 1 } /* end of loop for each `by' group */ if "`by'" != "" { di _n in gr "Statistics (all groups combined): " di in gr " Min: " in ye `ismn' _c di in gr " Q25: " in ye `is25' _c di in gr " Median: " in ye `ism' _c di in gr " Q75: " in ye `is75' _c di in gr " Max: " in ye `ismx' _c di in gr " n: " in ye `isn' di _n in gr "Densities computed using:" di in gr " Kernel: " in ye "`kernel'" _c di in gr " N: " in ye `n' _c di in gr " Ave. Scale: " in ye %6.2f `iss' / `byn' _c di in gr " Ave. Width: " in ye %6.2f `isw' / `byn' local scale = `iss' / `byn' local wwidth = `isw' / `byn' local ixmin = `ismn' local lav = . local q25 = `is25' local q50 = `ism' local q75 = `is25' local uav = . local ixmax = `ismx' local ixn = `isn' } local k = `k' + 1 } * save globals global S_1 "`kernel'" global S_2 = `n' global S_3 = `wwidth' global S_4 = `scale' global S_5 = `ixmin' global S_6 = `lav' global S_7 = `q25' global S_8 = `q50' global S_9 = `q75' global S_10 = `uav' global S_11 = `ixmax' global S_12 = `ixn' macro drop ixlixl b1flg t2flg end program define viogph version 5.0 local varlist "req ex min(2) max(2)" #delimit ; local options "J(int 1) K(int 1) BYN(int 1) TItle(str) B1title(str) IXMIN(real 0.0) IXMAX(real 0.0) Q50(real 0.0) ISMIN(real 0.0) ISMAX(real 0.0) NVARS(int 0) GP(int 3) BYL(str) UAV(real 0.0) LAV(real 0.0) Q75(real 0.0) Q25(real 0.0) Pen(str) Symbol(str) Connect(str) T1title(str) T2title(str) YLAbel(str) YSCale(str) ROUnd(real 0.0) *" ; #delimit cr parse "`*'" parse "`varlist'", parse(" ") local d "`1'" local m `2' local t2t2 = $t2flg local b1b1 = $b1flg local ixl = "$ixlixl" * set up the plot if "`pen'" == "" { local pen "2" } if "`symbol'" == "" { local symbol "i" } if "`connect'" == "" { local connect "l" } if `j' == 1 & `k' == 1 { if "`t1title'" == "." { local t1title t1t(" ") } else if "`t1title'" == "" { local t1title t1t(Violin Plot) } else { local t1title t1t("`t1title'") } if `byn' > 1 { local t1title t1t("`ixl'") } } if `j' > 1 | `k' > 1 { local t1title t1t(" ") } if `j' == 1 & `k' == 1 { if "`t2title'" != "" { local t2title t2t("`t2title'") local t2t2 1 } } else if `t2t2' == 1 { local t2title t2t(" ") } if "`title'" == "" { local title "`b1title'" } if "`title'" != "" { local b1title b1t(" ") local b1b1 1 } if "`ylabel'" == "" { local yl = "yla(" /* */ + string(round(`ixmin',`round')) + "," /* */ + string(round(`q50',`round')) + "," /* */ + string(round(`ixmax',`round')) + ")" } else { local yl yla(`ylabel') } if index("`options'","yla") > 0 { local yl "" } if "`yscale'" == "" { local ys ysc(`ismin',`ismax') } else { local ys ysc(`yscale') } * do plot * draw density traces local pw = min(.33, 1 / (`byn' * `nvars') ) local pw = 32000 * `pw' local p1 = (`j' * `k' - 1) * `pw' local p2 = `p1' + `pw' #delimit ; graph `m' `d', bbox(0,`p1',23063,`p2',923,444,0) s(`symbol') c(`connect') pe(`pen') `t1title' `yl' gap(`gp') `ys' `t2title' `b1title' b2t(" ") `options' ; #delimit cr tempname ysca yloc xloc scalar `ysca' = _result(5) scalar `yloc' = _result(6) scalar `xloc' = _result(8) * draw label local r1 = 20700 local r2 = 21700 local c1 = 21500 if `b1b1' == 1 { local r1 = `r1' - 1000 local r2 = `r2' - 1000 local c1 = `c1' - 1000 } gph clear `r1' `p1' `r2' `p2' gph pen 1 local xlo = `xloc' if `byn' == 1 { gph text `c1' `xlo' 0 0 `ixl' } else { gph text `c1' `xlo' 0 0 `byl' } * do title if "`title'" != "" { gph font 1300 650 gph text 22100 10 0 -1 `title' gph font 923 444 } * draw adjacent values line local r1 = `uav' * `ysca' + `yloc' local r2 = `lav' * `ysca' + `yloc' local c1 = `xloc' local c2 = `c1' gph pen `pen' gph line `r1' `c1' `r2' `c2' * draw quartile box (shaded) local r1 = `q75' * `ysca' + `yloc' local r2 = `q25' * `ysca' + `yloc' local c1 = -250 + `xloc' local c2 = 250 + `xloc' gph box `r1' `c1' `r2' `c2' 1 * draw median local r1 = `q50' * `ysca' + `yloc' + 100 local r2 = `q50' * `ysca' + `yloc' - 100 local c1 = -500 + `xloc' local c2 = 500 + `xloc' gph box `r1' `c1' `r2' `c2' 0 global t2flg = `t2t2' global b1flg = `b1b1' end program define kd version 5.0 * -> Kernel Density code stolen from kdensity.ado local varlist "req ex min(1) max(5)" local weight "fweight aweight" #delimit ; local options "N(integer 50) WW(real 0.0) J(int 1) BIweight COSine EPan GAUss RECtangle PARzen TRIangle" ; #delimit cr parse "`*'" parse "`varlist'", parse(" ") local ix "`1'" local d "`2'" local m "`3'" local use "`4'" local byg "`5'" tempvar y z qui gen double `y' = . qui gen double `z' = . tempname delta wid wwidth scalar `wwidth' = `ww' scalar `delta' = (_result(6) - _result(5) + 2 * `wwidth') /* */ / (`n' - 1) scalar `wid' = _result(1) * `wwidth' qui replace `m' = _result(5) - `wwidth' + (_n - 1) /* */ * `delta' in 1/`n' local i 1 if "`biweigh'" != "" { local con1 = .9375 while `i' <= `n' { qui replace `z' = (`ix' - `m'[`i']) / (`wwidth') /* */ if `use' & `byg' == `j' qui replace `y' = `con1' * (1 - (`z')^2)^2 /* */ if abs(round(`z',1e-8)) < 1 qui summ `y' [`weight'`exp'] if `y' != . qui replace `d' = (_result(3) * _result(1)) / `wid' in `i' qui replace `y' = . local i = `i' + 1 } qui replace `d' = 0 if `d' == . in 1/`n' } else if "`cosine'" != "" { while `i' <= `n' { qui replace `z' = (`ix' - `m'[`i']) / (`wwidth') /* */ if `use' & `byg' == `j' qui replace `y' = 1 + cos(2 * _pi * `z') /* */ if abs(round(`z',1e-8)) < 0.5 qui summ `y' [`weight'`exp'] if `y' != . qui replace `d' = (_result(3) * _result(1)) / `wid' in `i' qui replace `y' = . local i = `i' + 1 } qui replace `d' = 0 if `d' == . in 1/`n' } else if "`triangl'" != "" { while `i' <= `n' { qui replace `z' = (`ix' - `m'[`i']) / (`wwidth') /* */ if `use' & `byg' == `j' qui replace `y' = 1 - abs(`z') if abs(round(`z',1e-8)) < 1 qui summ `y' [`weight'`exp'] if `y' != . qui replace `d' = (_result(3) * _result(1)) / `wid' in `i' qui replace `y' = . local i = `i' + 1 } qui replace `d' = 0 if `d' == . in 1/`n' } else if "`parzen'" != "" { local con1 = 4 / 3 local con2 = 2 * `con1' while `i' <= `n' { qui replace `z' = (`ix' - `m'[`i']) / (`wwidth') /* */ if `use' & `byg' == `j' qui replace `y' = `con1' - 8 * (`z')^2 + 8 * abs(`z')^3 /* */ if abs(round(`z',1e-8)) <= .5 qui replace `y' = `con2' * (1 - abs(`z'))^3 /* */ if abs(round(`z',1e-8)) > .5 /* */ & abs(round(`z',1e-8)) < 1 qui summ `y' [`weight'`exp'] if `y' != . qui replace `d' = (_result(3) * _result(1)) / `wid' in `i' qui replace `y' = . local i = `i' + 1 } qui replace `d' = 0 if `d' == . in 1/`n' } else if "`gauss'" != "" { local con1 = sqrt(2 * _pi) while `i' <= `n' { qui replace `z' = (`ix' - `m'[`i']) / (`wwidth') /* */ if `use' & `byg' == `j' qui replace `y' = exp(-0.5 * ((`z')^2)) / `con1' qui summ `y' [`weight'`exp'] qui replace `d' = (_result(3) * _result(1)) / `wid' in `i' local i = `i' + 1 } qui replace `d' = 0 if `d' == . in 1/`n' } else if "`rectang'" != "" { while `i' <= `n' { qui replace `z' = (`ix' - `m'[`i']) / (`wwidth') /* */ if `use' & `byg' == `j' qui replace `y' = 0.5 if abs(round(`z',1e-8)) < 1 qui summ `y' [`weight'`exp'] if `y' != . qui replace `d' = (_result(3) * _result(1)) / `wid' in `i' qui replace `y' = . local i = `i' + 1 } qui replace `d' = 0 if `d' == . in 1/`n' } else { local con1 = 3 / (4 * sqrt(5)) local con2 = sqrt(5) while `i' <= `n' { qui replace `z' = (`ix' - `m'[`i']) / (`wwidth') /* */ if `use' & `byg' == `j' qui replace `y' = `con1' * (1 - ((`z')^2 / 5)) /* */ if abs(round(`z',1e-8)) <= `con2' qui summ `y' [`weight'`exp'] if `y' != . qui replace `d' = (_result(3) * _result(1)) / `wid' in `i' qui replace `y' = . local i = `i' + 1 } qui replace `d' = 0 if `d' == . in 1/`n' } end