/*

This will produce a stacked percentage distribution (y-axis) for a labeled numeric categorical variable as a function of a continuous numeric variable (x-axis).

stackedpercent varlist [if] [in] [,options]

where varlist is

y x

y is a categorical numeric variable. There must be at least two distinct values. If y takes on only one value, you should just use twoway area.
x is a continuous numeric variable (for example, year)

If the categorical variable you want to plot is string, run encode beforehand to create a labeled numeric categorical variable

Most of the important options for twoway are available via pass-through:

xlabel, xtick, xmtick, xtitle, xrange
ylabel, ytick, ymtick, ytitle, yscale
caption, scheme, note, legend

Others are easy to add by following the model in the code.

If I have time, I'll add a few lines to allow specification of a string variable for the y, and then encode it internally.

Cameron Campbell camcam@ust.hk
April 2020

*/

program define stackedpercent
quietly {
#delimit ;
syntax varlist (min=2 max=2) [if] [in], [xlabel(string)] [yscale(string)] [ylabel(string)]
	[ytitle(string)] [caption(string)] [title(string)] [subtitle(string)]
	[xtick(string)] [ytick(string)] [xmtick(string)] [ymtick(string)]
	[xtitle(string)] [scheme(string)] [note(string)] [legend(string)] [xrange(numlist)] [debug];
#delimit cr
tokenize `varlist'
tempvar percent t_percent
preserve
if "`if'" != "" {
	keep `if'
}
if "`in'" != "" {
	keep `in'
}
if "`yscale'" == "" {
    local yscale = "range(0 100)"
}

local labels : value label `1'
levelsof `1', local(value_list)
foreach i of local value_list {
      	 local value`i' : label `labels' `i'
		 display "`value`i''"
}

version 16: table `2' `1', replace
if("`debug'" != "") {
	noisily list
}
fillin `2' `1'
drop _fillin
replace table1 = 0 if table1 == .
bysort `2': egen `percent' = pc(table1)
bysort `2' (`1'): generate `t_percent' = sum(`percent')
keep `2' `1' `t_percent'
reshape wide `t_percent', i(`2') j(`1')
if("`debug'" != "") {
	noisily list
}
foreach i of local value_list {
	if("`debug'" != "") {
		noisily display "`t_percent'`i'" "`value`i''"
	}
	label variable `t_percent'`i' "`value`i''"
}
local i = 1
foreach l of varlist `t_percent'* {
	if `i' == 1 {
		local line_command "area `l' `2', cmissing(n)"
		local legend_order "`i'"
		}
	else {
		local line_command "area `l' `2', cmissing(n) || `line_command'"
		local legend_order "`i' `legend_order'"
		}
	local i = `i'+1
}
if("`debug'" != "") {
	noisily display "`line_command'"
	noisily display "`legend_order'"
}


tempvar range_match
generate `range_match' = 0
if ("`xrange'" != "") {
	foreach i of numlist `xrange' {
		replace `range_match' = `2' == `i'
		sort `range_match'
		if !`range_match'[_N] {
			insobs 1
			replace `2' = `i' in l
		}
	}
}

if "`xlabel'" != "" {
	local xlabel "xlabel(`xlabel')"
}

if "`ylabel'" != "" {
	local ylabel "ylabel(`ylabel')"
}

if "`yscale'" != "" {
	local yscale "yscale(`yscale')"
}

if "`xtitle'" != "" {
	local xtitle "xtitle(`xtitle')"
}

if "`scheme'" != "" {
	local scheme "scheme(`scheme')"
}

if "`note'" != "" {
	local note "note(`note')"
}

if "`ytitle'" != "" {
	local ytitle "ytitle(`ytitle')"
}

if "`ytick'" != "" {
	local ytick "ytick(`ytick')"
}

if "`xtick'" != "" {
	local xtick "xtick(`xtick')"
}

if "`xmtick'" != "" {
	local xmtick "xmtick(`xmtick')"
}

if "`ymtick'" != "" {
	local ymtick "ymtick(`ymtick')"
}

if "`title'" != "" {
	local title "title(`title')"
}

if "`subtitle'" != "" {
	local subtitle "subtitle(`subtitle')"
}

if "`caption'" != "" {
	local caption "caption(`caption')"
}

tempfile beginning
tempvar new_order

generate `new_order' = 2

save "`beginning'"

sort `2'
replace `2' = `2'[_n+1] if _n < _N
replace `2' = `2'[_N-1]+(`2'[_N-1]-`2'[_N-2]) if _n == _N

replace `new_order' = 1

append using "`beginning'"

sort `2' `new_order'

*set trace on
if("`debug'" != "") {
	noisily list
}

twoway `line_command' `xlabel' `ylabel' legend(order(`legend_order') `legend') `xtitle' `scheme' `note' ///
	`ytitle' `xtick' `ytick' `ymtick' `caption' `xmtick' `ymtick' `yscale' `title' `subtitle' graphregion(fcolor(white))
*set trace off

restore
}
*set trace off
end