*! arrowplot: Combined macro scatter and micro regression plot
*! Version 1.0.0 agosto 18, 2014 @ 00:14:47
*! Author: Damian C. Clarke
*! Department of Economics
*! The University of Oxford
*! damian.clarke@economics.ox.ac.uk

cap program drop arrowplot
program arrowplot, eclass
	vers 10.0

	#delimit ;
	syntax varlist(min=2 max=2) [if] [in] [pweight fweight aweight iweight]
	, GROUPvar(varname)
	[
	  LINEsize(numlist min=0 max=1)
	  groupname(string)
	  CONTrols(varlist fv ts)
	  *
	  regopts(string asis)
	  GENerate(name min=1 max=1)
	]
	;
	#delimit cr
	*=============================================================================
	*=== (0) Error capture
	*=============================================================================
	qui ds `groupvar', not(type string)
	if "`r(varlist)'"=="`groupvar'" {
		local er2 "Please regenerate group names as string prior to running"
		dis as error "Group variable must be a string variable.  `er2'."
		exit 107
	}

	*=============================================================================
	*=== (1) set-up temporary variables for line plots and beta estimates
	*=============================================================================
	tempvar intercept x1 x2 y1 y2 delta line
	tempvar my mx miny maxy minx maxx rany ranx scale reX
	qui gen `intercept'=.

	tokenize `varlist'

	if "`groupname'"=="" local groupname "Group"
	*=============================================================================
	*=== (2) Rescale X so size of line will be equal regardless of slope
	*=============================================================================
	qui {
		bys `groupvar': egen `my'=mean(`1')
		bys `groupvar': egen `mx'=mean(`2')
		foreach var in x y {
			egen `min`var''=min(`m`var'')
			egen `max`var''=max(`m`var'')
			gen `ran`var''=`min`var''-`max`var''
		}

		gen `scale'=`rany'/`ranx'
		gen `reX'  = `2'*`scale'
		}

	*=============================================================================
	*=== (3) Calculate intra-correlation (conditional upon any controls)
	*=============================================================================
	qui levelsof `groupvar', local(levels)
	foreach c of local levels {
		if "`if'"=="" local ifplus if `groupvar'==`"`c'"'
		else local ifplus `if'&`groupvar'==`"`c'"'

		cap reg `1' `reX' `controls' `ifplus' `in' [`weight' `exp'], `regopts'
		if _rc==0 qui replace `intercept'=_b[`reX'] `ifplus'
	}
	if "`generate'"!="" gen `generate'=`intercept'
	preserve
	collapse `1' `2' `reX' `scale' `intercept' `if' `in' [`weight' `exp'], by(`groupvar')

	qui sum `1'
	local scaledif = `r(max)'-`r(min)'
	if "`linesize'"=="" local linesize = 0.08*`scaledif'
	*=============================================================================
	*=== (4) Determine start and end point of lines (depends on slope and length)
	*=============================================================================
	gen  `delta'  = sqrt((`linesize'^2)/(`intercept'^2+1))
	gen  `x1'     = `reX'-`delta'
	gen  `x2'     = `reX'+`delta'
	gen  `y1'     = `1'-`delta'*`intercept'
	gen  `y2'     = `1'+`delta'*`intercept'

	gen `line'  = (`y2'-`y1')^2+(`x2'-`x1')^2

	qui replace `x1'=`x1'/`scale'
	qui replace `x2'=`x2'/`scale'
	*=============================================================================
	*=== (5) Plot
	*=============================================================================
	twoway pcarrow `y1' `x1' `y2' `x2' || scatter `1' `2', ///
	  mlabel(`groupvar') mlabsize(vsmall)  `options' ///
	  legend(label(1 "Within `groupname' Variation") label(2 "`groupname' Mean"))

	restore
	if "`generate'"!="" replace `generate'=`generate'*`scale'
end