cap program drop midas_pubbias
program define midas_pubbias, rclass byable(recall) sortpreserve
version 13
 #delimit;
 syntax [if] [in]
 [, Level(cilevel)
 WGT
 NOWgt
 REGline
 SUMline
 POINTopts(string asis)
 REGopts(string asis) *];
#delimit cr

capture assert e(package) == "midas"
if _rc !=0 {
di as error "Last estimation command was not a midas subcommand such as mle, smle, mh or inla or hmc"
error 301
}
qui {
preserve
clear
estimates store modpost
}
qui {
mat varrslist = e(varlist)
qui svmat varrslist, names(col)

/* Check syntax */

qui count if  ( (tp==0 & fn==0) | ( tn==0 & fp==0) )
if r(N) > 0 {
di as error "One or more studies have both tp and fn==0 or both tn and fp==0"
di as error  "replace both fp and tn as missing or botn fn and tp as missing which ever is applicable and rerun program."
exit 459
}

if ~missing("`wgt'") & ~missing("`nowgt'") {
opts_exclusive "`wgt' `nowgt'"
}

if `level' < 10 | `level' > 99 {
di as error "level() must be between 10 and 99"
	exit 198
}
* Log-scale axis labels (replaces mylabels dependency)
local ylab `"0 "1"  `=ln(10)' "10"  `=ln(100)' "100"  `=ln(1000)' "1000""'

/* initialise legend counter */
local li 1
local ptitle: di "Deeks' Funnel Plot Asymmetry Test"
tempvar  thetai sethetai xb yb stpred pubwgt dor ldor
tempvar n1 n2 nt ESS xxline pid
tempname stbias b4pubbias sumdor
gen `pid'=_n
gen `n1' = tn + fp
gen `n2' = tp + fn
gen `ESS' =(4 * `n1' * `n2')/(`n1' + `n2')

gen `dor' = (tp*tn)/(fp*fn)
gen `ldor' = ln(`dor')
gen `thetai'=`ldor'
gen `sethetai' = sqrt(`ESS')
gen `xb'=1/sqrt(`ESS')
label var `xb' "1/root(ESS)"
gen `yb' = `thetai'
label var `yb' "Diagnostic Odds Ratio"
gen `pubwgt' = `ESS'
if ~missing("`sumline'") {
mat bbias=e(bsum)
mat Vbias=e(Vsum)
_coef_table, bmatrix(bbias) vmatrix(Vbias)
mat biasmat=r(table)'
local sumdor =biasmat[3,1]
local sumline `"xline(`sumdor', lpatt(solid) lcolor(red))"'
}

if ~missing("`wgt'")  {
local _pdef "mlw(medthin) mlc(black) mfc(gs15) msize(*.5) ms(O)"
local _popts = cond(!missing("`pointopts'"), "`pointopts'", "`_pdef'")
local studypoints `"(scatter `xb' `yb' [aw=`pubwgt'*.10], sort `_popts')"'
local studypoints `"`studypoints' (scatter `xb' `yb', ms(i) mlabp(0) mlabel(`pid') mlabs(*.5) mlabc(black))"'
local legend `"`legend' label(`li' "Study")"'
local order "`order' `li++'"
local ++li
}
else if ~missing("`nowgt'") {
local _pdef2 "mlw(medthin) mlc(black) mfc(gs15) msize(*1.5) ms(O)"
local _popts2 = cond(!missing("`pointopts'"), "`pointopts'", "`_pdef2'")
local studypoints `"(scatter `xb' `yb', sort `_popts2')"'
local studypoints `"`studypoints' (scatter `xb' `yb', ms(i) mlabp(0) mlabel(`pid') mlabs(*.5) mlabc(black))"'
local legend `"`legend' label(`li' "Study")"'
local order "`order' `li++'"
local ++li
}

* mylabels replaced with hardcoded log-scale labels above
regress  `yb' `xb'[weight=`pubwgt'], level(`level')
estimates store `stbias'
scalar intercept = _b[_cons]
scalar se_intercept = _se[_cons]
scalar rmse = e(rmse)
scalar df = e(df_r)
scalar p = 2*ttail(e(df_r), abs(return(score_bc)/return(score_se)))
nois matrix define vcov = e(V)
nois matrix define b = e(b)
matrix colnames b =     Bias Intercept
matrix rownames vcov =  Bias Intercept
matrix colnames vcov =  Bias Intercept
nois matrix post b vcov, dep(yb) dof(`e(df_r)') obs(`e(N)')
local pbias=2*ttail(e(df_r), abs(_b[Bias]/_se[Bias]))
local note: di "pvalue  = "%6.2f `pbias'
nois di " "
nois di " "
nois ereturn display, level(`level')
estimates restore `stbias'

if ~missing("`regline'") {
predict `stpred'
local _ropts = cond(!missing("`regopts'"), "`regopts'", "clpattern(solid) clwidth(vthin)")
local stline "(line `xb' `stpred' , `_ropts' )"
local legend `"`legend' label(`li' "Regression" "Line")"'
local order "`order' `li++'"
local ++li
}
#delimit;
nois twoway `studypoints' `stline', xlab(`ylab', angle(horizontal) labsize(*.75) format(%7.2f))
legend(order(`order') pos(6) row(1) size(*.50)  `legend')
ylab(, labsize(*.75) angle(horizontal)) `title' aspectratio(1)
/*plotregion(margin(zero))*/ xtitle("Diagnostic Odds Ratio")  `sumline'
subtitle("`ptitle'" "`note'", size(*.65)) yscale(rev) `scheme' `saving' `options';
#delimit cr
estimates drop  `stbias'
restore
estimates restore modpost
}

* Return bias regression results
return scalar bias_coef = b[1,1]
return scalar intercept = b[1,2]
return scalar bias_se   = sqrt(vcov[1,1])
return scalar bias_pval = `pbias'

end