capture program drop margin
program define margin
*! Average marginal effects for categorical and limited dependent variable models
*! This version: 28 October 2004 - Author: Tamas Bartus

	if int(_caller())<6 {
		di in r "-margin- does not support this version of Stata"
		exit
	}
	if int(_caller())<8 {
		margin6 `0'
	}
	else margin8 `0'
end


program define margin8 , eclass
	version 8

*******************************************************************************
*
* [1] SYNTAX CHECK, ESTIMATION
*
*******************************************************************************

	if "`e(cmd)'"=="" {
		di in r "Last estimates not found"
		exit 301
	}
	if "`e(cmd)'"!="margin" {
		if `e(df_m)'==0  {
			di in r "There are no independent variables; running -margin- makes no sense"
			exit
		}
	}

	syntax [ , Count Model(string) Eform Dummies(string) Percent Replace  Table NOOFFset trace hascons mean]
	local Doit = ("`model'`count'`eform'`dummies'`table'`nooffset'`hascons'`mean'"!="")|("`e(margin_cmd)'"=="")
	if "`e(cmd)'"=="margin" {
		local Doit = 0
	}

	if `Doit'==1 {	/* START OF ESTIMATION */
		if "`eform'"!="" {
			local length : word count `e(depvar)'
			if `length'>1 {
				di in r "The eform option can only be used after single-equation commands"
				exit
			}
		}
   		if "`model'"=="" {
			local model = e(cmd)
		}

		SetEnv `model' `eform' /* Checks model & sets environment */

		if "`s(type)'"=="0" {
			di in r "-margin- does not work with `model'; use -mfx- instead"
			exit
		}
		if "`dummies'"!="" {
			local dummies dummies(`dummies')
		}

		preserve
		margin_e `depvar' , `eform' `table' `dummies' `count' `nooffset' `trace' `hascons' `mean'
		restore

	}  /* END OF ESTIMATION */


*******************************************************************************
*
* [2] COLLECTING AND DISPLAYING RESULTS
*
*******************************************************************************

	tempname b V bpost Vpost tab
	tempvar touse

	local Prefix margin_
	local Class e
	if "`e(cmd)'"=="margin"	 {
		local Prefix
	}
	else if `Doit'==1 {
		local Class r
	}

	mat `b' = `Class'(`Prefix'b)
	mat `V' = `Class'(`Prefix'V)
	mat `tab' = `Class'(margin_tab)
  	local depvar = `Class'(margin_depv)
  	local title  = `Class'(margin_title)
  	local cmd    = `Class'(margin_cmd)

	local numobs = e(N)
	qui gen byte `touse' = e(sample)
	local mdf  = e(df_m)
	local rdf  = e(df_r)
	if `rdf'!=. {
		local df "dof(`rdf')"
	}
	if "`depvar'"!="" {
		local depname depname(`depvar')
	}

	* Display form (avoiding double percentages)

	local dispform asis
	if `"`e(margin_display)'"'=="percent" {
		local percent
		local dispform percent
	}
	if `"`e(margin_display)'"'!="percent" & "`percent'"!="" {
		local percent  percent
		local dispform percent
	}

	if  "`percent'"!="" {
		mat `b' = 10^2 * `b'
		mat `V' = 10^4 * `V'
	}

	mat `bpost' = `b'
	mat `Vpost' = `V'

	if  "`replace'"=="" {
		tempname ehold
		_est hold `ehold'
	}

	di
	di in g "Marginal effects on " in y "`title'" in g " after " in y "`cmd'"
	di
	ereturn post `bpost' `Vpost' , `df' `depname' obs(`numobs') esample(`touse')
	ereturn disp

	if  "`replace'"=="" {
		_est unhold `ehold'
	}
	else {
		ereturn local cmd      margin
		ereturn scalar df_m =  `mdf'
		if `rdf'!=. {
			ereturn scalar df_r = `rdf'
		}
	}
	ereturn mat   margin_b        `b'
	ereturn mat   margin_V        `V'
	ereturn mat   margin_tab      `tab'
	ereturn local margin_display  `dispform'
	ereturn local margin_title    `title'
	ereturn local margin_depv     `depvar'
	ereturn local margin_cmd      `cmd'

	if "`table'"!="" {
		if "`percent'"!="" {
			local format %12.2f
		}
		else local format %20.5f
		di _newline(2) in g "Descriptive statistics for individual marginal effects"
		di
		mat list e(margin_tab) , noblank nohalf noheader format(`format')
	}

end


program define SetEnv , sclass
	version 6
	sret clear
	sret local model "`1'"
	sret local ncons 1
	if "`2'"!="" {
		sret local type 9
		sret local neq  1
		sret local nout 1
		sret local nap  0
		exit
	}
	else if "`1'"=="logit"    | "`1'"=="logistic" | "`1'"=="probit"  | "`1'"=="cloglog" | /*
		*/  "`1'"=="poisson" {
		sret local nout 1
		sret local type 1
		sret local neq  1
		sret local nap  0
		exit
	}
	else if "`1'"=="xtprobit" | "`1'"=="xtlogit"  | "`1'"=="nbreg" | /*
		*/  "`1'"=="tobit"    | "`1'"=="cnreg"    | "`1'"=="intreg"  | "`1'"=="truncreg"  {
		sret local nout 1
		sret local type 1
		sret local neq  1
		sret local nap  1
		exit
	}
 	else if "`1'"=="oprobit"  | "`1'"=="ologit" {
		qui tab `e(depvar)'	if e(sample)
		local ncons = e(k_cat)-1
		local nout = r(r)
		sret local ncons `ncons'
		sret local neq  1
		sret local nout `nout'
		sret local type 2
		sret local nap `ncons'
		exit
	}
	else if "`1'"=="mlogit" | "`1'"=="gologit"  {
		qui tab `e(depvar)' if e(sample)
		local neq = r(r)-1
		local nout = r(r)
		sret local ncons 1
		sret local neq  `neq'
		sret local nout `nout'
		sret local type 2
		sret local nap  0
		exit
	}
	else if "`1'"=="heckman"  | "`1'"=="heckprob" | /*
		*/  "`1'"=="biprobit"  | "`1'"=="zip"      | "`1'"=="zinb"       {
		local neq = 2
		local nout = 1 + ("`1'"=="biprobit")*3 + (substr("`1'",1,2)=="zi")*2
		local type = 3
		if "`1'"=="biprobit" {
			if substr(e(title),1,1)=="B" {
				local type = 2
			}
			*else local nout 1
			else local type 0
		}

		sret local neq `neq'
		sret local nout `nout'
		sret local type `type'
		if "`1'"=="heckman" {
			sret local nap 2
		}
		else if "`1'"=="zip" {
			sret local nap 0
		}
		else sret local nap 1
		exit
	}
	else sret local type 0
end