prog define diffplot, rclass
*!	version 3.11  by Mead Over 	12Apr2024
*	Based on a previous regression estimate of the diff-in-diff model,
*	construct a plot of the difference-in-differences using marginsplot

	version 14

	#delimit ;
	syntax
		[if] [in]                                // Allows restricting sample, as necessary
		[using]                                  // Specifies file for -using- option of -frmttable-
		,
		PEriod(varname fv numeric)               // Require these to be be coded (0,1) as does -diff-
		TReated(varname fv numeric)              // Require these to be be coded (0,1) as does -diff-
		[                                        //
		ESTRestore(string)                       // Restore the -est store-d results of a regression model from -ereturn- (Not useful after -diff-)
		ESTUse(string)                           // -est use- the -est save-d results of a regression model (Not useful after -diff-)
		MARGInslist(varlist fv)                  // Default is i.`period'#i.`treated'
		MARGAt(string)                           // In case we want to specify the at() option on the margins command. eg. after addvars() option on -diff-
		EXPression(passthru)                     // Example: If dep var is ln(y), use -expression(exp(predict(xb)))-
		reg4margins(string)                      // Store the quasi-regression results before executing -margins-
		title(passthru) subtitle(passthru)       // graph options
		ytitle(passthru) xtitle(passthru)        // graph options
		ylabel(passthru)                         // graph options (Excludes -xlabel-, which is under -diffplot- control)
		notext                                   // Suppresses text labels on right of plot
		textsize(str)                            // See -help textsizestyle-. Default is -vsmall-
		cfactci                                  // CI only on the counterfactual at -After-
		tci                                      // CI only on the -treated- at -After-
		allci                                    // all CIs displayed
		ciopts(string)                           // Apply to all CIs
		level(passthru)                          // Confidence level, passed thru to -margins- and -lincom()-
		MARGExpression(string)                   // Keep -margexpression- option only in order to trap it
		LEGTitle(string)                         // Legend title: Default is none
		LEGOpts(string)                          // Legend options: -order()-,-size()-,-col()- and -symxsize(*.8)-
		LEGPos(string)                           // -pos()-, -ring()- and -off- options only: Default is pos(3) ring(1)
		keywidth(string)                         // Width of legend keys (see -help size-)
		DIFFTAble                                // Reproduce Villa's table -> MS Word or TeX
		TRADTAble                                // Create the traditional DID table -> MS Word or TeX
		STATs(passthru)                          // Any combination or order of -N-, -se-, -t- and -p-
		pstars(passthru)                         // Numlist giving the critical values for 1, 2 or 3 stars [forbid user selection of asymbol]
		FRMTOpts(passthru)                       // Options passed through to -frmttable-
		trtlbl(string)                           // Replace the word "treated" with this word in all output
		conlbl(string)                           // Replace the word "control" with this word in all output
		aftlbl(string)                           // Replace the word "after" with this word in all output
		beflbl(string)                           // Replace the word "before" with this word in all output
		cfactlbl(string)                         // Replace the word "counterfactual" with this word in all output
		difftxtleft                              // For graphs, place the text labeling the DID on the left, instead of on the right.
		beftxtleft                               // For graphs, place the text labeling the "Before" estimates of control & treatment groups on the left, instead of on the right.
		b4txtleft                                // Alternative spelling for -b4txtleft-
		name(passthru)                           // Name of the graph (-replace- no longer added by -diffplot-)
		saving(passthru)                         // Passed to -marginsplot-, complete with replace and asis suboptions
		replace                                  // Applies only to frmttable saving, not to graph saving (a frmtopts option?)
		cfact                                    // Suboption for -difftable-: Display an extra row for estimate of the counterfactual.
		sdec(real 3)                             // If specified, all results in the graph and the tables are reported to this number of significant digits.
		verbose                                  // Additional intermediate results or debugging
		debug                                    // Debugging output
		noestimcheck                             // Passed through to margins command.
		PArselegopts                             // Use -parselegopts-
		* ]                                      // * = Other options passed to -marginplots-
	;
	#delimit cr
*	Perhaps more parsimonious to use -passthru- syntax for:
*		-marginslist()
*		-at(passthru)- option instead of a -margat(string)- option.

	//  Define the estimation sample with -touse-
	marksample touse

		tempvar esmpl eout
		qui gen byte `esmpl' = e(sample)
		qui gen byte `eout' = cond(`esmpl'~=1,.,1)

		//	If -diff- used option -support-, mark out additional observations
		cap confirm numeric variable _support
		if _rc==0 & strpos("`e(cmdline)'","& _support")>0 {
			tempvar nosupport
			qui gen byte `nosupport' = cond(_support~=1,.,1)
		}
		markout `touse' `treated' `period' `eout' `nosupport'

	local shhh = cond("`verbose'"=="" & "`debug'"=="", "quietly", "")

	if "`margexpression'"~="" {
		di as err _n "The option -margexpression- is no longer supported."  ///
			_n "Instead use the option {opth exp:ression(margins##pnl:exp)}, which is passed through to {help margins}."
		exit 198
	}

	if "`level'"=="" {
		if "`r(level)'"~="" {
			local level level(`r(level)')
		}
		else {
			local level level(95)
		}
	}
	else {
		local showlevelnote showlevelnote
	}

*	Check and label the -period- & -treated- variables
	ptok, period(`period') treated(`treated') `verbose'  ///
		trtlbl(`trtlbl') conlbl(`conlbl') beflbl(`beflbl') aftlbl(`aftlbl')

		local beforelbl  `r(beforelbl)'
		local afterlbl   `r(afterlbl)'
		local controllbl `r(controllbl)'
		local treatedlbl `r(treatedlbl)'

	if "`cfactlbl'"=="" {
		local cfactlbl Counterfactual
	}


	if "`debug'"~="" {
		di _n as err "Debug output:"
		foreach lcl in  beflbl aftlbl conlbl trtlbl beforelbl afterlbl controllbl treatedlbl  {
			di as err "After -ptok- the local `lcl' is: " as res "``lcl''"
		}
	}

	if `"`title'"'=="" {
		local title title("Difference in differences")
	}

	if "`textsize'"==""  {
		local textsize vsmall
	}
	if "`textsize'"=="vsmall" {
		local dashesto 1.4
	}
	else {
		local dashesto 1.3
	}


	if "`legtitle'"~=  ""  {
		local legtitle title(`"`legtitle'"', size(`textsize'))
	}

	//  Match legend key order to CI and notext options
	local nciopts = wordcount("`allci' `tci' `cfactci'")
	if `nciopts'== 0  {  // Default is no CIs at all
		local margci noci
		local ciopts
		local legorder `legtitle' order(  ///
			1 "`controllbl'" ///
			2 "`treatedlbl'" ///
			3 "`cfactlbl'" ///
			5 "Difference in" "differences")
	}
	else if `nciopts' > 1 {
		di as err "Only one of the three confidence interval options -allci-, -tci- and -cfactci- is permitted."
		exit 198
	}
	else {
		if "`tci'"~="" {
			local margci noci
			local legorder `legtitle' order(  ///
				1 "`controllbl'"  ///
				2 "`treatedlbl'"  ///
				3 "`treatedlbl'" "Confidence" "Interval"  ///
				4 "`cfactlbl'"  ///
				6 "Difference in" "differences")
			if "`ciopts'"=="" {
				local tci 	(pci  \`ll_trt_aft' 1  \`ul_trt_aft' 1, recast(pcbarrow) mangle(vertical) mcolor("scheme p2") msize(small) lpat(solid) lcolor("scheme p2"))
			}
			else {
				local tci 	(pci  \`lb_cnt_aft' 1  \`ub_cnt_aft' 1, recast(pcbarrow) mangle(vertical) `ciopts')
			}
		}
		if "`cfactci'"~="" | "`allci'"~="" {
			local margci noci
			local legorder `legtitle' order(  ///
				1 "`controllbl'" ///
				2 "`treatedlbl'" ///
				4 "`cfactlbl'" ///
				3 "`cfactlbl'" "Confidence" "Interval" ///
				6 "Difference in" "differences")
			if "`ciopts'"=="" {
				local cfactci 	(pci  \`lb_cnt_aft' 1  \`ub_cnt_aft' 1, recast(pcbarrow) mangle(vertical) mcolor("scheme p3") msize(small) lpat(solid) lcolor("scheme p3"))
			}
			else {
				local cfactci 	(pci  \`lb_cnt_aft' 1  \`ub_cnt_aft' 1, recast(pcbarrow) mangle(vertical) `ciopts')
			}
		}
		if "`allci'"~="" {
			if "`ciopts'"=="" {
				local margci `ciopts'
				local legorder `legtitle' order(  ///
					3 "`controllbl'" ///
					1 "`controllbl'" "Confidence" "Interval"   ///
					4 "`treatedlbl'" ///
					2 "`treatedlbl'" "Confidence" "Interval"  ///
					6 "`cfactlbl'" ///
					5 "`cfactlbl'" "Confidence" "Interval"  ///
					8 "Difference in" "differences")
			}
		}
		local lvltxt = subinstr("`level'"," ","",.)
		if "`lvltxt'" ~= "level(95)" | "`showlevelnote'"~="" {
			local lvltxt = substr("`lvltxt'",strpos("`lvltxt'","(")+1,strpos("`lvltxt'",")") - strpos("`lvltxt'","(") - 1)
			local cinote note("Displaying two-sided `lvltxt'% confidence interval(s)")
		}
	}

	if "`keywidth'"=="" & "`legopts'"=="" {
		local keywidth *.8
	}
	if 	"`legopts'"=="" {
		local legopts `legorder' size(`textsize') col(1) symxsize(`keywidth')
	}
	else {
		if strpos("`legopts'","order") {
			local legopts `legopts'
		}
		else {
			local legopts `legorder' `legopts'
		}
	}
	if "`legpos'"==""  {
		local legpos pos(3) ring(1)
	}
	else if strpos("`legpos'","off") {
		//  Reclaim white space on right of graph
	}

if "`parselegopts'"~="" {

	di as inp `"parselegopts, legpos(`legpos') legopts(`legopts') textsize(`textsize') legtitle(`legtitle') legorder(`legorder') debug"'

	parselegopts, legpos(`legpos') legopts(`legopts') textsize(`textsize') legtitle(`legtitle') legorder(`legorder') debug

	Xeq sreturn list

	di _n as inp `"s(legpos) is: " as res `"`s(legopts)'"'
	di _n as inp `"s(legopts) is: " as res `"`s(legopts)'"'

	set trace off
}

if "`debug'"~="" {
	di as err "Debug: legopts is: " as res `"`legopts'"'
	di as err "Debug: legpos is: " as res `"`legpos'"'
}

	if `"`ylabel'"'=="" {
		local ylabel ylabel(,angle(hor))
	}

	//  Restore results from a previous regression
	if "`estrestore'"~="" {
		est restore `estrestore'
		di as txt "Estimates " as res "`estrestore'" as txt " restored from memory"
		est dir `estrestore'
	}

	//  Retrieve from disk results from a previous regression
	if "`estuse'"~="" {
		est use `estuse'
		estimates esample:
		di as txt "Estimates " as res "`estuse'" as txt " retrieved from disk"
		est dir `estuse'
	}

***********************************************************************
****    Determine if the results come from
****    a regression command or from -diff-
****    (This check only works if no intervening commands
****     have ovwerwtten -diff-'s returned results)
***********************************************************************
	//  Look for all 3 characteristic returned results from -diff-
	if "`r(did)'"~="" & "`r(diff0)'"~="" & "`r(diff1)'"~=""   {
		local resultsfrom diff
		di _n as txt "-diffplot- determines that results from Juan Villa's {help diff} are currently in memory"
		local didfromdiff `r(did)'
	}
	else /* if "`r(did)'"=="" & "`r(diff0)'"=="" & "`r(diff0)'"=="" */ {
		if "`e(cmdline)'"==""  | "`e(cmd)'"=="margins"  {
			di _n as err "-diffplot- determines estimated DID results are not currently in memory "  ///
				_n "from either a prior DID regression or from prior execution of Juan Villa's -diff-.'"  ///
				_n "Suggestion: Use the option -estrestore(name)- or -estuse(name)- to apply -diffplot-"  ///
				_n "to a previously stored or saved DID regression result"
			exit 198
		}
		else {
			local regcmdline `e(cmdline)'
			foreach ip in i 1 {
				foreach it in i 1 {
					//  Confirm that approriate interaction coefficient is among estimated coefficients
					//  Assume that both the -period- and the -treated- variables are specified either with the unary operator -i.- or with the prefix -1-.

					//  The -marginslist- must always be -period- followed by -treated-
					//  regardless of the order of the -period- and -treated- variables
					//  in the regression's factor variable interaction term
					if strpos("`regcmdline'","`ip'.`period'##`it'.`treated'") {
						local ptcoef "`ip'.`period'##`it'.`treated'"
						local marginslist `ip'.`period'#`it'.`treated'
					}
					if strpos("`regcmdline'","`it'.`treated'##`ip'.`period'") {
						local tpcoef "`it'.`treated'##`ip'.`period'"
						local marginslist `ip'.`period'#`it'.`treated'
					}
					if strpos("`regcmdline'","`ip'.`period'##`it'.`treated'") | strpos("`regcmdline'","`ip'.`period'#`it'.`treated'") {
						if strpos("`regcmdline'","`ip'.`period'#`it'.`treated'") {
							di as txt `"Suggestion: In the estimation command, specify the interaction with two hashes as -i.`period'##i.`treated'- not with one hash as -i.`period'#i.`treated'-"							'
						}
*						local regcmdline = subinstr(`"`regcmdline'"',"#","##",.)
						local marginslist `ip'.`period'#`it'.`treated'
						local ptcoef1h yes
					}
					if strpos("`regcmdline'","`it'.`treated'##`ip'.`period'") | strpos("`regcmdline'","`it'.`treated'#`ip'.`period'") {
						if strpos("`regcmdline'","`it'.`treated'#`ip'.`period'") {
							di as txt `"Suggestion: In the estimation command, specify the interaction with two hashes as -i.`treated'##i.`period'- not with one hash as -i.`treated'#i.`period'-"'
						}
*						local regcmdline = subinstr(`"`regcmdline'"',"#","##",.)

						local tpcoef1h yes
						local marginslist `ip'.`period'#`it'.`treated'
					}
				}
			}

			if "`ptcoef'`tpcoef'`ptcoef1h'`tpcoef1h'"== ""  {
				di as err "Interaction coefficient not recognizable in command line of the estimation command"
				exit 198
			}
			if "`ptcoef'"~="" & "`tpcoef'"~="" {
				di as err "The estimation command in memory contains two versions of the interaction coefficient, -i.`period'##i.`treated'- and -i.`treated'##i.`period'-"  ///
					_n "Only one, but not both, of the two versions can be included and estimated."
				exit 198
			}
			di _n as txt "-diffplot- determines that results from a regression containing the interaction term " as res "`ptcoef'`tpcoef'" as txt " are currently in memory"
			local resultsfrom regress
		}
	}

***********************************************************************
****    Prepare for -margins- if results are from regression
***********************************************************************

	if "`resultsfrom'"=="regress" {

		local depvar `e(depvar)'

		//  -marginslist- should be of the form i.`period'#i.`treated' which is a single word
		if wordcount(`"`marginslist'"') > 1 {
			di as err `"Incorrect -marginslist- option: -`marginslist'-"'  ///
				_n "Option -marginslist- may contain no spaces"
			exit 198
		}
		else if wordcount("`marginslist'") ==0 {  //  Set the margins default
			local marginslist `ptcoef'`tpcoef'
			local marginslist = subinstr("`marginslist'","##","#",.)
		}
		else if strpos("`marginslist'","#") {  // Strip out extra hash operator
			local marginslist = subinstr("`marginslist'","##","#",.)
		}
		else {
			di as err `"Incorrect -marginslist- option: -`marginslist'-"'  ///
				_n "Option -marginslist- must have a hash (#) operator"
				exit 198
		}

		//  Trap the -reg4margins()- option
		if "`reg4margins'"~= ""  {
			di as err "Option -reg4margins(`reg4margins')- is ineffective because prior DID estimates are not from -{stata help diff:diff}-"  ///
				_n "No estimates are stored. -diffplot- excecution continues..."
		}
	}


********************************************************************************************
****    Prepare for -margins- if results are from Villa's -diff.ado- version  5.0.1 Dec2019
********************************************************************************************
	if "`resultsfrom'"=="diff" {

		//	Strategy for constructing plot from -diff- results:
		//		In order to use marginsplot, we must construct a viable set of -ereturn- information using -erepost- and -estadd-
		//		(1) Replace the variable -`period'- with -1.`period'- in e(b), e(V) and e(cmdline)
		//		(2) Replace the variable -`treated'- with -1.`treated'- in e(b), e(V) and e(cmdline)
		//		(3) replace the _diff coefficient name in e(b) and e(V) with -i.`period'##i.`treated'- in e(b), e(V) and e(cmdline)
		//		(4) if -diff-'s -bootstrap- option was used, additionally modify the ereturn results with -estadd- (which is part of -estout-)

		foreach prg in estout erepost {
			capt qui which `prg'
			if _rc > 0 {
				di _n as err "To use -diffplot- after the community contributed {help diff} requires the community contributed command {help `prg'}, by Ben Jann" ///
					_n "Search for and install it by clicking {search `prg':here}."
					exit 111
			}
		}

		local depvar `r(depvar)'

		tempname eb
		mat def `eb' = e(b)
		local diffcnms0 : colnames `eb'
		if "`e(cmd)'" =="bootstrap"  {
			local diffcnms : colnames `eb'
			local newcnms = subinstr("`diffcnms'","b_cons","_cons", .)
			local newcnms = subinstr("`newcnms'","b_","", .)
			mat colnames `eb' = `newcnms'
			// -diff- has set macro -predict- to "_no_predict"
			estadd local predict regres_p , replace
			// -diff- has set e(sample) to exclude `period'==0
			tempvar tmptouse
			clonevar `tmptouse'= `touse'
			local esample esample(`tmptouse')
			local diff_estimator diff_with_bootstrap
		}
		else {
			local diff_estimator diff_wo_bootstrap
		}
//	BUG here:  When the -period- variable and -group- variable are defined
//	with options "period(t) treated(treated)", this logic replaces BOTH t's
//	in the variable name -treated- with "1.t", producing an illegal variable
//	and hence column name of: "1.trea1.ted".
//	Work around: Rename one-letter variables:  i.e. rename variable t to e.g. "year" or "month" or "after"
		local diffcnms : colnames `eb'
		local newcnms = subinstr("`diffcnms'","`period'","1.`period'", .)
		local newcnms = subinstr("`newcnms'","`treated'","1.`treated'", .)
		local newcnms = subinstr("`newcnms'","_diff","1.`period'#1.`treated'", .)

		`shhh' di as txt "Original column names for the -diff- e(b) are: " as res "`diffcnms0'"
		`shhh' di as txt "New column names for the -diff- e(b) are: " as res "`newcnms'"

		mat colnames `eb' = `newcnms'

		erepost b = `eb' , cmd(diffplot) rename `esample'

		//  Optionally store the modified regression or pseudo-regression results to be used by -margins-
		if "`reg4margins'"~= ""  {
			local newcmdline = subinstr("`e(cmdline)'","`period'","1.`period'", .)
			local newcmdline = subinstr("`newcmdline'","`treated'","1.`treated'", .)
			local newcmdline = subinstr("`newcmdline'","_diff","1.`period'#1.`treated'", .)
			local newcmdline = subinstr("`newcmdline'","_diff","1.`period'#1.`treated'", .)
			`shhh' estadd local cmdline `"`newcmdline'"' , replace

			est store `reg4margins', title("-diff-'s ereturn results with coefficient names modified by -diffplot- to be acceptable to -margins-")
		}

		local marginslist i.`period'#i.`treated'

	}

***********************************************************************
****    Execute -margins and create the graph regardless of whether
****    estimates come from -diff- or a regression
***********************************************************************


	********************
	* Default ytitle *
	********************
	if `"`ytitle'"'==`""' {
		local depvlbl : variable label `depvar'
		local ytitle ytitle(`"Estimated `depvlbl'"')
	}

	********************
	* Set observations *
	********************
	tempname totobs
	qui: summ `touse' if `touse'
	scalar `totobs' = r(N)
	tempname blo0
	qui: summ `touse' if `period' == 0 & `treated' == 0 & `touse'
	scalar `blo0' = r(N)
	tempname blo1
	qui: summ `touse' if `period' == 0 & `treated' == 1 & `touse'
	scalar `blo1' = r(N)
	tempname flo0
	qui: summ `touse' if `period' == 1 & `treated' == 0 & `touse'
	scalar `flo0' = r(N)
	tempname flo1
	qui: summ `touse' if `period' == 1 & `treated' == 1 & `touse'
	scalar `flo1' = r(N)
	return clear

	if `"`marginslist'"'==""  {
	    di as err "The option -marginslist()- is empty.  It must be specified by the user"  ///
			_n "or inferred from a previous -diff- or estimation command."
			exit 198
	}
	if `"`margat'"'~=""  {
		local margat at(`margat')
	}
	if "`verbose'"~="" {
		di _n as txt "Estimated levels at `controllbl' `beforelbl' & `afterlbl' and `treatedlbl' `beforelbl' & `afterlbl'"  ///
			_n "as estimated by the following -margins- command:"  ///
			_n(2) as inp `"margins `marginslist', `expression' `margat' post `level' `estimcheck'"'
	}
	// -margins'- -post- option required for subsequent -lincom-
	// -margins'- are left in -ereturn- at termination of -diffplot-
	// After -xtreg ..., fe-, the option noestimcheck may be required
	`shhh' margins `marginslist', `expression' `margat' post `level' `estimcheck'

	tempname eb rt
		mat define `eb' = e(b)
		mat define `rt' = r(table)
		if "`debug'"=="debug" {
			di _n as txt "After executing {help margins} on the estimation results,"  ///
				_n as txt "the e(b) matrix in memory is:"
			mat list `eb', noheader
			di _n as txt "and the r(table) matrix in memory is:"
			mat list `rt', noheader
		}

	//	Define -outmat- matrices to hold estimation results from -margin-'s r(table) and e(b)
	tempname outmat outmat_b outmat_se outmat_t outmat_p outmat_N
	// Notation:  cnt := Control group; trt := `treated' or Treatment Group; b4 := Before; aft := After; cfact := Counterfactual
	// Column names:           cnt_b4          cnt_aft     cnt_dif             trt_b4        trt_aft      trt_dif         did   trt_cfact   b4_dif aft_dif
	mat define `outmat_b' = ( el(`rt', 1,1), el(`rt', 1,3),    .        ,  el(`rt', 1,2), el(`rt', 1,4) ,     .       ,    .   ,    .    ,    .   ,  .   )
	mat define `outmat_se'= ( el(`rt', 2,1), el(`rt', 2,3),    .        ,  el(`rt', 2,2), el(`rt', 2,4) ,     .       ,    .   ,    .    ,    .   ,  .   )
	mat define `outmat_t' = ( el(`rt', 3,1), el(`rt', 3,3),    .        ,  el(`rt', 3,2), el(`rt', 3,4) ,     .       ,    .   ,    .    ,    .   ,  .   )
	mat define `outmat_p' = ( el(`rt', 4,1), el(`rt', 4,3),    .        ,  el(`rt', 4,2), el(`rt', 4,4) ,     .       ,    .   ,    .    ,    .   ,  .   )
	mat define `outmat_N' = (    `blo0'    ,    `flo0'    ,`blo0'+`flo0',     `blo1'    ,     `flo1'    ,`blo1'+`flo1',`totobs',    .    ,`blo0'+`blo1',`flo0'+`flo1')
	mat colnam `outmat_b'  = cnt_b4 cnt_aft cnt_dif trt_b4 trt_aft trt_dif did trt_cfact b4_dif aft_dif

	//  Populate -outmat- row vectors with results of hypothesis tests
	`shhh' di _n as txt "Ho: `afterlbl' - `beforelbl' in `controllbl' group is zero:"
	`shhh' lincom (_b[1.`period'#0.`treated'] - _b[0.`period'#0.`treated']), `level'	// Increase in control group
		mat define `outmat_b'[1,3]   = `r(estimate)'
		mat define `outmat_se'[1,3] = `r(se)'
		mat define `outmat_t'[1,3]   = `r(estimate)'/`r(se)'
		mat define `outmat_p'[1,3]  = `r(p)'

	`shhh' di _n as txt "Ho: `afterlbl' - `beforelbl' in `treatedlbl' group is zero:"
	`shhh' lincom (_b[1.`period'#1.`treated'] - _b[0.`period'#1.`treated']), `level'  // Increase in treatment group
		mat define `outmat_b'[1,6]   = `r(estimate)'
		mat define `outmat_se'[1,6] = `r(se)'
		mat define `outmat_t'[1,6]   = `r(estimate)'/`r(se)'
		mat define `outmat_p'[1,6]  = `r(p)'

	`shhh' di _n as txt "Ho: Difference in differences is zero:"
	`shhh' lincom (_b[1.`period'#1.`treated'] - _b[0.`period'#1.`treated'] ) - (_b[1.`period'#0.`treated'] - _b[0.`period'#0.`treated']), `level'
		mat define `outmat_b'[1,7]   = `r(estimate)'
		mat define `outmat_se'[1,7] = `r(se)'
		mat define `outmat_t'[1,7]   = `r(estimate)'/`r(se)'
		mat define `outmat_p'[1,7]  = `r(p)'
		local did = `r(estimate)'
		local esttxt : di %-9.`sdec'g `did'
		local p_did = `r(p)'
		local p_esttxt : di %-9.`sdec'g `p_did'

	//  Compute the After Counterfactual  =  Intercept + Slope
	`shhh' di _n as txt "Ho: `cfactlbl' at `afterlbl' is zero:"
	`shhh' lincom ( _b[0.`period'#1.`treated']  + (_b[1.`period'#0.`treated'] - _b[0.`period'#0.`treated'])), `level'
		mat define `outmat_b'[1,8]   = `r(estimate)'
		mat define `outmat_se'[1,8] = `r(se)'
		mat define `outmat_t'[1,8]   = `r(estimate)'/`r(se)'
		mat define `outmat_p'[1,8]  = `r(p)'
		local lb_cnt_aft = `r(lb)'
		local ub_cnt_aft = `r(ub)'

	`shhh' di _n as txt "Ho: `treatedlbl' - `controllbl' at `beforelbl' is zero:"
	`shhh' lincom (_b[0.`period'#1.`treated'] - _b[0.`period'#0.`treated']), `level'  // Treated - Control before intervention
		mat define `outmat_b'[1,9]   = `r(estimate)'
		mat define `outmat_se'[1,9] = `r(se)'
		mat define `outmat_t'[1,9] = `r(estimate)'/`r(se)'
		mat define `outmat_p'[1,9]  = `r(p)'

	`shhh' di _n as txt "Ho: `treatedlbl' - `controllbl' at `afterlbl' is zero:"
	`shhh' lincom (_b[1.`period'#1.`treated'] - _b[1.`period'#0.`treated']), `level'	// Treated - Control after intervenetion
		mat define `outmat_b'[1,10]   = `r(estimate)'
		mat define `outmat_se'[1,10] = `r(se)'
		mat define `outmat_t'[1,10]   = `r(estimate)'/`r(se)'
		mat define `outmat_p'[1,10]  = `r(p)'

	//  Space betwn -\- & -`- is obligatory
	mat define `outmat' = (`outmat_b' \ `outmat_se' \ `outmat_t' \ `outmat_p' \ `outmat_N')
		mat rownames `outmat' = estimate  std_err  t-stat  p-value Nobs

*	DEBUG
if "`debug'"~=""  {
	foreach s in _b _se _t _p _N {
		matlist `outmat`s'', title("Debug: Temporary matrix -outmat`s'-")
	}
	di _n as txt "Debug: Temporary matrix -outmat- is: "
	matlist `outmat', title("Returned matrix -r(outmat)-")
}

	local c = 1  // column number of -outmat- matrices
	foreach est in cnt_b4 cnt_aft cnt_dif trt_b4 trt_aft trt_dif did trt_cfact b4_dif aft_dif {
		local `est' = `outmat'[1,`c']
		local `est'txt : di %-9.`sdec'g ``est''
		foreach s in _se _t _p {
			local `est'`s' = `outmat`s''[1,`c']
			local `est'`s'txt : di %-9.`sdec'g ``est'`s''
		}
		local c = `c' + 1
	}

	//	Define local macros from matrix elements
	local ll_trt_aft = el(`rt', 5,4)
	local ul_trt_aft = el(`rt', 6,4)
	local df_did  = el(`rt', 7,4)

	local intercept = el(`rt', 1,2)
	local slope = (el(`rt', 1,3) - el(`rt', 1,1)) / 1
	local lb_did = `intercept' + `slope'
	local lb_didtxt : di %-9.`sdec'g `lb_did'
	local ub_did = el(`rt', 1,4)
	local ub_didtxt : di %-9.`sdec'g `ub_did'
	local mid_dif = (`lb_did' + `ub_did')/2

	//  implement -difftxtleft- option
	opts_exclusive "`difftxtleft' `text'"
	if "`difftxtleft'"==""  {
		local difftext 	text(\`mid_dif' 1.7 "Difference in" "differences: `esttxt'" "p = `p_esttxt'",size(\`textsize') just(left))
		local diffdashes (pci `mid_dif' 1.2  `mid_dif' `dashesto', lpat(shortdash) lcolor("scheme p"%50))
	}
	else {
		local difftext 	text(\`mid_dif' -.1 "Difference in" "differences: `esttxt'" "p = `p_esttxt'",size(\`textsize') just(left))
		local diffdashes (pci `mid_dif' 0.1  `mid_dif' 1.2, lpat(shortdash) lcolor("scheme p"%50))
	}

	//  implement -b4txtleft- option
	opts_exclusive "`b4txtleft' `beftxtleft' `text'"
	if "`b4txtleft'`beftxtleft'"==""  {
		local minrange -.1
		local maxrange  2
		local rtmargtext     5
		local rtmargnotext  10
		local cntb4text 	text(\`cnt_b4'  1.7 "`controllbl' at" "`beforelbl': `cnt_b4txt'",size(\`textsize') just(left))
		local cntb4dashes (pci  `cnt_b4'     0  `cnt_b4'  `dashesto', lpat(shortdash) lcolor("scheme p"%50))
		local trtb4text     text(\`trt_b4'  1.7 "`cfactlbl' &" "`treatedlbl' at" "`beforelbl': `trt_b4txt'",size(\`textsize') just(left))
		local trtb4dashes (pci  `trt_b4'     0  `trt_b4'  `dashesto', lpat(shortdash) lcolor("scheme p"%50))
	}
	else {
		local minrange -.75
		local maxrange  2.5
		local rtmargtext     0
		local rtmargnotext   5
		local cntb4text 	text(\`cnt_b4'  -0.25 "`controllbl' at" "`beforelbl': `cnt_b4txt'",size(\`textsize') just(left))
*		local cntb4dashes (pci  `cnt_b4'     0  `cnt_b4'  0.5, lpat(shortdash) lcolor("scheme p"%50))
		local cntb4dashes    //  No need for dashes if text is on the left
		local trtb4text     text(\`trt_b4'  -0.25 "`cfactlbl' &" "`treatedlbl' at" "`beforelbl': `trt_b4txt'",size(\`textsize') just(left))
*		local trtb4dashes (pci  `trt_b4'     0  `trt_b4'  0.5, lpat(shortdash) lcolor("scheme p"%50))
		local trtb4dashes    //  No need for dashes if text is on the left
	}

	//  Save existing graphics setting for subsequent restoration
	local gphset `c(graphics)'
	if "`gphset'"=="off" di as txt "At -diffplot- execution, Stata's graphics is set to " as res "`c(graphics)'"

	//	Suppress -twoway-'s time-consuming preliminary display prior to the integration of the -addplots-
	set graphics off
	//	Produce graph with text
	if "`text'"=="" {  //  Option -text- is either blank or -notext-
	    local xscale  xscale(range(`minrange'/`maxrange') noextend)  plotregion(margin(0 `rtmargtext' 0 0))
		`shhh' marginsplot , `xscale' `margci' ///
			xlabel(0 "`beforelbl'" 1 "`afterlbl'")  ///
			text(`ub_did'  1.7 "`treatedlbl' at" "`afterlbl': `ub_didtxt'",size(`textsize') just(left))  ///
			text(`lb_did'  1.7 "`cfactlbl' at" "`afterlbl': `lb_didtxt'",size(`textsize') just(left))  ///
			text(`cnt_aft' 1.7 "`controllbl' at" "`afterlbl': `cnt_afttxt'",size(`textsize') just(left))  ///
			`cntb4text' `trtb4text' `difftext'    ///
			`title' `subtitle' `ytitle' `ylabel' `xtitle' `cinote'  ///
			legend(`legpos')  ///
			addplot(  `cfactci' `tci' ///
				(pci  `intercept'  0  `lb_did'   1,   ///  trend line for counterfactual
					xlabel(0 "`beforelbl'" 1 "`afterlbl'") lpat(dash) lcolor("scheme p3") `xscale' `ylabel')  ///
				(scatteri  `lb_did'   1,   ///   marker symbol for counterfactual at -After-
					mcolor("scheme p3") legend(`legopts') )  ///
				(pcarrowi `ub_did' 1.2 `lb_did' 1.2,   ///  DID vertical span
					recast(pcbarrow) lcolor("scheme p") mcolor("scheme p"))  ///
				`cntb4dashes' `trtb4dashes' `diffdashes'  ///
				(pci  `lb_did'      1  `lb_did'   `dashesto',   ///
					lpat(shortdash) lcolor("scheme p"%50))  ///
				(pci  `ub_did'      1  `ub_did'   `dashesto',   ///
					lpat(shortdash) lcolor("scheme p"%50))  ///
				(pci  `cnt_aft'    1  `cnt_aft' `dashesto',   ///
					lpat(shortdash) lcolor("scheme p"%50))  ///
			) `name' `saving' `options'

	}
	//	Produce graph without text
	else {
	    if `"`legopts'"'=="off" | "`text'"=="notext" {
		    local xscale  xscale(range(-.1/1.6) noextend) plotregion(margin(0 `rtmargnotext' 0 0))
		}
		else {
		    local xscale  xscale(range(-.1/2) noextend)
		}
		`shhh' marginsplot , `xscale' `margci' ///
			xlabel(0 "`beforelbl'" 1 "`afterlbl'")  ///
			`title' `subtitle' `ytitle' `ylabel' `xtitle' `cinote'  ///
			legend(`legpos')    ///
			addplot(  `cfactci' `tci' ///
				(pci  `intercept'  0  `lb_did'   1,   ///  trend line for counterfactual
					xlabel(0 "`beforelbl'" 1 "`afterlbl'") `xscale'  `ylabel' lpat(dash) lcolor("scheme p3"))  ///
				(scatteri  `lb_did'   1,   ///   marker symbol for counterfactual at -After-
					`xscale' mcolor("scheme p3")  legend(`legopts'))  ///
				(pcarrowi `ub_did' 1.2 `lb_did' 1.2,   ///  DID vertical span
					`xscale' recast(pcbarrow) lcolor("scheme p") mcolor("scheme p"))  ///
			) `name' `saving' `options'
	}

	//	Restore original graphics setting
	set graphics `gphset'
	//	Display the composite -diffplot- graph, including the -addplot-s
	if "`gphset'"=="on" {
		if "`name'"~="" {
			tokenize "`name'" , parse(" ,()")
			if "`debug'"~=  ""  di as err "-tokenize- parses -diffplot-'s option -name-: 1=|`1'|, 2=|`2'|, 3=|`3'|, 4=|`4'|, 5=|`5'|, 6=|`6'|"
			graph display `3'
		}
		else if "`saving'"~="" {
			tokenize "`saving'" , parse(" ,()")
			if "`debug'"~=  ""  di as err "-tokenize- parses -diffplot-'s option -saving-: 1=|`1'|, 2=|`2'|, 3=|`3'|, 4=|`4'|, 5=|`5'|, 6=|`6'|"
			graph use `"`3'"'
		}
		else {
			graph display Graph
		}
	}
	else {
		set graphics `gphset'
	}

	// make table(s)
	if "`difftable'"~="" {

		difftable `depvar' if `touse' `using' , resultsfrom(`resultsfrom') period(`period') treated(`treated') ///
			beforelbl(`beforelbl') afterlbl(`afterlbl') controllbl(`controllbl') treatedlbl(`treatedlbl')  ///
			outmat(`outmat') `frmtopts' `stats' `pstars' `cfact' `title' sdec(`sdec') `verbose' `debug' `replace'

		tempname dtblrtrn
		mat def `dtblrtrn' = r(difftable)
		return matrix difftable = `dtblrtrn'

		local frmtaddtable frmtaddtable
		local replace
	}

	if "`tradtable'"~="" {

		tradtable `depvar' if `touse' `using' , resultsfrom(`resultsfrom') period(`period') treated(`treated') ///
			beforelbl(`beforelbl') afterlbl(`afterlbl') controllbl(`controllbl') treatedlbl(`treatedlbl')  ///
			outmat(`outmat') `frmtopts' `stats' `pstars' `frmtaddtable' `title' sdec(`sdec') `verbose' `debug' `replace'

		tempname ttblrtrn
		mat def `ttblrtrn' = r(tradtable)
		return matrix tradtable = `ttblrtrn'

	}

	return add  //  Retain only from last execution of an rclass program

	// macros
	return local legpos `legpos'
	return local legopt `legopts'
	return local didfromdiff  `didfromdiff'  // If present

	//  scalars
	return scalar intercept = `intercept'
	return scalar slope = `slope'
	return scalar lb_did = `lb_did'
	return scalar ub_did = `ub_did'
	return scalar mid_dif = `mid_dif'
	return scalar trt_b4 = `trt_b4'
	return scalar trt_aft = `trt_aft'
	return scalar cnt_b4 = `cnt_b4'
	return scalar cnt_aft = `cnt_aft'
	return scalar ll_trt_aft = `ll_trt_aft'
	return scalar ul_trt_aft = `ul_trt_aft'
	return scalar df_did  = `df_did'

	return scalar did = `did'
	return scalar p_did = `p_did'

	// matrices
	return matrix eb = `eb'
	return matrix outmat  = `outmat'

end  /* End of main program -diffplot-  */

/*
Following subroutines are now external programs:
	ptok.ado
	difftable.ado
	tradtable.ado
	getfrmt4diff.ado
	getfrmt4trad.ado
The following supplementary help file documents -frmttable- options:
	frmttable_opts_for_diffplot.sthlp
*/

exit

*	Version history:
*	1.0 31Mar2019:	First version
*	1.1 4Apr2019: Add verbose option, the outmat_se matrix, the -int_cfact- column
*		Stack the outmat_b, outmat_se and outmat_p matrices into r(outmat)
*		Add the -unwind(function)- option to transform results to different metric
*		Add the -notext- option to suppress the text in the graphs
*		Biggest change:  Replace option -margexpression(string)-
*		with -expression(passthru).  This breaks previous DO files.
*	1.2 9Apr2019: Add the -xtitle- option
*	1.3 9Apr2019: Add trt_aft, cnt_b4, cnt_aft estimates to return space
*	1.4 3May2019: Add error trap to asure -addplot- is installed
*	1.5 10May2019: Allow -margat- and -restore- to be optional
*	2.1 27Sep2020: Replace Baseline/Endline with Before/After
*		Detect whether estimated DID results in memory are from -diff- or
*		or from a previous regression with a i.period#i.treatment coefficient.
*		If from -diff-, rename the matrix stripes to fool -margins- into
*		thinking coefficients were estimated with factor variables.
*		Optionally store the modified quasi-regression results as -reg4margins-
*		Replace -twoway function- with -twoway pci-
*		Use Jann's -erepost- instead of my -addest-
*		Allow four CI options: -none-, -allci-, -cfactci- and -tci-
*	2.2 2Oct2020: Add -title- and -subtitle- passthru options
*		Fix wrong numbers in -text- output
*		Enable using prior -regress- results instead of prior -diff- results
*		Change -int_- prefixes to -trt_- prefixes
*	2.3 9Oct2020: Add an error trap for -reg4margins- option after -regress-
*		Fix syntax for option -title-.
*		Add frmttable output option for -tradtable-. Program -getfrmtcmdline-
*	2.4 12Oct2020: Make number of substats user selectable in -tradtable-
*		Add options -beforealt-, -afteralt-, -controlalt- and -treatedalt-
*		to relabel these concepts in the graph and table output.
*   2.5 13Oct2020: Switch to use -marginsplot-'s option -addplot-
*		instead of Jann's -addplot- program.
*		Now -gr combine- works, but not -grc1leg- or -grc1leg2-.
*		Add option -difftxtleft-
*   2.6 15Oct2020: Fix mistaken star placement on DID in -tradtable-
*		and enable user selection of pstars for the stars and of
*		-asymbol- to select other symbols.
*		Enable interpretation of -diff- with its bootstrap option
*		Sub "_" for " " in before, after, control, treated labels
*		Add trap if -erepost- or -estadd- not installed
*		Move -return add- to end of main program to avoid deleting
*		-diff- return results prematurely. Change -frmt_opts- to -FRMTOpts-.
*		Enable user to specify -N- as one of the statistics for tradtable-
*	2.7 18Oct2020:  Add saving and -*- options
*	2.8 20Oct2020:	Add -difftable- option -cfact- for the counterfactual.
*		Require variables -period- and -treated- to be numeric
*		Change option -Xalt- to -xlbl-, for all four user-supplied labels,
*		where X = {before, after, etc.} and x = {bef, aft, con, trt}.
*		Fix -ptok- so that user-selected labels beforealt, afteralt, etc.
*			take priority over pre-existing value labels.
*		For -tradtable-, fix bug which allowed non-N results to sometimes
*		appear in the body of the table.
*	2.9 27Oct2020:  Rename -getfrmtcmdline- as -getfrmt4trad- and add
*		subroutine -getfrmt4diff- to parse -frmttable- options for -difftable-
*		Enable both -difftable- and -tradtable- options on same execution of -diffplot-
*		(uses the internal option -frmttradtable-.)
*		Rename the -substats(se t p)- option as -stats(se t p)-
*		Fix bug in -tradtable- when N is omitted from -stats()-
*		Change default stat format in graph to %-9.`sdec'g
*		In -tradtable-, set sdec to 0 for N. Display N & se in interior cells.
*		Apply the -title()- option to both tables as well as to the graph
*	2.10 27Oct2020: Revise solid/dotted lines in difftable.
*		Change the name of the macro -estdifndif- to -did-
*		If -diffplot- follows -diff-, also return -didfromdiff-
*	2.11 12Feb2021: Since -est restore- is not guaranteed
*		to recover -e(sample)-, which -margins- requires,
*		rename the -restore- option as -ESTRestore-
*		and add the option -ESTUse- so that the user has the option
*		of recalling to memory estimation results
*		from disk that include the -e(sample)-.
*	2.13 28Apr2023: The margins command's argument, -marginslist-,
*		determines the order of the rows of its -r(table)- output regardless
*		of the order of the interacted factor variables in the referenced
*		regression results, use the same order for the -marginslist-
*		in each case in lines 255ff.
*	2.14 1May2023: Fix check for only two-values of -period-
*		Enable the option -level()- to control width of CIs and
*		add a note to the plot when level~=95.
*		Make -diffplot- scheme independent by globallly replacing:
*			 -black- with -"scheme p"-  (N.B. Quotes are essential)
*			 -maroon - with -"scheme p2"-
*			 -dkgreen- with -"scheme p3"-
*		Add error trap to catch when one of the two variable names,
*		period() or treated(), occurs as a character string
*		within the other variable name.
*		Add the undocumented -noestimcheck- option for the margins command.
*			Required for -xtreg ..., fe- if model is oversaturated
*			as with Card & Kreuger data.
*			However, -xtreg ..., re- works without the -noestimcheck option
*	3.0 4Aug2023: In the syntax command, replace name(string) with name(passthru).
*		Set graphics off until twoway has completed constructing the graph
*		with all the added plots.  Then turn it back on for the display.
*		Add the option -beftxtleft- to move both of the "Before" labels
*		(for Control and for Counterfactual & Control) to the left of the plot
*		independently  of option -difftxtleft-.
*		Set the default -ytitle- to the label of the dep variable
*		Fix bug in user-controlled ylabel, by adding `ylabel' option to the addplot -pci- graphs
*		Left-justify text labels.
*		Fix bug in -getfrmt4trad- so that the N statistic is displayed with 0 digits.
*		If either the level differs from 95 or the level option is selected in -diffplot-,
*		display a note specifying the confidence level for confidence intervals.
*		Allow -stat()- as an abreviation of the option -stats()-.
*		For -difftable-, add an optional column for N for each row
*		For -difftable-, add the note: *** p<0.01; ** p<0.05; * p<0.1
*		Delete the undocumented -unwind()- option and code in favor of option -expression()-
*	3.1 8Apr2024: Allow optional replacement of term "counterfactual"
*		with the option cfactlbl(string)

*		TODO:
*		1. Would -at(passthru)- be better than -margat(string)-?
*		2. For -tradtable-, consider adding a row for the counterfactual
*		3. For -difftable-, enable user-specified -frmttable- options
*		4. Which -frmttable- options belong in -frmtopts()-?
*		Coordinate and distinguish -getfrmt4trad- from -getfrmt4diff-
*		What options do they both process and which are specific to a table type?
*		Assure parsing of -frmttable- options and protect user from
*		conflicts caused by using an option on -diffplot- command line or
*		as one of the -frmtopts()- options.

*		ISSUES:
*		1. With Abadie data, the standard errors of the margins estimates of
*		-margins "i.period# i.treated"- are all identical.
*		However, this is no longer true if we randomly unbalance the data.
*		What's going on here? Is is this an example of a general property?
*		2. When we insist on common support with the -diff- option -support-,
*		how do we communicate the dropped observations in the two tables?
*		3. Can -diffplot- accommodate Stata's DID estimation commands
*		like -didregress- and -xtdidregress-?  At first glance "no",
*		because they don't accept a subsequent margins command.
*		4. Can -diffplot- be used after a margins command instead of after
*		an estimation command?
*		5. Confirm the impracticality of accommodating -diff-'s triple difference results.
*		6. Options -sdec- and -title-, when specified among -frmtopts(opts)-,
*		should in principle be able to override the similar options from -diffplot-.
*		But this doesn't work.
*		7.  Added error trap in -ptok-, but is there a way to permit
*		one variable name to be included in the other?
*		For example, could -diffplot- use temporary names to refer to the two key variables?
*		Or in lines 373ff, can we substitute by matching entire variable names
*		instead of by character string matching?
*		8. Should be able to suppress all notes by adding the option -note(" ")- or -nonotes-.
*		9. Is there a better way to label time periods 0 and 1 then with the word "at"?