*! pathdiagfull.ado Version 2.0 RL Kaufman 01/22/2017 *** 1.0 Renamed from pathdiag.ado Version 1.0 as pathdiagfull.ado. Shows ALL paths& variables. Called by GFI.ADO *** NOTE:Print from graph window in order to set to landscape orientation *** 1.1 Added options TITLE NAME BOXWIDTH YGAP XGAP . Fixed spacing issues. *** 2.0 Added functionality for mlogit. *** 3.0 CHnaged bform() to ndigit() option program pathdiagfull, rclass version 14.2 syntax , eqnow(string) [ TItle(string asis) name(string) NDIGits(integer 3) EQName(string asis) /// BOXWidth(real 1.25) ygap(real .625) xgap( real 1.25) ] tempname bmat tempvar ybox xbox boxwd ytail xtail yhead xhead boxtext disp as res "Path Diagram All Paths & Coefficients" quiet { mat bmat=e(b) loc nmtxt "`eqnow'" if ${eqnum$sfx2} ==1 loc nmtxt "1" loc pname "Path`nmtxt'" if "`name'" != "" loc pname `=strtoname("`name'`nmtxt'",0)' *** mvarn$sfx}= #of moderators mcnum#$sfx}= # of nominal dummies, 1 if interval *** madj# = adjust y-coord for 2way textbox with > 6 lines *** yinc & xinc are increments between textboxes on x&y axes *** bx# is width of textbox(% of axis) Maineffect box (x=0 to bx1) 2way box (x=bx1+xinc to ... + bx2) 3way box (x=bx1+xinc+bx2 to ... + bx3) *** bxw=rescaling factor for bxwidths loc yinc=`ygap' loc xinc=`xgap' loc bx1=1.25 loc bx2=1.75 loc bx3=1.25 loc bxw=`boxwidth' loc madj1=0 forvalues mi=1/${mvarn$sfx} { loc ii=`mi'-1 if `mi' > 1 loc madj`mi'= max(0,(${fcnum$sfx}*${mcnum`ii'$sfx}-6)/6*`yinc') +`madj`ii'' if "${fm1m2list$sfx}"!="" & `mi'==3 loc madj3= max(0,`madj`ii'', /// (${mcnum1$sfx}*${mcnum2$sfx}-6)/6*`yinc' +`madj`ii'', (${fcnum$sfx}*${mcnum1$sfx}*${mcnum2$sfx}-6)/6*`yinc') } loc ii=${mvarn$sfx}+1 loc madj`ii'=`madj${mvarn$sfx}' *** ymax=max/starting y coord (axes rescaled efore graph made) pdtxt[] = y,x and boxwidth for textbox *** txt[] = MATA string matrix with textbox title pdarr[] = coord for arrow y&x tail y&x head loc ymax= (${mvarn$sfx}+2) * `yinc' + `madj${mvarn$sfx}' mat pdtxt=J(50,3,.) mata: txt=J(50,1," ") mat pdarr=J(100,4,.) *** Define Main Effect Box and Arrows to 2-way Boxes: Focal Var lasty=y coord of box, use todefine arrows *** ii = textbox counter jj = arrow counter loc lasty=`ymax' loc ii=1 loc jj=0 mat pdtxt[`ii',1]= `lasty' mat pdtxt[`ii',2]= 0 mat pdtxt[`ii',3]= 24*`bxw' *** Concatenate title for textbox if interval/1 dummy title = VarName*(coeff) + *** if nominal 2+ dummies title = VarCategoryName*(coeff) + with each dummy on separate line *** nm = accumulate named across categories if ${fcnum$sfx}==1 { // title if interval/1 dummy getb , mat(bmat) vn("${fvarc1$sfx}") eqn(`eqname') bform(%8.`ndigits'f) loc nm= "< ${fvldisp$sfx}> Effect = " + r(bstr) + " +" mata: txt[`ii',1]="`nm'" } if ${fcnum$sfx}>1 { // title if 2+dummies embed " to create multi-line title as line1" "line2" "line3" ... "lastline loc nm= "" forvalues fci=1/${fcnum$sfx} { getb , mat(bmat) vn("${fvarc`fci'$sfx}") eqn(`eqname') bform(%8.`ndigits'f) if `fci'==1 loc nm= `"`nm'"' + "< ${fvnamec`fci'$sfx}> Effect *(" + r(bstr) + ") +" +`"""' if `fci'==${fcnum$sfx} loc nm= `"`nm'"' + " " + `"""' + "< ${fvnamec`fci'$sfx}> Effect *(" + r(bstr) + " +" if `fci'>1 & `fci' < ${fcnum$sfx} loc nm= `"`nm'"' + " " + `"""' + "< ${fvnamec`fci'$sfx}> Effect *(" + r(bstr) + ") +" +`"""' } mata: txt[`ii',1]=`"`nm'"' } *** Arrows from main effect box to each 2way of focal*m1 , focal*m2 .... start just below top of box *** Adjust y coord for arrow head for oversize 2way boxes and for extra 2way term (m1*m2) if 3way specified forvalues mi=1/${mvarn$sfx} { loc ++jj mat pdarr[`jj',1]= `lasty'-.1/2 mat pdarr[`jj',2]= `bx1' mat pdarr[`jj',3]= `ymax' - (`mi'-1 )*`yinc' -.1/2 -`madj`mi'' if "${fm1m2list$sfx}"!="" & `mi' >2 mat pdarr[`jj',3]= `ymax' - `mi'*`yinc' -.1/2 -`madj`mi'' mat pdarr[`jj',4]= `bx1'+`xinc' } *** Define Main Effects Box(s) and Arrows to 2-way Boxes: Moderators *** Adjust y coord for textbox and arrow head for oversize 2way boxes and for extra 2way term (m1*m2) if 3way specified *** bk1 = left bracket type bk2 = right bracket types = [m1] {m2} use {} for m3 on forvalues mi=1/${mvarn$sfx} { loc bk1="{ " loc bk2="}" if `mi'==1 { loc bk1="[ " loc bk2="]" } loc ++ii loc mst=`mi'+1 loc lasty= `ymax'- `mi'*`yinc' -`madj`mst'' mat pdtxt[`ii',1]= `lasty' mat pdtxt[`ii',2]= 0 mat pdtxt[`ii',3]= 24*`bxw' if ${mcnum`mi'$sfx}==1 { getb , mat(bmat) vn("${mvar`mi'c1$sfx}") eqn(`eqname') bform(%8.`ndigits'f) loc nm= "`bk1'${mvldisp`mi'$sfx}`bk2' Effect= " + r(bstr) + " +" mata: txt[`ii',1]="`nm'" } if ${mcnum`mi'$sfx}>1 { loc nm= "" forvalues mci=1/${mcnum`mi'$sfx} { getb , mat(bmat) vn("${mvar`mi'c`mci'$sfx}") eqn(`eqname') bform(%8.`ndigits'f) if `mci'==1 loc nm= `"`nm'"' + "`bk1'"+`"${mvname`mi'c`mci'$sfx}"'+"`bk2' Effect= " + r(bstr) + " +" +`"""' if `mci'==${mcnum`mi'$sfx} loc nm= `"`nm'"' + " " + `"""' + "`bk1'${mvname`mi'c`mci'$sfx}`bk2' Effect= " + r(bstr) + " +" if `mci'>1 & `mci' < ${mcnum`mi'$sfx} loc nm= `"`nm'"' + " " + `"""' + "`bk1'${mvname`mi'c`mci'$sfx}`bk2' Effect=" + r(bstr) + " +" +`"""' } mata: txt[`ii',1]=`"`nm'"' } *** Draw arrows to 2-way with focal *** loc ++jj mat pdarr[`jj',1]= `lasty'-.1/2 mat pdarr[`jj',2]= `bx1' mat pdarr[`jj',3]= `ymax' -(( `mi'-1)*`yinc'+`madj`mi''+.1/2) + .2*`xinc'*tan((atan(((`mi'-1)*`yinc'+`madj`mi'')/`xinc'))) if "${fm1m2list$sfx}"!="" & `mi' > 2 mat pdarr[`jj',3]= `ymax' - (`mi'*`yinc'+`madj`mi''+.1/2) + .2*`xinc'*tan((atan((`mi'*`yinc'+`madj`mi'')/`xinc'))) mat pdarr[`jj',4]= (`bx1'+.8*`xinc') *** If 3way exists, draw arrows to 2way with only moderators for moderators 1 & 2 *** if "${fm1m2list$sfx}"!="" & `mi' < 3 { loc ++jj loc ypos=`ymax' -2*`yinc' - (`madj2' +`madj3')/2 mat pdarr[`jj',1]= `lasty'-.1/2 mat pdarr[`jj',2]= `bx1' mat pdarr[`jj',3]= `ypos' -.1/2 mat pdarr[`jj',4]= `bx1'+`xinc' } } *** Define Box & Arrow for Other Predictors Box loc ++ii loc ++jj loc lasty = `ymax'-`yinc'* (${mvarn$sfx}+1)-`madj${mvarn$sfx}' mat pdtxt[`ii',1]= `lasty' mat pdtxt[`ii',2]= 0 mat pdtxt[`ii',3]= 24*`bxw' mata: txt[`ii',1]=`"Other" "Predictors"' mat pdarr[`jj',1]= `lasty'-.1/2 mat pdarr[`jj',2]= `bx1' mat pdarr[`jj',3]= `lasty'-.1/2 mat pdarr[`jj',4]= `bx1'+`xinc'+`bx2'+`xinc' if "${fm1m2list$sfx}"!="" mat pdarr[`jj',4]= (`bx1'+`xinc'+`bx2'+`xinc'+`bx3'+`xinc')/1.007 *** Define 2way Box(s) with Focal (leave spot for M1*M2 if there is a 3way int ) and Arrows to Outcome or to 3-way Boxes *** nmend = end=symbols for textbox line ")" if no 3way ") +" if 3way loc nmend= ") " forvalues mi=1/${mvarn$sfx} { if "${fm1m2list$sfx}"!="" & `mi'<3 loc nmend= ") +" loc ++ii loc lasty= `ymax'- (`mi'-1)*`yinc' -`madj`mi'' if "${fm1m2list$sfx}"!="" & `mi'>2 loc lasty= `ymax'- `mi'*`yinc' -`madj`mi'' mat pdtxt[`ii',1]= `lasty' mat pdtxt[`ii',2]= `bx1'+`xinc' mat pdtxt[`ii',3]= 26*`bxw' loc nm3= "" loc nm4= "" loc bk1="{ " loc bk2="}" if `mi'==1 { loc bk1="[ " loc bk2="]" } *** nm defines focal var name prefix for texbtox line *** nm2 = accummulated text lines across categories of moderator for given focal var category, reset with fci to keep embedded " " correct *** nm3 = accumulated nm2 across categories of focal, reset with fci to keep embedded " " correct *** nm4 = accumulated nm3 across categories of focal forvalues fci=1/${fcnum$sfx} { loc nm= "< ${fvnamec`fci'$sfx}> * " if ${mcnum`mi'$sfx}==1 { getb , mat(bmat) vn("${f`fci'm`mi'c1$sfx}") eqn(`eqname') bform(%8.`ndigits'f) loc nm2= `"`nm'"' + " " + "`bk1'${mvname`mi'c1$sfx}`bk2' * (" + r(bstr) + "`nmend'" + `"" ""' loc nm3=`"`nm2'"' } if ${mcnum`mi'$sfx}>1 { loc nm3="" loc nm2 = `"`nm'"' + " " forvalues mci=1/${mcnum`mi'$sfx} { getb , mat(bmat) vn("${f`fci'm`mi'c`mci'$sfx}") eqn(`eqname') bform(%8.`ndigits'f) if `mci'==1 loc nm2= `"`nm2'"' + "`bk1'${mvname`mi'c`mci'$sfx}`bk2' * (" + r(bstr) + "`nmend'" if `mci' == ${mcnum`mi'$sfx} loc nm2= `"`nm2'"' + `"" ""' + `"`nm'"' + " " + "`bk1'${mvname`mi'c`mci'$sfx}`bk2' * (" + r(bstr) + "`nmend'" + `"" ""' if `mci'> 1 & `mci' < ${mcnum`mi'$sfx} loc nm2= `"`nm2'"' + `"" ""' + `"`nm'"' + " " + "`bk1'${mvname`mi'c`mci'$sfx}`bk2' * (" + r(bstr) + "`nmend'" } loc nm3= `"`nm3'"' + `"`nm2'"' } loc nm4= `"`nm4'"' + `"`nm3'"' } mata: txt[`ii',1]=`"`nm4'"' *** Define arrow from 2way to Outcome box if no 3way *** if "${fm1m2list$sfx}"=="" | `mi'> 2 { loc ++jj mat pdarr[`jj',1]= `lasty'-.1/2 mat pdarr[`jj',2]= (`bx1'+`xinc'+`bx2')/1.1 mat pdarr[`jj',3]= `lasty'-.1/2 mat pdarr[`jj',4]= `bx1'+`xinc'+`bx2'+`xinc' if "${fm1m2list$sfx}"!="" mat pdarr[`jj',4]= `bx1'+`xinc'+`bx2'+`xinc'+`bx3'+`xinc' } *** Define arrow from 2way to 3way box if present *** if "${fm1m2list$sfx}"!="" & `mi' < 3 { loc ++jj mat pdarr[`jj',1]= `lasty'-.1/2 mat pdarr[`jj',2]= `bx1'+`xinc'+`bx2' mat pdarr[`jj',3]= `ymax' -.1/2 mat pdarr[`jj',4]= `bx1'+`xinc'+`bx2'+`xinc' } } *** If 3way exists Define 2way Box Moderators 1&2 and Arrows to Outcome Box *** place box after f*m2 and before f*m3. Adjustment is 1/2 between m2 and m3 adjustment *** same use of nm,nm2,nm3, nm4 as above if "${fm1m2list$sfx}"!="" { loc ++ii loc ypos= `ymax' -2*`yinc' -(`madj2' + `madj3')/2 mat pdtxt[`ii',1]= `ypos' mat pdtxt[`ii',2]= `bx1'+`xinc' mat pdtxt[`ii',3]= 26*`bxw' loc nm3= "" loc nm4= "" forvalues mci1=1/${mcnum1$sfx} { loc nm= "[${mvname1c`mci1'$sfx}] * " if ${mcnum2$sfx} ==1 { getb , mat(bmat) vn("${m1c`mci1'm2c1$sfx}") eqn(`eqname') bform(%8.`ndigits'f) loc nm2= `"`nm'"' + " " + "{${mvname2c1$sfx}} *(" + r(bstr) + ") " +`"" ""' loc nm3=`"`nm2'"' } if ${mcnum2$sfx} >1 { loc nm3="" loc nm2 = `"`nm'"' + " " forvalues mci2=1/${mcnum2$sfx} { getb , mat(bmat) vn("${m1c`mci1'm2c`mci2'$sfx}") eqn(`eqname') bform(%8.`ndigits'f) if `mci2'==1 loc nm2= `"`nm2'"' + "{${mvname2c`mci2'$sfx}} * (" + r(bstr) + ") " if `mci2'==${mcnum2$sfx} loc nm2= `"`nm2'"' + `"" ""' + `"`nm'"' + " " + "{${mvname2c`mci2'$sfx}} * (" + r(bstr) + ") " +`"" ""' if `mci2'>1 & `mci2' < ${mcnum2$sfx} loc nm2= `"`nm2'"' + `"" ""' +`"`nm'"' + "{${mvname2c`mci2'$sfx}} * (" + r(bstr) + ") " } loc nm3= `"`nm3'"' + `"`nm2'"' } loc nm4= `"`nm4'"' + `"`nm3'"' } mata: txt[`ii',1]=`"`nm4'"' loc ++jj mat pdarr[`jj',1]= `ypos'-.1/2 mat pdarr[`jj',2]= (`bx1'+`xinc'+`bx2')/1.1 mat pdarr[`jj',3]= `ymax' -.1/2 mat pdarr[`jj',4]= `bx1'+`xinc'+`bx2'+`xinc' } *** If 3way exists Draw 3way Box and Arrows to Outcome *** use nm0 to hold prefix name for focal var. same use of nm,nm2,nm3, nm4 as above if "${fm1m2list$sfx}"!="" { loc ++ii mat pdtxt[`ii',1]= `ymax' mat pdtxt[`ii',2]= `bx1'+`xinc'+`bx2'+`xinc' mat pdtxt[`ii',3]= 24*`bxw' loc nm3= "" loc nm4= "" forvalues fci=1/${fcnum$sfx} { loc nm0= "< ${fvnamec`fci'$sfx}> * " forvalues mci1=1/${mcnum1$sfx} { loc nm= "`nm0'" + "[ ${mvname1c`mci1'$sfx}] * " if ${mcnum2$sfx}==1 { getb , mat(bmat) vn("${f`fci'm1c`mci1'm2c1$sfx}") eqn(`eqname') bform(%8.`ndigits'f) loc nm2= `"`nm'"' + " " +`"" ""' + " {${mvname2c1$sfx}} * (" + r(bstr) + ") " + `"" ""' loc nm3=`"`nm2'"' } if ${mcnum2$sfx} > 1 { loc nm3="" forvalues mci2=1/${mcnum2$sfx} { getb , mat(bmat) vn("${f`fci'm1c`mci1'm2c`mci2'$sfx}") eqn(`eqname') bform(%8.`ndigits'f) if `mci2'==1 loc nm2= `"`nm'"' + `"" ""' + " {${mvname2c`mci2'$sfx}} * (" + r(bstr) + ") " if `mci2'==${mcnum2$sfx} loc nm2= `"`nm2'"' + `"" ""' + `"`nm'"' + `"" ""' + " {${mvname2c`mci2'$sfx}} * (" + r(bstr) + ") " +`"" ""' if `mci2'>1 & `mci2' < ${mcnum2$sfx} loc nm2= `"`nm2'"' + `"" ""' +`"`nm'"' + `"" ""' +" {${mvname2c`mci2'$sfx}} * (" + r(bstr) + ") " } loc nm3= `"`nm3'"' + `"`nm2'"' } loc nm4= `"`nm4'"' + `"`nm3'"' } } mata: txt[`ii',1]=`"`nm4'"' loc ++jj mat pdarr[`jj',1]= `ymax'-.1/2 mat pdarr[`jj',2]= `bx1'+`xinc'+`bx2'+`xinc'+`bx3' mat pdarr[`jj',3]= `ymax'-.1/2 mat pdarr[`jj',4]= (`bx1'+`xinc'+`bx2'+`xinc'+`bx3'+`xinc')/1.007 } *** Define Outcome box. boxwidth=90 will apply to rotated box and is its height loc ++ii loc ++jj mat pdtxt[`ii',1]= `ymax'/2 mat pdtxt[`ii',2]= `bx1'+`xinc'+`bx2'+`xinc'*1.05 mat pdtxt[`ii',3]= 90 if "${fm1m2list$sfx}"!="" mat pdtxt[`ii',2]= `bx1'+`xinc'+`bx2'+`xinc'+`bx3'+`xinc'*1.05 mata: txt[`ii',1]= "g(${dvname$sfx})" *** Make variables from matrices defining textbox (pdtxt and mata:txt) and arrows (pdarr) *** mat colnames pdtxt = "`ybox'" "`xbox'" "`boxwd'" mat colnames pdarr= "`ytail'" "`xtail'" "`yhead'" "`xhead'" svmat pdtxt, names(col) svmat pdarr, names(col) mata: st_addvar("strL","`boxtext'") mata: st_sstore((1,50),"`boxtext'",txt) replace `xhead'=`xhead'*1 replace `xtail'=`xtail'/1 *** Concatenate text boxes *** graph has fixed y/xsize=12 and y/x axes 0 to 12 *** rescale x& y so each runs from (0+ a tad) to (11.5+ a tad) loc yxy="y x" foreach yx of loc yxy { loc `yx'min=100 loc `yx'max=0 foreach yv of var ``yx'box' ``yx'head' ``yx'tail' { summ `yv' if r(min) < ``yx'min' loc `yx'min=r(min) if r(max) > ``yx'max' loc `yx'max=r(max) } loc scale=6.3 if "`yx'"=="x" loc scale=8.8 foreach yv of var ``yx'box' ``yx'head' ``yx'tail' { replace `yv'=(`yv'-``yx'min'+.1)*`scale'/(``yx'max'-``yx'min') } } *** reset y coord for Outcome boox to 1/2 way between rescaled ybox min and max *** qui summ `ybox' loc iin=r(N) qui replace `ybox'= r(min)+.47*(r(max)-r(min)) if _n==`iin' *** tb = accumulated textbox definitions tt1=text title bxwd=boxwidth *** gg=accumulate pieces of iith textbox Outcome box (last box) rotated to vertical loc tb = " " forvalues ii=1/`iin' { loc tt1= `boxtext'[`ii'] loc bxwd = `boxwd'[`ii'] loc gg= "text( " + strofreal(`ybox'[`ii'], "%14.6g") + " " + strofreal(`xbox'[`ii'], "%14.6g") + " " + `"""' + `"`tt1'"' /// + `"""' + " , size(2) box m(tiny) place(se) width(`bxwd') bexp j(left) linegap(*1.2) ) " if `ii'==`iin' loc gg="text( " + strofreal(`ybox'[`ii'], "%14.6g") + " " + strofreal(`xbox'[`ii'], "%14.6g") + " " + `"""' + `"`tt1'"' /// + `"""' + " , size(2.5) box m(tiny) place(0) width(`bxwd') bexp orient(rvertical)) " loc tb = `"`tb'"' + `"`gg'"' } } // end quietly tw pcarrow `ytail' `xtail' `yhead' `xhead', msize(tiny) barbsize(.5) lw(*.5) lc(black) mc(black) /// xsize(9) ysize(6.5) ti( , size(*.7) m(b+2)) tit(`title' ) scheme(s1mono) ytit("") xtit("") ysc(r(0 6.5)) /// ysc(noline) xsc(r(0 9)) xsc(noline) xlab(none) ylab(none) leg(off) name(`pname',replace) plotreg(lc(none)) `tb' end