*!  cbplot.ado 	Version 6.3		RL Kaufman 	03/14/2019

***  	1.0 Create Confidnece Bounds Plot. Called by EFFDISP.ADO
***		2.0	Made separate PLOTCOMB.ADO as a shared ado to combine plots to replace same process in multiple ADOs
***		3.0 Added save plot data functionality
***		3.1 Incorporated improvments from ERRBPLOT, ylab setting, putexel code, noeffect line creation
***		5.0	Added mlogit functionality
***		6.0	Added factor change and spost functionality
***		6.1 Changed meaning of sigmark.  Adds Sig-NoSig vertical line to line plot but not confidence bounds
***		6.2 Use min and max of mvrange1 to define added xaxis (yaxis indirectly) min & max instead of actual variable min and max
***		6.3 Fixed float precision problem when selecting on m2var when making matrix 

program cbplot, rclass
version 14.2
syntax  ,  m1var(varname) mlab1(varname) bmod(varname) upb(varname) lowb(varname) bsig(varname) crittz(real) ci(real) /// 
	fvarnum(varname) fnum(integer)  noeffval(integer) ///
 [ titotheff(string) titdel(string) dvtxt(string) m2var(varname)  m3var(varname) mlab3(string) m3val(real 0) m3ind(integer 0) /// 
   m4ind(integer 0) m4var(varname) mlab4(string) m4val(real 0) ndig(integer 4) frqmat(string) ///
   base(string) KEEP name(string) save(string) estint(string) pltopts(string asis) pltsigmark(string) ] 
 
tempname   frqvsub  m1cat frqvar frqv savmat
tempvar    noeff 

qui {
*** Create vars and info for CB plot
loc cipct =100*`ci'

loc xfirst: word 1 of ${mvrange1$sfx}
loc mstp1: list sizeof global(mvrange1$sfx)
loc xlast: word `mstp1' of ${mvrange1$sfx}
loc xmin = `xfirst'-.05*(`xlast'-`xfirst')
loc xmax = `xlast'+.05*(`xlast'-`xfirst')

if strmatch("`pltsigmark'","*Yes*") == 1  qui sum `upb' if inrange(`m1var', `xfirst' , `xlast')  , meanonly
if strmatch("`pltsigmark'","*Yes*") == 0  qui sum `bmod' if inrange(`m1var', `xfirst' , `xlast') , meanonly

loc ymax=r(max)
loc yy = abs(r(max))
loc ylabmax = 0
if `yy' > 0 {
	loc p10 = int(log10(`yy'))-2
	loc ylabmax = round(`yy'+.5*(10^(`p10')),10^(`p10'+1))*sign(r(max))
	if `yy' < 1 {
		loc pyy=int(log10(`yy'))*2
		loc y1=`yy'*(10^(-`pyy'+1))
		loc p10=int(log10(`y1'))-1
		loc y2 =round(`y1'+ .5*(10^(`p10')),10^(`p10'+1))*sign(r(max))
		loc ylabmax= `y2'*(10^(`pyy'-1))
	}
}
*
if strmatch("`pltsigmark'","*Yes*") == 1  qui sum `lowb' if inrange(`m1var', `xfirst' , `xlast') , meanonly
if strmatch("`pltsigmark'","*Yes*") == 0  qui sum `bmod' if inrange(`m1var', `xfirst' , `xlast') , meanonly

loc yy = abs(r(min))
loc ymin=r(min)
loc ylabmin = 0
if `yy' > 0 {
	loc p10 = int(log10(`yy'))-1
	loc ylabmin = round(`yy'+.5*(10^(`p10')),10^(`p10'+1))*sign(r(min))
	if `yy' < 1 {
		loc pyy=int(log10(`yy'))*2
		loc y1=`yy'*(10^(-`pyy'+1))
		loc p10=int(log10(`y1'))-1
		loc y2 =round(`y1'+ .5*(10^(`p10')),10^(`p10'+1))*sign(r(min))
		loc ylabmin= `y2'*(10^(`pyy'-1))
	}

}

loc yy = (`ylabmax' - `ylabmin')/4 

loc p10 = int(log10(`yy'))-1
loc ylabinc = round(`yy',10^(`p10'+1))
if `yy' < 1 {
	loc pyy=int(log10(`yy'))*2
	loc y1=`yy'*(10^(-`pyy'+1))
	loc p10=int(log10(`y1'))-1
	loc y2 =round(`y1'+ .5*(10^(`p10')),10^(`p10'+1))
	loc ylabinc= `y2'*(10^(`pyy'-1))
}

if `ylabmax' == . | `ylabmin' == . | `ylabinc' == . {
	loc ylabmax = `ymax'
	loc ylabmin = `ymin'
	loc ylabinc = (`ylabmax' - `ylabmin')/4 
}
if `ymax' - `ylabmax' > .3*`ylabinc' loc ylabmax = `ylabmax' + .4*`ylabinc'
if `ymin' - `ylabmin' < .3*`ylabinc' loc ylabmin = `ylabmin' - .4*`ylabinc'

loc yeffmax = `ylabmax' + .025*(`ylabmax'-`ylabmin')

loc yeffmin = `ylabmin' - .05*(`ylabmax'-`ylabmin')


***   Set # of rows/plot for saving plotdata

loc npltrow = 51

***   Create info for freq distn vars if requested 
if "`frqmat'" != "" {
	loc vnm: coln `frqmat'
	loc cnum=colsof(`frqmat')-1
	loc cnm ""
	forvalues j=1/`cnum' {
		loc nm: word `j' of `vnm'
		loc cnm "`cnm' `=strtoname("`frqv'`nm'")' "
	}
	loc cnm "`cnm' `m1cat'"
	mat colnames `frqmat' = `cnm'
	svmat `frqmat' , names(col)
	mat `frqvar'= `frqmat'[.,1..`cnum']
	mata: fmat=st_matrix("`frqvar'"); fsum= sum(fmat); fmax= max(fmat); fsumcol = colsum(fmat); fmaxcol= colmax(fmat); st_numscalar("fsum",fsum); st_numscalar("fmax",fmax); st_matrix("fsumcol",fsumcol); st_matrix("fmaxcol",fmaxcol)
}
****
**** Loop over m2 values if specified, otherwise loop once over m2  
loc grphcomb ""

loc mstp2=1
if "`m2var'" != "" loc mstp2: list sizeof global(mvrange2$sfx)

***	create freq distn vars & plot if requested.  

if  "`frqmat'" != ""  & "`base'" == "tot" {
		loc vv: word 1 of `cnm'
		replace `vv' = `vv'/fsum*100 if `vv'<.
		loc ypctmax= round(fmax/fsum*100+.5)
	}

forvalues m2=1/`mstp2' {
if "`frqmat'" != "" {

	if "`base'" == "subtot" {
		loc vv: word `m2' of `cnm'
		replace `vv' = `vv'/fsum*100 if `vv'<. 	
		loc ypctmax= round(fmax/fsum*100+.5)
	}
	
	if "`base'" == "sub" {

		mat `frqvsub'=`frqvar'[.,`m2'..`m2']
		loc vv: word `m2' of `cnm'		
		replace `vv' = `vv'/el("fsumcol",1,`m2')*100 if `vv'<. 
		loc ypctmax= 0
		forvalues j=1/`cnum' {
			if (el("fmaxcol",1,`j')/el("fsumcol",1,`j'))*100 > `ypctmax' loc ypctmax = round(el("fmaxcol",1,`j')/el("fsumcol",1,`j')*100+.5)
		}
	}
}

*** Set up substitution text and conditions
loc noplt "nodraw"
if "`m2var'" == ""  & ${fcnum$sfx} == 1 & "`frqmat'" == "" loc noplt ""
loc addif ""

loc titletxt `"`titotheff' Effect of ${fvldisp$sfx} `titdel' Moderated by ${mvldisp1$sfx}"'
loc subtittxt ""
if strmatch("`pltsigmark'","*Yes*") == 1   loc subtittxt `" subtit( "`cipct'% Confidence Bounds" , size(*.9) m(b+1)  ) "'

loc titxtcomb ""
loc titsz = "*.7"
loc titint "${mvldisp1$sfx}"
if "${bf1m1c1m2c1$sfx}" != "" loc titint " the Interaction of ${mvldisp1$sfx} "

loc legoff  ""
if "`frqmat'" != "" 	loc legoff " legend(off)"

loc legefftxt "${fvldisp$sfx}"
loc titxtfv  ""
if ${fcnum$sfx} > 1 & "`m2var'" == ""  {
*	loc titxtfv "`titotheff' Effect of ${fvldisp$sfx}: ${fvlabc`=`fnum'+1'$sfx} "
	loc titxtfv "${fvldisp$sfx}: ${fvlabc`=`fnum'+1'$sfx}, "
	loc titletxt "${fvldisp$sfx}: ${fvlabc`=`fnum'+1'$sfx}"
	loc legoff " legend(off)"
	loc legefftxt "${fvldisp$sfx}"
	loc titsz = "*.7"
}
loc m2val: word `m2' of ${mvrange2$sfx}
*if "${mviscat2$sfx}" == "y" loc m2val = inrange(`m2',1,100)
if "`m2var'" != "" {
	loc legoff " legend(off)"
	loc addif "& `m2var' == float(`m2val')"
	loc titletxt "`titxtfv' ${mvldisp2$sfx} = ${mvlabm2c`m2'$sfx}"
	loc titsz = "*.7"
	loc titxtcomb "`titint' and ${mvldisp2$sfx}"
}
if "`m3var'" != "" {
	loc addif "`addif' & `m3var' == float(`m3val')"
	loc titletxt "`titxtfv' ${mvldisp2$sfx} = ${mvlabm2c`m2'$sfx} & ${mvldisp3$sfx} =  `mlab3'"
	loc titsz = "*.7"
	loc titxtcomb "`titint', ${mvldisp2$sfx} and ${mvldisp3$sfx}"
}

***  Create sig change info

loc isig = 0
loc ins = 0

forvalues j=1/3 {
	loc sig`j' ""
	loc ns`j' ""
	loc addsig`j' ""
	loc addns`j' ""
}

if strmatch("`pltsigmark'","*Yes*") == 1 |  strmatch("`pltsigmark'","*Vertical*") {

mkmat `bsig' `m1var'  if `fvarnum' == `fnum' `addif'  , mat(signe) nomiss


loc siglst =el(signe,1,1)

forvalues i=2/`=rowsof(signe)' {
	loc signow =el(signe,`i',1)
	loc sigchg =`signow' - `siglst'
	if `sigchg' != 0 {
		if `sigchg' > 0 {
			loc ++isig
			loc sig`isig'= el(signe,`i',2) - (el(signe,`i',2) - el(signe,`=`i' - 1',2) ) / 2
		}
		if `sigchg' < 0 {
			loc ++ins
			loc ns`ins'= el(signe,`i',2) - (el(signe,`i',2) - el(signe,`=`i' - 1',2) ) / 2
		}
		loc siglst = `signow'
	}
	}
*
loc svsig ""
loc svns ""
loc chgn = max(`isig', `ins')
forvalues j=1/`chgn' {
	loc addsig`j' ""
	loc addns`j' ""
*	if "`sig`j''" != "" & strmatch("`pltsigmark'","*Yes*") == 1 {
	if "`sig`j''" != "" {
		loc addsig`j' = " || scatteri `yeffmin' `sig`j'' `=`yeffmin'+.05*(`yeffmax' -`yeffmin')' `sig`j'' (12) " + `"""' +"NS───Sig" + `"""' +",  ms(i) xline(`sig`j'', lc(gs7) lp(solid) lw(*.8)) "
		loc svsig "`svsig' `=strofreal(`sig`j'',"%9.`ndig'f")'"
	}
*	if "`ns`j''" != "" & strmatch("`pltsigmark'","*Yes*") == 1 {
	if "`ns`j''" != ""  {
		loc addns`j' = " || scatteri `yeffmin'  `ns`j'' `=`yeffmin'+.05*(`yeffmax' -`yeffmin')' `ns`j'' (12) " + `"""' + "Sig───NS" + `"""' +" ,  ms(i)  xline(`ns`j'', lc(gs7) lp(solid) lw(*.8))"   
		loc svns "`svns' `=strofreal(`ns`j'',"%9.`ndig'f")'"
	}
	}
	}
	
loc xaxoff  ""
if "`frqmat'" != "" loc xaxoff "xscale(axis(1) off)"



loc gnmadd ""
if ${fcnum$sfx}>1 loc gnmadd "f`fnum'" 
loc m2ind = `m2'
forvalues j=2/4 {
	if  "`m`j'var'" != "" loc gnmadd "`gnmadd'm`j'`m`j'ind'"
}
loc top "Top"
if "`frqmat'" == "" loc top ""
loc noeffline "yline(`noeffval' , lp(shortdash) lc(gs12) lw(*1.1) )"
if ( `yeffmax' < `noeffval') | (`yeffmin' > `noeffval' ) loc noeffline ""
*if (`yeffmin' < -.5 +1.45*`noeffval' & `yeffmax' < -.5 +1.45*`noeffval') | (`yeffmin' > .5 +.55*`noeffval' & `yeffmax' > .5 +.55*`noeffval') loc noeffline ""

loc ytxt "`upb' `bmod' `lowb'"
loc legtxt `""  — — — —    Upper Bound" " " "  —————    Effect of `legefftxt'" " " "  — — — —    Lower Bound""'
loc lptxt "dash solid dash"
loc ordtxt `" order ( 1 "Upper Bound" 2 "Effect of `legefftxt'" 3 "Lower Bound")"'
if strmatch("`pltsigmark'","*Yes*") == 0 {
	loc ytxt " `bmod' "
	loc legtxt `" "  —————    Effect of `legefftxt'" "'
	loc lptxt "solid "
	loc ordtxt `" on label( 1 "Effect of `legefftxt'")"'	
}

loc lgap=3.5
if "`m2var'" != "" {
	loc lgap =1
	if mod(`mstp2',3) ==0 | (mod(`mstp2',3) ==2 & `m2' <= 3*int(`mstp2'/3)) loc lgap = .9
	if mod(`mstp2',3) ==1 & `m2' <= 3*(int(`mstp2'/3)-1) loc lgap = .9
	if `mstp2' == 4 | `mstp2'==2 loc lgap = 1
	loc lgap=.5
}

scatter `ytxt'  `m1var' if `bmod' < . & `fvarnum' == `fnum' & inrange(`m1var', `xfirst' , `xlast')  `addif' , conn(l l l ) /// 
	lp(`lptxt' ) lc(black black black ) ms(i i i ) `noeffline' scheme(s1mono)  /// 
	ysc(r(`yeffmin' `yeffmax'))  `noplt' ylab(`ylabmin'(`ylabinc')`ylabmax' , nogrid form(%9.`ndig'f) labsize(*1.2) labgap(*`lgap')) lw(*1 *1 *1 *.8) ///
	name(`name'`top'`gnmadd', replace) 	title("`titletxt'",  size(`titsz') m(b+1)) `subtittxt' xti("${mvldisp1$sfx}", size(*1) m(t+1))   /// 
	yti("Effect on `dvtxt'", size(*.85) m(r+2)) graphreg(fc(white) ma(zero) style(none)) xlab( ${mvrange1$sfx} , labsize(*1.2) form(%9.${mvdigit1$sfx}f)) xsc(r(`xmin' `xmax')) ///
	plotr(m(tiny) style(none)) legend( col(1) `ordtxt' size(*1) pos(6) rowg(*.5)) `legoff' `xaxoff' ///
	   `pltopts' `addsig1' `addns1' `addsig2' `addns2' `addsig3' `addns3'  

 

if "`frqmat'" != "" {

loc ylabsz = 1.2
if "`m2var'" != "" | ${fcnum$sfx} > 1 loc ylabsz = .96

loc xlabopt ""
if strpos("`pltopts'","xlab") !=0 {
	loc nw=wordcount("`pltopts'")
	forvalues ww=1/`nw' {
		loc xword: word `ww' of `pltopts' 
		if strmatch("`xword'","*xlab*") == 1 loc xlabopt "`xword'"
	}
}

tw spike `vv' `m1cat',  ysca(reverse r(0) ) scheme(s1mono) ylabel( `=`ypctmax'/3' " " `=`ypctmax'/3*2' " "  `ypctmax', nogrid labsize(*`ylabsz') labgap(*`lgap') ) /// 
	yline(0, lw(*.8) ) xlabel(${mvrange1$sfx} , labsize(*1) form(%9.${mvdigit1$sfx}f)) fysize(20)   name(`name'Bot`gnmadd', replace)   /// 
    lc(black) lw(*5) graphregion(margin(zero) style(none))  ytitle("Pct", size(*.85) margin(r+2)) xtitle("${mvldisp1$sfx}" , size(*1) m(t+2) ) ///
	xsc(r(`xmin' `xmax')) plotr(m(l=0 r=0 t=0 b=0) style(none)) nodraw `xlabopt'

	if "`m2var'" != "" | ${fcnum$sfx} > 1  ///
		graph combine `name'Top`gnmadd' `name'Bot`gnmadd', ysize(4.5) xsize(5)  xcommon cols(1) name(`name'`gnmadd', replace) ////
			graphreg(fc(white) style(none)) plotr(m(tiny) style(none)) imargin(0 0 0 0) nodraw iscale(*1.3)
			
	if "`m2var'" == "" & ${fcnum$sfx} == 1  ///
		graph combine `name'Top`gnmadd' `name'Bot`gnmadd', ysize(4.5) xsize(5)  xcommon cols(1) name(`name'`gnmadd', replace) ////
			graphreg(fc(white) style(none)) plotr(m(tiny) style(none)) imargin(0 0 0 0) /// 
			cap(`legtxt', pos(6) linegap(*.25) j(left) margin(t+1 b+1) fc(white) bmargin(t+2) box size(*.8) ) iscale(*1.3)
	
graph drop `name'Top`gnmadd' `name'Bot`gnmadd'
}
if "`save'" != "" {
	glo plotnum$sfx = ${plotnum$sfx}+1
	loc rownum=2 + `npltrow'*(${plotnum$sfx}-1)
	loc rnadj = `rownum' + `npltrow'-1
	loc fpnum = `fnum'
	if "${fviscat$sfx}" == "y" | ("${fisfv$sfx}" == "y" & ${fcnum$sfx} == 1 ) loc fpnum=`fnum'+1 
	putexcel set "`save'" , sheet(plotdata_${eqnow$sfx2}) modify
	putexcel B`rownum' = "Plot Name = `name'`gnmadd'"  B`=`rownum'+1' = "  Mod1= ${mvldisp1$sfx}" ///
		B`=`rownum'+2' = "  Mod2= ${mvldisp2$sfx}"  B`=`rownum'+3' = "  Mod3= ${mvldisp3$sfx}" 
	loc mv2="."
	if "`m2'" != "" loc mv2 = `m2'
	loc mv3="."
	if "`m3var'" != "" loc mv3 = `m3val'
	if ${plotnum$sfx} == 1	/// 
		putexcel B1 = "Focal= ${fvldisp$sfx}" C1 = "upb" D1 = "bmod" E1 = "lowb" F1= "M1Value" G1 = "M1Label" H1 = "${fvldisp$sfx}" I1="FocalLabel" J1 = "Mod2Value" K1="M2Label" L1 = "Mod3Value" M1="M3Label"
*	mkmat `bmod' `sebar' `m1var' in `=`rownum'-1'/`=`rnadj'-1', mat(`savmat')
	mkmat `upb' `bmod' `lowb' `m1var' in `=`rownum'-1'/`=`rnadj'-1', mat(`savmat')
	putexcel C`rownum'= mat(`savmat') 
	putexcel H`rownum':H`rnadj'= `fnum' I`rownum':I`rnadj'= "${fvlabc`fpnum'$sfx}" J`rownum':J`rnadj'= `mv2' K`rownum':K`rnadj'= "${mvlabm2c`m2'$sfx}" L`rownum':L`rnadj'= `mv3' M`rownum':M`rnadj'= "`mlab3'"
	mata: mlab1 = st_sdata((1,`npltrow'),("`mlab1'")); b=xl();b.load_book("`save'"); b.set_sheet("plotdata_${eqnow$sfx2}"); b.set_mode("closed"); b.put_string(`rownum',7,mlab1)
}

*
if "`m2var'" != ""  loc grphcomb "`grphcomb' `name'`gnmadd'"

*** Close m2 loop	
}
*
if ${fcnum$sfx} > 1 & ${mvarn$sfx} == 1 glo grnames$sfx "${grnames$sfx} `name'`gnmadd'"

if "`m2var'" != "" {
if `mstp2' > 3 | ${fcnum$sfx} > 1 | "`m3var'" != "" glo pannum$sfx = ${pannum$sfx} + 1
loc fvtxt "${fvldisp$sfx}"
if ${fcnum$sfx} > 1 loc fvtxt "${fvldisp$sfx}: ${fvlabc`=`fnum'+1'$sfx}"
loc combti `"`titotheff' Effect of `fvtxt' `titdel'" "Moderated by `titxtcomb'"'
loc combleg `""  — — —      Upper Bound" " " "  ————    Effect of `legefftxt'" " " "  — — —      Lower Bound""'
if strmatch("`pltsigmark'","*Yes*") == 0 {
	loc combleg `" "  —————    Effect of `legefftxt'" "'
}
plotcomb , grphcomb(`grphcomb') title(`combti') grname(`name'`gnmtxt') legend(`combleg') plttype(cbound)
}
if "`keep'" != "keep" & "`grphcomb'" != "" graph  drop `grphcomb'
}
end