*! v1.32  4/26/2022 by FRA: Fixes IF
* v1.31  4/26/2022 by FRA: Transparency fix
* v1.3  4/24/2022 by FRA: Adds FIT option.
* v1.2  4/21/2022 by FRA: Works with Stata < 16
* v1.1  4/11/2022 by FRA
** Scatter with across multiple groups

mata:
	void gquery(string scalar scm, anything){
		string matrix any, sch, ssch
		ssch=cat(scm)
		any=stritrim(strtrim(tokens(anything)))
		real scalar i, fnd, nr
		nr=rows(ssch)
		fnd=1
		i=1
		while(fnd==1){
			i++
			sch=stritrim(tokens(ssch[i,]))
			if (cols(sch)==3) {
				if (sch[1]==any[1] & sch[2]==any[2]) {
					fnd=0
					st_local("toreturn",sch[3])
				}
			}
			if (i==nr) {
				fnd=0
			}
		}
	}
end

program graphquery, rclass
	syntax anything, [DEFAULT DEFAULT1(str asis) ]
	qui:findfile "scheme-`c(scheme)'.scheme"
	mata:gquery("`r(fn)'","`anything'")
	if `"`toreturn'"'=="" & "`default'`default1'"!="" local toreturn `default'`default1'
	display "`anything':" `"`toreturn'"'

	return local query   `toreturn'
end

program byparse, rclass
	syntax [anything], [*]
	if "`anything'"!=""	return local byvlist `anything'
	return local byopt   `options'
end

program easter_egg
display in w "{p}This is a small easter egg! And you are lucky because only 0.1% of people may ever see this!{p_end}"
display in w "{p}I should have come up with this at some point. And hopefully Stata will use this too (officially) {p_end}"
display in w "{p}Granted, using color in papers is tough (most prints are black and white). However, if you are into visualizations, color palettes are your friends {p_end}"
display in w "{p}All right, that is it! {p_end}"
end

program colorpalette_parser, rclass
	syntax [anything(everything)], [nograph * n(string asis) opacity(passthru)]
	return local clp   = `"`anything', `options'"'
	return local clpop = `"`anything', `options' `opacity'"'
end

program mscatter
	* If nothing is done, all goes to 0
	*syntax anything(everything), [  * ]
	if runiform()<0.001 {
		easter_egg
	}

	if runiform()<0.001 {
		if `c(stata_version)'>=16 {
			easter_egg2
		}
	}
	mscatterx `0'
end

program easter_egg2
	tempname mario
	frame create `mario'
	frame `mario':use https://friosavila.github.io/playingwithstata/rnd_dta/mario, clear
	frame `mario':mscatterx y x, over(cc10)  color(mc10) msize(1.3) msymbol(S) aspect(1)  title("Let me take care of it")
	if _rc==0 sleep 2000

end

program mscatterx
 	syntax varlist(max=2)   [if] [in] [aw/], [over(varname)] ///
				[ alegend legend(string asis) color(string asis) ///
				  fit(str asis)	 ///
				  colorpalette(string asis) by(string asis)  * ]
	** First Parse
	tempvar touse
	qui:gen byte `touse'=0
	qui:replace `touse'=1 `if' `in'
	** over?
	if "`over'"=="" {
		tempvar over
		qui:gen byte `over'=1
	}
	tempname new
	** Check color
	capture confirm var `color'
	if _rc==0 	local myvlist `color'
	** check by
	byparse `by'
	***
	local byvlist `r(byvlist)'
	local byopts  `r(byopt)'
	*display "`myvlist' `varlist' `byvlist' `over' `exp'"

	** Check weights in fit
	fit_parser `fit'
	local fitwgt `r(fitwgt)'

	** markout only works with numeric
	markout `touse' `varlist' `byvlist' `over' `exp', strok

	local myvlist `myvlist' `varlist' `byvlist' `over' `exp' `fitwgt'

	** Put into Frame
	if `c(stata_version)'>=16 {
		frame put `myvlist' if `touse', into(`new')
		syntax anything [aw] [if] [in], [*]
		frame `new':mscatter_do `anything' [`weight'`exp'], `options'
	}
	else {
		preserve
			qui:keep if `touse'
			keep `myvlist'
			syntax anything [aw] [if] [in], [*]
			mscatter_do `anything' [`weight'`exp'], `options'
		restore
	}


end


program fit_parser, rclass
	syntax [anything] [aw fw pw iw ], [* fcolor(passthru) lcolor(passthru)]
	if "`anything'"=="" exit

	if inlist("`anything'","lfitci","qfitci","fpfitci","lpolyci") {
		return local fitval =2
	}
	else if inlist("`anything'","lfit","qfit","fpfit","lpoly") {
		return local fitval =1
	}
	else {
		display in red "Not a valid {cmd:fit} option. One can only use lfit qfit fpfit or lpoly (with CI options)"
		error 99
	}

	if `"`fcolor'"'=="" & `c(stata_version)'<=14 local fcolor fcolor(*.50)
	if `"`fcolor'"'=="" & `c(stata_version)'>14  local fcolor fcolor(%50)

	if `"`lcolor'"'=="" local lcolor lcolor(*1.1)

	local wgt=subinstr("`exp'","=","",1)
	return local  fitcmd  `anything'
	return local  fitopt  `options' `fcolor' `lcolor'
	return local  fitwgt  `wgt'
	return local  fitewgt [`weight'`exp']

end


**!! Consider adding a sample option.

program mscatter_do
 	syntax varlist(max=2)   [if] [in] [aw/], [over(varname)] [ alegend legend(string asis) color(string asis) colorpalette(string asis) by(str asis) ///
										msymbol(passthru) msize(passthru) fit(str asis) noscatter ///
										msangle(passthru) mfcolor(passthru) mlcolor(passthru) strict ///
										mlwidth(passthru) mlalign(passthru) jitter(passthru) jitterseed(passthru) * ]
	** First Parse
	tempvar touse
	qui:gen byte `touse'=0
	qui:replace `touse'=1 `if' `in'
	** over?
	if "`over'"=="" {
		tempvar over
		qui:gen byte `over'=1
	}
	tempname new
	** Check color
	capture confirm var `color'
	if _rc==0 	local myvlist `color'
	** check by
	byparse `by'
	***
	local byvlist `r(byvlist)'
	local byopts  `r(byopt)'
	*display "`myvlist' `varlist' `byvlist' `over' `exp'"

	** markout only works with numeric


	local myvlist `myvlist' `varlist' `byvlist' `over' `exp'

	** Put into Frame
 	qui {
		** check fit options
		fit_parser `fit'
		local fitcmd `r(fitcmd)'
		local fitopt `r(fitopt)'
		local fitval `r(fitval)'
		local fitwgt `r(fitewgt)'
		**Check Weight
		capture confirm numeric var `over'
			if _rc!=0 {
				tempvar nover
				encode `over', gen(`nover')
				local over `nover'
			}

		if "`exp'"!="" local wexp [aw=`exp']

		if "`scatter'"!="" {
			tempvar fuse
			qui: gen byte `fuse'=.
			local tofuse & `fuse'!=.
		}
		** Check over to be numeric.
		** sort so 1 per over

 		tempvar flag
		bysort `over':gen __flag=_n

		sort __flag `over'
		qui:levelsof `over' , local(lvlby)

		** Which color options:
		if `"`color'"'!="" {
			capture confirm var `color'
			if _rc==0 local col_op = 1   // <--- provides colors by variable
			else      local col_op = 2   // <--- provides colors by color list
		}
		else {
			if "`colorpalette'"!="" local col_op = 3   // <-- Uses Color palette
			else                    local col_op = 4   // <-- Uses default "system" colors
		}

		if `col_op'==3 {
			local cnt: word count `lvlby'
			colorpalette_parser `colorpalette'
			colorpalette `r(clpop)' nograph n(`cnt')
			local cpcolor  `"`r(p)'"'
		}

		local cnt=0
		local cnx=0
		foreach i of local lvlby {
			local cnt = `cnt' +1
			local cnx = `cnx'+1
			if `col_op'==1 {
				local mycolor `=`color'[`cnt']'
			}
			if `col_op'==2 {
				local wrd:word count `color'
				if `cnt'<=`wrd'	local mycolor:word `cnt' of `color'
				else  		    local mycolor:word `wrd' of `color'
			}
			if `col_op'==3 local mycolor:word `cnt' of `cpcolor'
			if `col_op'==4 {
				if `cnx'>15	 local cnx 1
				qui:graphquery color p`cnx'
				local mycolor `r(query)'
			}
			if "`fit'"!="" local fitplot (`fitcmd' `varlist' if `over'==`i' `fitwgt', `fitopt' color("`mycolor'") )
			local pscatter `pscatter' ///
					(scatter `varlist' if `over'==`i'  `tofuse', ///
					color( "`mycolor'" ) ///
					`msymbol' `msize' `msangle' `mfcolor' `mlcolor' ///
					`mlwidth' `mlalign' `jitter' `jitterseed') `fitplot'
		}


		 ** Then just Scatter, but...One more component, legend. Default Legend off
		 if "`alegend'"=="" & `"`legend'"' == ""   local mylegend legend(off)
		 if "`alegend'"=="" & `"`legend'"' != ""   local mylegend legend(`legend')
		 if "`alegend'"!="" {
		 	local cn =0

		 	foreach i of local lvlby {
					local cn = `cn'+1+0`fitval'
					local slg: label (`over') `i', `strict'
					local mylegend `mylegend' `cn' "`slg'"

				}
			local mylegend legend(order(`mylegend') `legend')
		 }
		** the figure

		two `pscatter', `options' by(`by') `mylegend'
	}
end