prog define rankplot, rclass
*!	Version 1.4 17Jul2023 by Mead Over, based on Cox (2009) SJ 9:4, pp. 621-39.

syntax varlist (numeric min=2 max=2) [if] [in], id(varname)   ///
	[BIGchange(integer 4) List Round(real .01)  ///
	LEFTAlias(string) LEFTOpts(string) RIGHTAlias(string) RIGHTOpts(string)  ///
	noLEFTValues noRIGHTValues nonote noktau  ///
	shift(real 0) MARGadjust(real 0) add(real 0)   ///
	KEEPDups KEEPVars(varlist) textsize(string)  ///
	grcolor(string) style(string) mlabcolor(string) lcolor(passthru)  *]

version 12

tempvar initial final idtag
	tokenize `varlist'
	qui clonevar `initial' = `1'
		char `initial'[varname] `1'
	qui clonevar `final' = `2'
		char `final'[varname] `2'

capt egen `idtag' = tag(`id') `if' `in'  //  -if- and -in- added in version 1.4

marksample touse, strok
markout `touse' `idtag' `keepvars'

if "`grcolor'" ~=""  {
	local grcolor graphregion(color(`grcolor'))
}

if "`style'"==""  {
	local mlabstyle mlabstyle(p1)
	local pstyle pstyle(p1)
}
else {
	local mlabstyle mlabstyle(`style')
	local pstyle pstyle(`style')
}

if "`textsize'"==""  {
	local mlabsize mlabsize(vsmall)
}
else {
	local mlabsize mlabsize(`textsize')
}

if "`mlabcolor'"~=""  {
	local mlabcolor mlabcolor(`mlabcolor')
}

preserve

	qui keep if `touse' & `idtag'
	keep `id' `initial' `final'  `keepvars'

	if "`keepdups'"=="" {
		qui duplicates drop
	}

	local nobs _N

	tempvar initrnd finrnd rank1  rank2 one two left right newcntry

	gsort -`initial'
	gen `rank1' = _n
		char `rank1'[varname] rank1
	gen `initrnd' = round((`initial' + `add'), `round')
		char `initrnd'[varname] Rounded

	gsort -`final'
	gen `rank2' = _n
		char `rank2'[varname] rank2
	gen `finrnd' = round((`final' + `add'), `round')
		char `finrnd'[varname] Rounded

	gen float `one' = 1 + `shift'
		local oneplusshift = 1 + `shift'
	gen float `two' = 2 + `shift'
		local twoplusshift = 2 + `shift'
	gen `left' = 0.5 + `margadjust' + `shift'
	if "`rightvalues'"=="" {
		gen `right' = 2.1 + `shift'
	}
	else {
		gen `right' = 2 + `shift'

	}

	cap confirm string variable `id'
	if _rc==0 {
		qui gen str `newcntry' = `id' if abs(`rank2' - `rank1') > `bigchange'
		qui count if `newcntry' ~= ""
	}
	else {
	    local vallbl : value label `id'
		if "`vallbl'"~="" {
		    decode `id' , gen(`newcntry')
			qui replace `newcntry' =  ""  if abs(`rank2' - `rank1') <= `bigchange'
			qui count if `newcntry' ~= ""
		}
		else {
			qui gen long `newcntry' = `id' if abs(`rank2' - `rank1') > `bigchange'
			qui count if `newcntry' < .
		}
	}
	local nchgrank = `r(N)'

	//  Compute Kendall's Tau_a statistic and its p-value
	if "`ktau'"~="noktau" {       /*  , stats(taua obs p)   */
		di _n as txt "Executing Stata's {help ktau:ktau} command:" ///
			_n(2) as inp "ktau `varlist' "
		ktau `initial' `final'  /* , stats(taua obs p)  */
			local ktau_a : di %6.3f `r(tau_a)'
			local ktau_obs `r(N)'
			local ktau_p : di %6.4f `r(p)'
		if "`note'" ~= "nonote" {
			local note_tau  "Kendall's -tau_a- rank correlation: `ktau_a' on `r(N)' observations. p-value: `ktau_p'"
			local notebene note("          `note_tau'", size(small))
		}
		return add   //  Return results of Stata's -ktau- command
	}

	//  Number of units changing rank
	if `nchgrank' > 0 & "`note'"~="nonote"  {
	    local notetxt  "The right margin flags the `nchgrank' unit(s) for which rank changes more that `bigchange' positions."
	    local notebene note("          `notetxt'"  "          `note_tau'", size(small))
		di _n as txt "`notetxt'"
	}
	char `newcntry'[varname] Rank_Chg

	if "`leftalias'"=="" {
	    local leftalias `1'
	}
	else {
	    char `initial'[varname] "`leftalias'"
	}

	if "`rightalias'"=="" {
	    local rightalias `2'
	}
	else {
	    char `final'[varname] "`rightalias'"
	}

	if "`list'"~=""  {
		gsort -`initial'
		list `id' `rank1' `initial' `initrnd' `rank2' `final' `finrnd' `newcntry' `keepvars', subvarname constant
		local maxrows = min(_N,100)
		tempname listmatrix
		mkmat `rank1' `initial' `initrnd' `rank2' `final' `finrnd' `keepvars' in 1/`maxrows', matrix(`listmatrix')  rownames(`id')
		matrix colnames `listmatrix' = rank1 initial initrnd rank2 final finrnd `keepvars'
		return matrix list = `listmatrix'
	}

	if "`leftvalues'"~="noleftvalues" {
	    local putleftvalues  (scatter `rank1' `one',   mla(`initrnd')  `mlabsize' mlabpos(9) ms(none) `mlabstyle' `mlabcolor')
	}

	if "`rightvalues'"~="norightvalues" {
	    local putrightvalues  (scatter `rank2' `two',   mla(`finrnd')   `mlabsize' mlabpos(3) ms(none) `mlabstyle'  `mlabcolor' )
	}

	twoway  ///
		(pcspike `rank1' `one' `rank2' `two',  ///
			xla(none) xsc(noline r(0.3 2.3)) xtitle("")  ///
			ysc(r(-1 .) reverse off) yla(, nogrid) `pstyle' `lcolor' )  ///
		`putleftvalues'  `putrightvalues'  ///  Values on left and right y-axes
		(scatter `rank1' `left',  mla(`id')      `mlabsize' mlabpos(3) ms(none) `mlabstyle'  `mlabcolor' )    ///  Unit IDs on left
		(scatter `rank2' `right', mla(`newcntry') `mlabsize' mlabpos(3) ms(none) `mlabstyle' `mlabcolor' ) ,  ///  Names of units changing rank by more than -bigchange-
			text(-0.5 `oneplusshift' "`leftalias'", `leftopts') text(-0.5 `twoplusshift' "`rightalias'", `rightopts')  graphregion(lcolor(none)) plotregion(lcolor(none))  ///
			legend(off) `grcolor' `notebene' `options'


restore

return scalar nchgrank = `nchgrank'
return scalar bigchange = `bigchange'
return scalar N = `nobs'

end  /* End of program -rankplot- */
*	Version 1.0 17Jun2020 based on Cox (2009) sjart_gr0041.pdf
*	Version 1.1 20Jun2020 Add the production and display of Kendall's -tau_a-
*		Add optioons -grcolor- and -mlabstyle- to make the program scheme independent.
*	Version 1.2 27Jun2020 Return the matrix from the -list- option.
*		Add the -plotregion(lcolor(none))- and -graphregion(lcolor(none))- options
*		to line 211 as overall options. User specified values will override them.
*		Add the common option -style- and the specific options -mlabstyle- and mlabcolor-.
*	Version 1.3 3Jul2020 Display Tau without a change in rank > -bigchange- (line 117)
*	Version 1.4 17Jul2023 Add -if- and -in- to the -egen ... = tag()- command