You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4455 lines
125 KiB
Plaintext
4455 lines
125 KiB
Plaintext
*! 3.02 13Nov2008
|
|
* 13 Nov 2008- fixed counts option, was using str20 and truncating in `rawdata'
|
|
* decimal place option dp()
|
|
* Based on 2.34 11May2007
|
|
* Based on previous version: 1.86 1Apr2004
|
|
*
|
|
|
|
/*Revision list at end
|
|
|
|
Syntax:
|
|
a) binary data:
|
|
metan #events_group1 #nonevents_group1 #events_group2 #nonevents_group2 , ...
|
|
b) cts data:
|
|
metan #group1 mean1 sd1 #group2 mean2 sd2 , ...
|
|
c) generic effect size+st error:
|
|
metan theta se_theta , ...
|
|
d) generic effect size+ci:
|
|
metan theta lowerlimit upperlimit , ...
|
|
|
|
*/
|
|
|
|
program define metan, rclass
|
|
|
|
version 9.0
|
|
#delimit ;
|
|
syntax varlist(min=2 max=6 default=none numeric) [if] [in] [, BY(string)
|
|
ILevel(integer $S_level) OLevel(integer $S_level) CC(string)
|
|
OR RR RD FIXED FIXEDI RANDOM RANDOMI PETO COHEN HEDGES GLASS noSTANDARD
|
|
CHI2 CORNFIELD LOG BRESLOW EFORM noINTeger noOVERALL noSUBGROUP SGWEIGHT
|
|
SORTBY(passthru) noKEEP noGRAPH noTABLE LABEL(string) noBOX
|
|
XLAbel(passthru) XTick(passthru) FORCE BOXSCA(real 100.0) BOXSHA(integer 4)
|
|
TEXTSize(real 100.0) noWT noSTATS COUNTS WGT(varlist numeric max=1)
|
|
GROUP1(string) GROUP2(string) EFFECT(string)
|
|
/* new additions */
|
|
LCOLS(varlist) RCOLS(varlist) ASTEXT(integer 50) DOUBLE NOHET NULL(real 999) RFDIST SUMMARYONLY
|
|
SECOND(string) NOSECSUB SECONDSTATS(string) FAVOURS(string) FIRST(string) FIRSTSTATS(string)
|
|
BOXOPT(string) DIAMOPT(string) POINTOPT(string) CIOPT(string) OLINEOPT(string)
|
|
CLASSIC NOWARNING NULLOFF EFFICACY RFLevel(integer $S_level) DP(integer 2)
|
|
* ];
|
|
|
|
#delimit cr
|
|
|
|
|
|
global MA_OTHEROPTS `"`options'"'
|
|
global MA_BOXOPT `"`boxopt'"'
|
|
global MA_DIAMOPT `"`diamopt'"'
|
|
global MA_POINTOPT `"`pointopt'"'
|
|
global MA_CIOPT `"`ciopt'"'
|
|
global MA_OLINEOPT `"`olineopt'"'
|
|
|
|
global MA_DOUBLE "`double'"
|
|
global MA_FAVOURS "`favours'"
|
|
global MA_secondstats "`secondstats'"
|
|
global MA_firststats "`firststats'"
|
|
global MA_nohet "`nohet'"
|
|
global MA_rfdist "`rfdist'"
|
|
global MA_summaryonly "`summaryonly'"
|
|
global MA_classic "`classic'"
|
|
global MA_nowarning "`nowarning'"
|
|
global MA_nulloff "`nulloff'"
|
|
global MA_efficacy "`efficacy'"
|
|
global MA_dp = "`dp'"
|
|
|
|
if `null' != 999{
|
|
global MA_NULL = "`null'"
|
|
}
|
|
else{
|
|
global MA_NULL = ""
|
|
}
|
|
|
|
global MA_FBSC `boxsca'
|
|
global MA_ESLA "`effect'"
|
|
global MA_params = 0 // set as appropriate in variable set-up
|
|
|
|
if "`legend'"!="" {
|
|
global S_TX "`legend'"
|
|
}
|
|
else {
|
|
global S_TX "Study"
|
|
}
|
|
|
|
global MA_AS_TEXT `astext' // new option- percentage of graph as text
|
|
global MA_TEXT_SCA `textsize' // oops, that was in already
|
|
|
|
if `astext' > 90 | `astext' < 10 {
|
|
di as error "Percentage of graph as text (ASTEXT) must be within 10-90%"
|
|
di as error "Must have some space for text and graph"
|
|
exit
|
|
}
|
|
if `textsize' < 20 | `textsize' > 500 {
|
|
di as error "Text scale (TEXTSize) must be within 20-500"
|
|
di as error "Value is character size relative to graph"
|
|
di as error "Outside range will either be unreadable or too large"
|
|
exit
|
|
}
|
|
|
|
*label groups
|
|
if "`group1'"=="" {
|
|
global MA_G1L "Treatment"
|
|
}
|
|
else {
|
|
global MA_G1L "`group1'"
|
|
}
|
|
if "`group2'"=="" {
|
|
global MA_G2L "Control"
|
|
}
|
|
else {
|
|
global MA_G2L "`group2'"
|
|
}
|
|
if "`legend'"!="" {
|
|
global S_TX "`legend'"
|
|
}
|
|
|
|
global MA_FTSI `textsize'
|
|
if ("`by'"=="" & "`overall'"!="") {
|
|
local wt "nowt"
|
|
}
|
|
if `ilevel'<1 {
|
|
local ilevel `ilevel'*100
|
|
}
|
|
if `ilevel'>99 | `ilevel'<10 {
|
|
local ilevel $S_level
|
|
}
|
|
|
|
global ZIND -invnorm((100-`ilevel')/200)
|
|
|
|
if `olevel'<1 {
|
|
local olevel `olevel'*100
|
|
}
|
|
if `olevel'>99 | `olevel'<10 {
|
|
local olevel $S_level
|
|
}
|
|
|
|
global ZOVE -invnorm((100-`olevel')/200)
|
|
global IND `ilevel'
|
|
global OVE `olevel'
|
|
|
|
if `rflevel'<1 {
|
|
local rflevel `rflevel'*100
|
|
}
|
|
if `rflevel'>99 | `olevel'<10 {
|
|
local rflevel $S_level
|
|
}
|
|
global RFL `rflevel'
|
|
|
|
forvalues i = 1/12{
|
|
global S_`i' .
|
|
}
|
|
global MA_rjhby "`by'"
|
|
|
|
*If not using own weights set fixed as default
|
|
|
|
if "`fixed'`random'`fixedi'`randomi'`peto'"=="" & ( "`wgt'"=="" ) {
|
|
local fixed "fixed"
|
|
}
|
|
|
|
*declare study labels for display
|
|
if "`label'"!="" {
|
|
tokenize "`label'", parse("=,")
|
|
while "`1'"!="" {
|
|
cap confirm var `3'
|
|
if _rc!=0 {
|
|
di as err "Variable `3' not defined"
|
|
exit
|
|
}
|
|
local `1' "`3'"
|
|
mac shift 4
|
|
}
|
|
}
|
|
|
|
tempvar code
|
|
|
|
qui {
|
|
*put name/year variables into appropriate macros
|
|
|
|
if "`namevar'"!="" {
|
|
local lbnvl : value label `namevar'
|
|
if "`lbnvl'"!="" {
|
|
quietly decode `namevar', gen(`code')
|
|
}
|
|
else {
|
|
gen str10 `code'=""
|
|
cap confirm string variable `namevar'
|
|
if _rc==0 {
|
|
replace `code'=`namevar'
|
|
}
|
|
else if _rc==7 {
|
|
replace `code'=string(`namevar')
|
|
}
|
|
}
|
|
}
|
|
if "`namevar'"=="" & "`lcols'" != ""{
|
|
local var1 = word("`lcols'",1)
|
|
cap confirm var `var1'
|
|
if _rc!=0 {
|
|
di in re "Variable `var1' not defined"
|
|
exit _rc
|
|
}
|
|
local namevar "`var1'"
|
|
local lbnvl : value label `namevar'
|
|
if "`lbnvl'"!="" {
|
|
quietly decode `namevar', gen(`code')
|
|
}
|
|
else {
|
|
gen str10 `code'=""
|
|
cap confirm string variable `namevar'
|
|
if _rc==0 {
|
|
replace `code'=`namevar'
|
|
}
|
|
else if _rc==7 {
|
|
replace `code'=string(`namevar')
|
|
}
|
|
}
|
|
}
|
|
if "`namevar'"=="" & "`lcols'" == ""{
|
|
gen str3 `code'=string(_n)
|
|
}
|
|
|
|
if "`yearvar'"!="" {
|
|
local yearvar "`yearvar'"
|
|
cap confirm string variable `yearvar'
|
|
if _rc==7 {
|
|
local str "string"
|
|
}
|
|
if "`namevar'"=="" {
|
|
replace `code'=`str'(`yearvar')
|
|
}
|
|
else {
|
|
replace `code'=`code'+" ("+`str'(`yearvar')+")"
|
|
}
|
|
}
|
|
|
|
if "`wgt'"!="" {
|
|
*User defined weights verification
|
|
if "`fixed'`random'`fixedi'`randomi'`peto'"!="" {
|
|
di as err "Option invalid with user-defined weights"
|
|
exit
|
|
}
|
|
confirm numeric variable `wgt'
|
|
local wgt "wgt(`wgt')"
|
|
}
|
|
|
|
} /* End of quietly loop */
|
|
|
|
|
|
tokenize "`varlist'", parse(" ")
|
|
|
|
if "`6'"=="" {
|
|
|
|
if "`4'"=="" {
|
|
|
|
*Input is {theta setheta} or {theta lowerci upperci} => UDW, IV or D+L weighting
|
|
if "`3'"!="" {
|
|
*input is theta lci uci
|
|
cap assert ((`3'>=`1') & (`1'>=`2'))
|
|
if _rc!=0 {
|
|
di in bl "Effect size and confidence intervals invalid:"
|
|
di in bl "order should be {effect size, lower ci limit, upper ci limit}"
|
|
exit _rc
|
|
}
|
|
global MA_params = 3
|
|
}
|
|
else{
|
|
global MA_params = 2
|
|
}
|
|
|
|
cap assert "`log'"==""
|
|
if _rc!=0 {
|
|
di in bl "Log option not available without raw data counts: if necessary, transform both"
|
|
di in bl "effect and standard error using " in wh "generate" in bl " and re-issue the metan command"
|
|
exit _rc
|
|
}
|
|
|
|
cap assert "`chi2'`cornfield'`peto'`breslow'`counts'`or'`rr'`rd'`standard'`hedges'`glass'`cohen'"==""
|
|
if _rc!=0 {
|
|
di as err "Option not available without raw data counts"
|
|
exit _rc
|
|
}
|
|
if "`wgt'"!="" {
|
|
local method "*"
|
|
}
|
|
else {
|
|
if "`random'`randomi'"!="" {
|
|
local randomi
|
|
local random "random"
|
|
local method "D+L"
|
|
}
|
|
if "`fixed'`fixedi'"!="" {
|
|
local fixedi
|
|
local fixed "fixed"
|
|
local method "I-V"
|
|
}
|
|
cap assert ("`random'"=="") + ("`fixed'"=="")==1
|
|
if _rc!=0 {
|
|
di as err "Specify fixed or random effect/s model"
|
|
exit _rc
|
|
}
|
|
}
|
|
|
|
cap assert "`cc'"==""
|
|
if _rc!=0 {
|
|
di as err "Continuity correction not valid with unless individual counts specified"
|
|
exit _rc
|
|
}
|
|
|
|
local callalg "iv_init"
|
|
local sumstat "ES"
|
|
|
|
} /*end of 2&3-variable set-up */
|
|
|
|
if "`4'"!="" {
|
|
*Input is 2x2 tables: MH, Peto, IV, D+L or user defined weighting allowed
|
|
cap assert "`5'"==""
|
|
if _rc!=0 {
|
|
di as err "Wrong number of variables specified"
|
|
exit _rc
|
|
}
|
|
if "`integer'"=="" {
|
|
cap {
|
|
assert int(`1')==`1'
|
|
assert int(`2')==`2'
|
|
assert int(`3')==`3'
|
|
assert int(`4')==`4'
|
|
}
|
|
if _rc!=0 {
|
|
di as err "Non integer cell counts found"
|
|
exit _rc
|
|
}
|
|
|
|
}
|
|
cap assert ( (`1'>=0) & (`2'>=0) & (`3'>=0) & (`4'>=0) )
|
|
if _rc!=0 {
|
|
di as err "Non-positive cell counts found"
|
|
exit _rc
|
|
}
|
|
if "`cc'"!="" {
|
|
*Ensure Continuity correction is valid
|
|
if "`peto'"!="" {
|
|
di as err "Peto method not valid with continuity correction"
|
|
exit
|
|
}
|
|
*Currently, allows user to define own constant [0,1) to add to all cells
|
|
cap confirm number `cc'
|
|
if _rc!=0 {
|
|
di as err "Invalid continuity correction: specify a constant number eg metan ... , cc(0.166667)"
|
|
exit
|
|
}
|
|
cap assert (`cc'>=0) & (`cc'<1)
|
|
if _rc!=0 {
|
|
di as err "Invalid continuity correction: must be in range [0,1)"
|
|
exit
|
|
}
|
|
}
|
|
else {
|
|
local cc "0.5"
|
|
}
|
|
if "`peto'"=="" {
|
|
local cont "cc(`cc')"
|
|
}
|
|
if "`peto'"!="" {
|
|
local or "or"
|
|
}
|
|
capture {
|
|
assert ( ("`or'"!="")+("`rr'"!="")+("`rd'"!="") <=1 )
|
|
assert ("`fixed'"!="")+("`fixedi'"!="")+("`random'"!="")+ /*
|
|
*/ ("`randomi'"!="")+("`peto'"!="")+("`wgt'"!="") <=1
|
|
assert "`standard'`hedges'`glass'`cohen'"==""
|
|
}
|
|
if _rc!=0 {
|
|
di as err "Invalid specifications for combining trials"
|
|
exit
|
|
}
|
|
*Default is set at pooling RRs.
|
|
if "`or'"!="" {
|
|
local sumstat "OR"
|
|
}
|
|
else if "`rd'"!="" {
|
|
local sumstat "RD"
|
|
}
|
|
else {
|
|
local sumstat "RR"
|
|
}
|
|
if "`wgt'"!="" {
|
|
local method "*"
|
|
}
|
|
else if "`random'`randomi'"!="" {
|
|
local method "D+L"
|
|
}
|
|
else if "`peto'"!="" {
|
|
local method "Peto"
|
|
}
|
|
else if "`fixedi'"!="" {
|
|
local method "I-V"
|
|
}
|
|
else {
|
|
local method "M-H"
|
|
}
|
|
if "`peto'"!="" {
|
|
local callalg "Peto"
|
|
}
|
|
else {
|
|
local callalg "`sumstat'"
|
|
}
|
|
if ("`sumstat'"!="OR" | "`method'"=="D+L") & "`chi2'"!="" {
|
|
di as err "Chi-squared option invalid for `method' `sumstat'"
|
|
exit
|
|
}
|
|
if ("`sumstat'"!="OR" | "`method'"=="D+L" | "`method'"=="Peto" ) & "`breslow'"!="" {
|
|
di as err "Breslow-Day heterogeneity option not available for `method' `sumstat'"
|
|
exit
|
|
}
|
|
if ("`sumstat'"!="OR" & "`sumstat'"!="RR") & "`log'"!="" {
|
|
di as err "Log option not appropriate for `sumstat'"
|
|
exit
|
|
}
|
|
if "`keep'"=="" {
|
|
cap drop _SS
|
|
qui gen _SS =`1'+`2'+`3'+`4'
|
|
}
|
|
|
|
global MA_params = 4
|
|
|
|
} /* end of binary variable setup */
|
|
|
|
} /* end of all non-6 variable set up */
|
|
|
|
|
|
if "`6'"!="" {
|
|
|
|
*Input is form N mean SD for continuous data: IV, D+L or user defined weighting allowed
|
|
cap assert "`7'"==""
|
|
if _rc!=0 {
|
|
di as err "Wrong number of variables specified"
|
|
exit _rc
|
|
}
|
|
if "`integer'"=="" {
|
|
cap assert ((int(`1')==`1') & (int(`4')==`4'))
|
|
if _rc!=0 {
|
|
di as err "Non integer sample sizes found"
|
|
exit _rc
|
|
}
|
|
}
|
|
cap assert (`1'>0 & `4'>0)
|
|
if _rc!=0 {
|
|
di as err "Non positive sample sizes found"
|
|
exit _rc
|
|
}
|
|
if "`random'`randomi'"!="" {
|
|
local randomi
|
|
local random "random"
|
|
}
|
|
if "`fixed'`fixedi'"!="" {
|
|
local fixedi
|
|
local fixed "fixed"
|
|
}
|
|
cap{
|
|
assert ("`hedges'"!="")+ ("`glass'"!="")+ ("`cohen'"!="")+ ("`standard'"!="")<=1
|
|
assert ("`random'"!="")+ ("`fixed'"!="") <=1
|
|
assert "`or'`rr'`rd'`peto'`log'`cornfield'`chi2'`breslow'`eform'"==""
|
|
}
|
|
if _rc!=0 {
|
|
di as err "Invalid specifications for combining trials"
|
|
exit
|
|
}
|
|
if "`standard'"!="" {
|
|
local sumstat "WMD"
|
|
local stand "none"
|
|
}
|
|
else {
|
|
if "`hedges'"!="" {
|
|
local stand "hedges"
|
|
}
|
|
else if "`glass'"!="" {
|
|
local stand "glass"
|
|
}
|
|
else {
|
|
local stand "cohen"
|
|
}
|
|
local sumstat "SMD"
|
|
}
|
|
local stand "standard(`stand')"
|
|
if "`wgt'"!="" {
|
|
local method "*"
|
|
}
|
|
else if "`random'"!="" {
|
|
local method "D+L"
|
|
}
|
|
else {
|
|
local method "I-V"
|
|
}
|
|
/* CAN NOW HAVE THIS
|
|
if "`counts'"!="" {
|
|
di in bl "Data option counts not available with continuous data"
|
|
local counts
|
|
}
|
|
*/
|
|
if "`cc'"!="" {
|
|
di as err "Continuity correction not available with continuous data"
|
|
exit
|
|
}
|
|
local callalg "MD"
|
|
if "`keep'"=="" {
|
|
cap drop _SS
|
|
qui gen _SS =`1'+`4'
|
|
}
|
|
global MA_params = 6
|
|
|
|
} /*end of 6-var set-up*/
|
|
|
|
|
|
if "`by'"!="" {
|
|
cap confirm var `by'
|
|
if _rc!=0 {
|
|
di in red "Variable `by' does not exist"
|
|
exit _rc
|
|
}
|
|
local by "by(`by')"
|
|
local nextcall "nextcall(`callalg')"
|
|
local callalg "metanby"
|
|
local sstat "sumstat(`sumstat')"
|
|
}
|
|
|
|
if "$MA_efficacy" != ""{
|
|
cap assert "`sumstat'" == "RR" | "`sumstat'" == "OR"
|
|
if _rc!=0 {
|
|
di in red "Efficacy statistics only possible with odds ratios and risk ratios"
|
|
exit _rc
|
|
}
|
|
}
|
|
|
|
// RJH- code for second effect estimate
|
|
global MA_method1 ""
|
|
global MA_method2 "" // MAKE BLANK OR MAY BE KEPT FROM PREV
|
|
|
|
|
|
// CODE AND CONDITIONS FOR USER DEFINED "FIRST" ANALYSIS
|
|
// FIRST DITCH ANY MACROS WE DON'T WANT
|
|
|
|
foreach globule in MA_userES MA_userCIlow MA_userCIupp MA_userDesc MA_userESM ///
|
|
MA_userCIlowM MA_userCIuppM MA_userDescM MA_ODC {
|
|
global `globule' = .
|
|
}
|
|
|
|
if "`first'" != ""{
|
|
cap assert real(word("`first'",1)) != . & real(word("`first'",2)) != . ///
|
|
& real(word("`first'",3)) != .
|
|
if _rc != 0{
|
|
di as err "Must supply estimate with confidence intervals: ES CIlow CIupp"
|
|
di as err "with user-defined main analysis"
|
|
exit
|
|
}
|
|
cap assert "`wgt'" != ""
|
|
if _rc != 0{
|
|
di as err "Must supply weight variable with option WGT(varname)"
|
|
di as err "with user-defined main analysis"
|
|
exit
|
|
}
|
|
cap assert "`by'"==""
|
|
if _rc != 0{
|
|
di as err "Cannot use option BY() with user-defined main analysis"
|
|
exit
|
|
}
|
|
cap assert $MA_params == 2 | $MA_params == 3
|
|
if _rc != 0{
|
|
di as err "Variable input must be 2 or 3 parameters, i.e.,
|
|
di as err "{theta se_theta} or {ES CIupp CIlow}"
|
|
di as err "with user-defined main analysis"
|
|
exit
|
|
}
|
|
|
|
global MA_userESM = real(word("`first'",1))
|
|
global MA_userCIlowM = real(word("`first'",2))
|
|
global MA_userCIuppM = real(word("`first'",3))
|
|
if "`eform'" != ""{
|
|
foreach glob in MA_userESM MA_userCIlowM MA_userCIuppM{
|
|
global `glob' = exp($`glob')
|
|
}
|
|
}
|
|
if $MA_userESM < $MA_userCIlowM | $MA_userESM > $MA_userCIuppM{
|
|
di as err "Must supply estimate with confidence interval in the order: ES CIlow CIupp"
|
|
exit
|
|
}
|
|
global MA_userDescM = substr("`first'", (strpos("`first'",word("`first'",4))), ///
|
|
(length("`first'")-strpos("`first'",word("`first'",4))+1) )
|
|
if word("`first'",4) == "" {
|
|
global MA_userDescM = "USER DEFN"
|
|
}
|
|
local method "USER"
|
|
|
|
}
|
|
|
|
|
|
if "`second'" != ""{
|
|
|
|
// METHODS
|
|
// RANDOM- D+L
|
|
// FIXED- M-H only available with cell counts
|
|
// RANDOMI- D+L
|
|
// FIXEDI- I-V
|
|
|
|
if "`second'" == "random" | "`second'" == "randomi" {
|
|
local method_2 "D+L"
|
|
}
|
|
else if "`second'" == "fixed" & "`4'" != "" & "`6'" == ""{
|
|
local method_2 "M-H"
|
|
}
|
|
else if "`second'" == "peto" & "`4'" != "" & "`6'" == ""{
|
|
local method_2 "Peto"
|
|
}
|
|
else if "`second'" == "fixedi" | ( ("`4'" == "" | "`6'" != "") & "`second'" == "fixed" ) ///
|
|
| ( ("`4'" == "" | "`6'" != "") & "`second'" == "peto" ){
|
|
local method_2 "I-V"
|
|
}
|
|
else{
|
|
cap assert real(word("`second'",1)) != . & real(word("`second'",2)) != . ///
|
|
& real(word("`second'",3)) != .
|
|
if _rc != 0{
|
|
di as err "Choose appropriate method for second analysis, or supply user-"
|
|
di as err "defined estimate with confidence intervals: ES CIlow CIupp"
|
|
exit
|
|
}
|
|
global MA_userES = real(word("`second'",1))
|
|
global MA_userCIlow = real(word("`second'",2))
|
|
global MA_userCIupp = real(word("`second'",3))
|
|
if "`eform'" != ""{
|
|
foreach glob in MA_userES MA_userCIlow MA_userCIupp{
|
|
global `glob' = exp($`glob')
|
|
}
|
|
}
|
|
if $MA_userES < $MA_userCIlow | $MA_userES > $MA_userCIupp{
|
|
di as err "Must supply estimate with confidence interval in the order: ES CIlow CIupp"
|
|
}
|
|
global MA_userDesc = substr("`second'", (strpos("`second'",word("`second'",4))), ///
|
|
(length("`second'")-strpos("`second'",word("`second'",4))+1) )
|
|
if word("`second'",4) == ""{
|
|
global MA_userDesc = "USER DEFN"
|
|
}
|
|
local nosecsub "nosecsub"
|
|
local method_2 "USER"
|
|
}
|
|
}
|
|
|
|
if "`method'" == "USER" & "`method_2'" != "USER" & "`method_2'" != ""{
|
|
di as err "Cannot have user defined analysis as main analysis and standard analysis
|
|
di as err "as second analysis. You can do it the other way round, or have two user"
|
|
di as err "defined analyses, but you can't do this particular thing."
|
|
di as err "Sorry, that's just the way it is."
|
|
exit
|
|
}
|
|
|
|
global MA_method1 "`method'"
|
|
global MA_method2 "`method_2'"
|
|
global MA_SECOND_ES .
|
|
global MA_SECOND_LCI .
|
|
global MA_SECOND_UCI .
|
|
global MA_SECOND_SE_ES .
|
|
global MA_SECOND_TAU2 .
|
|
global MA_first_TAU2 .
|
|
global MA_SECOND_DF .
|
|
global MA_first_DF .
|
|
|
|
if "`second'" != ""{
|
|
if "`callalg'" != "metanby"{ // just run through twice
|
|
|
|
`callalg' `varlist' `if' `in', `by' label(`code') `keep' /*
|
|
*/ method(`method_2') `randomi' `cont' `stand' `chi2' `cornfield' /*
|
|
*/ `log' `breslow' `eform' `wgt' `overall' `subgroup' `sgweight' /*
|
|
*/ `sortby' `saving' `xlabel' `xtick' `force' `wt' `stats' `counts' `box' /*
|
|
*/ t1(".`t1title'") t2(".`t2title'") b1(".`b1title'") b2(".`b2title'") lcols("`lcols'") rcols("`rcols'") /*
|
|
*/ `groupla' `nextcall' `sstat' notable nograph rjhsecond
|
|
|
|
global MA_second_ES = $S_1 // IF NO BY JUST KEEP ESTIMATES AND STICK IN SOMEWHERE LATER
|
|
global MA_second_SE_ES = $S_2
|
|
global MA_second_LCI = $S_3
|
|
global MA_second_UCI = $S_4
|
|
global MA_second_TAU2 = $S_12
|
|
global MA_second_DF = $S_8
|
|
|
|
`callalg' `varlist' `if' `in', `by' label(`code') `keep' `table' `graph' /*
|
|
*/ method(`method') `randomi' `cont' `stand' `chi2' `cornfield' /*
|
|
*/ `log' `breslow' `eform' `wgt' `overall' `subgroup' `sgweight' /*
|
|
*/ `sortby' `saving' `xlabel' `xtick' `force' `wt' `stats' `counts' `box' /*
|
|
*/ t1(".`t1title'") t2(".`t2title'") b1(".`b1title'") b2(".`b2title'") lcols("`lcols'") rcols("`rcols'") /*
|
|
*/ `groupla' `nextcall' `sstat'
|
|
|
|
}
|
|
|
|
if "`callalg'" == "metanby"{ // if by, then send to metanby and sort out there
|
|
|
|
`callalg' `varlist' `if' `in', `by' label(`code') `keep' `table' `graph' /*
|
|
*/ method(`method') method2(`method_2') `randomi' `cont' `stand' `chi2' `cornfield' /*
|
|
*/ `log' `breslow' `eform' `wgt' `overall' `subgroup' `sgweight' /*
|
|
*/ `sortby' `saving' `xlabel' `xtick' `force' `wt' `stats' `counts' `box' /*
|
|
*/ t1(".`t1title'") t2(".`t2title'") b1(".`b1title'") b2(".`b2title'") lcols("`lcols'") rcols("`rcols'") /*
|
|
*/ `groupla' `nextcall' `sstat' `nosecsub'
|
|
}
|
|
|
|
}
|
|
|
|
if "`second'" == ""{
|
|
|
|
if "`callalg'" != "metanby"{
|
|
`callalg' `varlist' `if' `in', `by' label(`code') `keep' `table' `graph' /*
|
|
*/ method(`method') `randomi' `cont' `stand' `chi2' `cornfield' /*
|
|
*/ `log' `breslow' `eform' `wgt' `overall' `subgroup' `sgweight' /*
|
|
*/ `sortby' `saving' `xlabel' `xtick' `force' `wt' `stats' `counts' `box' /*
|
|
*/ t1(".`t1title'") t2(".`t2title'") b1(".`b1title'") b2(".`b2title'") lcols("`lcols'") rcols("`rcols'") /*
|
|
*/ `groupla' `nextcall' `sstat'
|
|
|
|
}
|
|
if "`callalg'" == "metanby"{
|
|
`callalg' `varlist' `if' `in', `by' label(`code') `keep' `table' `graph' /*
|
|
*/ method(`method') `randomi' `cont' `stand' `chi2' `cornfield' /*
|
|
*/ `log' `breslow' `eform' `wgt' `overall' `subgroup' `sgweight' /*
|
|
*/ `sortby' `saving' `xlabel' `xtick' `force' `wt' `stats' `counts' `box' /*
|
|
*/ t1(".`t1title'") t2(".`t2title'") b1(".`b1title'") b2(".`b2title'") lcols("`lcols'") rcols("`rcols'") /*
|
|
*/ `groupla' `nextcall' `sstat'
|
|
}
|
|
|
|
}
|
|
|
|
if $S_8<0 {
|
|
di as err "Insufficient data to perform this meta-analysis"
|
|
}
|
|
|
|
*return log or eform as appropriate for OR/RR
|
|
|
|
return scalar ES=$S_1
|
|
if "$MA_method2" != ""{
|
|
return scalar ES_2=$MA_second_ES
|
|
return local method_1 "$MA_method1"
|
|
return local method_2 "$MA_method2"
|
|
}
|
|
|
|
if ("`sumstat'"=="OR" | "`sumstat'"=="RR") & ("`log'"=="") {
|
|
return scalar selogES=$S_2
|
|
if "$MA_method2" != ""{
|
|
return scalar selogES_2=$MA_second_SE_ES
|
|
}
|
|
}
|
|
|
|
else if ("`sumstat'"=="ES" & "`eform'"!="") {
|
|
return scalar selogES=$S_2
|
|
if "$MA_method2" != ""{
|
|
return scalar selogES_2=$MA_second_SE_ES
|
|
}
|
|
}
|
|
|
|
else {
|
|
return scalar seES=$S_2
|
|
if "$MA_method2" != ""{
|
|
return scalar seES_2=$MA_second_SE_ES
|
|
}
|
|
}
|
|
|
|
return scalar ci_low=$S_3
|
|
return scalar ci_upp=$S_4
|
|
if "$MA_method2" != ""{
|
|
return scalar ci_low_2=$MA_second_LCI
|
|
return scalar ci_upp_2=$MA_second_UCI
|
|
}
|
|
return scalar z=$S_5
|
|
return scalar p_z=$S_6
|
|
return scalar i_sq=$S_51 // ADDED I2 IN RETURN
|
|
return scalar het=$S_7
|
|
return scalar df=$S_8
|
|
return scalar p_het=$S_9
|
|
return scalar chi2=$S_10
|
|
return scalar p_chi2=$S_11
|
|
return scalar tau2=$S_12
|
|
return local measure "`log'`sumstat'"
|
|
if ("`sumstat'"=="RR" | "`sumstat'"=="OR" | "`sumstat'"=="RD") {
|
|
return scalar tger=$S_13
|
|
return scalar cger=$S_14
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
program define OR
|
|
|
|
version 9.0
|
|
#delimit ;
|
|
syntax varlist(min=4 max=4 default=none numeric) [if] [in] [,
|
|
LABEL(string) SORTBY(passthru) noGRAPH noTABLE CHI2 RANDOMI CC(string)
|
|
METHOD(string) XLAbel(passthru) XTICK(passthru) FORCE CORNFIELD noKEEP
|
|
SAVING(passthru) noBOX T1(string) T2(string) B1(string) B2(string) LCOLS(string) RCOLS(string)
|
|
noOVERALL noWT noSTATS LOG BRESLOW COUNTS WGT(varlist numeric max=1) noGROUPLA RJHSECOND] ;
|
|
|
|
#delimit cr
|
|
|
|
qui {
|
|
|
|
tempvar a b c d use zeros r1 r2 c1 c2 t or lnor es v se ill iul ea /*
|
|
*/ va weight qhet id rawdata cont_a cont_b cont_c cont_d
|
|
tempname ernum erden R S PR PS QR QS W OR lnOR selnOR A EA VA
|
|
tokenize "`varlist'", parse(" ")
|
|
if "`log'"!="" {
|
|
local exp
|
|
}
|
|
else {
|
|
local exp "exp"
|
|
}
|
|
gen double `a' =`1'
|
|
gen double `b' =`2'
|
|
gen double `c' =`3'
|
|
gen double `d' =`4'
|
|
gen double `r1'=`a'+`b'
|
|
gen double `r2'=`c'+`d'
|
|
gen double `c1'=`a'+`c'
|
|
gen double `c2'=`b'+`d'
|
|
gen byte `use'=1 `if' `in'
|
|
replace `use'=9 if `use'==.
|
|
replace `use'=9 if (`r1'==.) | (`r2'==.)
|
|
replace `use'=2 if (`use'==1) & (`r1'==0 | `r2'==0 )
|
|
replace `use'=2 if (`use'==1) & (`c1'==0 | `c2'==0 )
|
|
count if `use'==1
|
|
global S_8 =r(N)-1
|
|
if $S_8<0 {
|
|
exit
|
|
}
|
|
if "`counts'"!="" {
|
|
*Display raw counts
|
|
gen str `rawdata'= string(`a') + "/" + string(`r1') +";" + /*
|
|
*/ string(`c') + "/"+ string(`r2') if `use'!=9
|
|
replace `rawdata'= trim(`rawdata')
|
|
if "`overall'"=="" {
|
|
sum `a' if (`use'==1 | `use'==2)
|
|
local sum1 = r(sum)
|
|
sum `r1' if (`use'==1 | `use'==2)
|
|
local sum2 = r(sum)
|
|
sum `c' if (`use'==1 | `use'==2)
|
|
local sum3 = r(sum)
|
|
sum `r2' if (`use'==1 | `use'==2)
|
|
local sum4 =r(sum)
|
|
global MA_ODC "`sum1'/`sum2';`sum3'/`sum4'"
|
|
}
|
|
}
|
|
else {
|
|
gen str1 `rawdata'="."
|
|
}
|
|
|
|
if "`method'"=="D+L" & ($S_8==0) {
|
|
local method "M-H"
|
|
}
|
|
|
|
*Get average event rate for each group (before any 0.5 adjustments or excluding 0-0 studies)
|
|
sum `a' if `use'<3
|
|
scalar `ernum'=r(sum)
|
|
sum `r1' if `use'<3
|
|
scalar `erden'=r(sum)
|
|
global S_13=`ernum'/`erden'
|
|
sum `c' if `use'<3
|
|
scalar `ernum'=r(sum)
|
|
sum `r2' if `use'<3
|
|
scalar `erden'=r(sum)
|
|
global S_14=`ernum'/`erden'
|
|
|
|
*Remove "uninformative" studies
|
|
replace `a'=. if `use'!=1
|
|
replace `b'=. if `use'!=1
|
|
replace `c'=. if `use'!=1
|
|
replace `d'=. if `use'!=1
|
|
replace `r1'=. if `use'!=1
|
|
replace `r2'=. if `use'!=1
|
|
gen double `t' =`r1'+`r2'
|
|
|
|
* Chi-squared test for effect
|
|
sum `a',meanonly
|
|
scalar `A'=r(sum)
|
|
gen double `ea'=(`r1'*`c1')/`t'
|
|
gen double `va'=`r1'*`r2'*`c1'*(`b'+`d')/(`t'*`t'*(`t'-1))
|
|
sum `ea',meanonly
|
|
scalar `EA'=r(sum)
|
|
sum `va',meanonly
|
|
scalar `VA'=r(sum)
|
|
global S_10=( (`A'-`EA')^2 )/`VA' /* chi2 effect value */
|
|
global S_11=chiprob(1,$S_10) /* p(chi2) */
|
|
|
|
if "`cornfield'"!="" {
|
|
*Compute Cornfield CI
|
|
gen `ill'=.
|
|
gen `iul'=.
|
|
local j = 1
|
|
tempname i al aj c1j r1j r2j alold
|
|
while `j'<=_N {
|
|
if `use'[`j']==1 {
|
|
scalar `i' = 0
|
|
scalar `al' =`a'[`j']
|
|
scalar `aj' =`a'[`j']
|
|
scalar `c1j'=`c1'[`j']
|
|
scalar `r1j'=`r1'[`j']
|
|
scalar `r2j'=`r2'[`j']
|
|
scalar `alold'= .
|
|
while abs(`al'-`alold')>.001 & `al'!=. {
|
|
scalar `alold' = `al'
|
|
scalar `al'=`aj'-($ZIND)/sqrt( (1/`al') + 1/(`c1j'-`al') + /*
|
|
*/ 1/(`r1j'-`al') + 1/(`r2j'-`c1j'+`al') )
|
|
if `al'==. {
|
|
scalar `i'=`i'+1
|
|
scalar `al'=`aj'-`i'
|
|
if (`al'<0 | (`r2j'-`c1j'+`al')<0) {scalar `al'= . }
|
|
}
|
|
}
|
|
|
|
if `al'==. {
|
|
scalar `al'= 0
|
|
}
|
|
replace `ill'=`log'( `al'*(`r2j'-`c1j'+`al')/((`c1j'-`al')*(`r1j'-`al')) ) in `j'
|
|
scalar `al'= `a'[`j']
|
|
scalar `alold'= .
|
|
scalar `i'= 0
|
|
while abs(`al'-`alold')>.001 & `al'!=. {
|
|
scalar `alold'= `al'
|
|
scalar `al'=`aj'+($ZIND)/sqrt( (1/`al')+ 1/(`c1j'-`al') + /*
|
|
*/ 1/(`r1j'-`al') + 1/(`r2j'-`c1j'+`al') )
|
|
if `al'==. {
|
|
scalar `i'=`i'+1
|
|
scalar `al'=`aj'+`i'
|
|
if (`al'>`r1j' | `al'>`c1j' ) {
|
|
scalar `al' = .
|
|
}
|
|
}
|
|
}
|
|
|
|
replace `iul'=`log'( `al'*(`r2j'-`c1j'+`al')/((`c1j'-`al')*(`r1j'-`al')) ) in `j'
|
|
}
|
|
|
|
local j=`j'+1
|
|
|
|
} // end while
|
|
|
|
} // end Cornfield
|
|
|
|
|
|
*Adjustment for zero cells in calcn of OR and var(OR)
|
|
gen `zeros'=1 if `use'==1 & (`a'==0 | `b'==0 | `c'==0 | `d'==0 )
|
|
gen `cont_a'=`cc'
|
|
gen `cont_b'=`cc'
|
|
gen `cont_c'=`cc'
|
|
gen `cont_d'=`cc'
|
|
replace `a'=`a'+`cont_a' if `zeros'==1
|
|
replace `b'=`b'+`cont_b' if `zeros'==1
|
|
replace `c'=`c'+`cont_c' if `zeros'==1
|
|
replace `d'=`d'+`cont_d' if `zeros'==1
|
|
replace `r1'=`r1'+(`cont_a'+`cont_b') if `zeros'==1
|
|
replace `r2'=`r2'+(`cont_c'+`cont_d') if `zeros'==1
|
|
replace `t' =`t' +(`cont_a'+`cont_b')+(`cont_c'+`cont_d') if `zeros'==1
|
|
gen double `or' =(`a'*`d')/(`b'*`c')
|
|
gen double `lnor'=log(`or')
|
|
gen double `v' =1/`a' +1/`b' +1/`c' + 1/`d'
|
|
gen double `es' =`log'(`or')
|
|
gen double `se' =sqrt(`v')
|
|
|
|
if "`cornfield'"=="" {
|
|
gen `ill' =`exp'(`lnor'-$ZIND*`se')
|
|
gen `iul' =`exp'(`lnor'+$ZIND*`se')
|
|
}
|
|
|
|
if "`method'"=="M-H" | ( "`method'"=="D+L" & "`randomi'"=="" ) {
|
|
tempname p q r s pr ps qr qs
|
|
gen double `r' =`a'*`d'/`t'
|
|
gen double `s' =`b'*`c'/`t'
|
|
sum `r', meanonly
|
|
scalar `R' =r(sum)
|
|
sum `s', meanonly
|
|
scalar `S' =r(sum)
|
|
|
|
*Calculate pooled MH- OR
|
|
scalar `OR' =`R'/`S'
|
|
scalar `lnOR'=log(`OR')
|
|
|
|
*Calculate variance/SE of lnOR and weights
|
|
gen double `p' =(`a'+`d')/`t'
|
|
gen double `q' =(`b'+`c')/`t'
|
|
gen double `pr' =`p'*`r'
|
|
gen double `ps' =`p'*`s'
|
|
gen double `qr' =`q'*`r'
|
|
gen double `qs' =`q'*`s'
|
|
sum `pr', meanonly
|
|
scalar `PR' =r(sum)
|
|
sum `ps', meanonly
|
|
scalar `PS' =r(sum)
|
|
sum `qr', meanonly
|
|
scalar `QR' =r(sum)
|
|
sum `qs', meanonly
|
|
scalar `QS' =r(sum)
|
|
scalar `selnOR'= sqrt( (`PR'/(`R'*`R') + (`PS'+`QR')/(`R'*`S') + /*
|
|
*/ `QS'/(`S'*`S'))/2 )
|
|
gen `weight'=100*`s'/`S'
|
|
|
|
*Store results in global macros, on log scale if requested
|
|
global S_1 =`log'(`OR')
|
|
global S_2 =`selnOR'
|
|
global S_3 =`exp'(`lnOR' -$ZOVE*`selnOR')
|
|
global S_4 =`exp'(`lnOR' +$ZOVE*`selnOR')
|
|
global S_5 =abs(`lnOR')/(`selnOR')
|
|
global S_6 =normprob(-abs($S_5))*2
|
|
drop `p' `q' `r' `pr' `ps' `qr' `qs'
|
|
|
|
*Calculate heterogeneity
|
|
if "`breslow'"=="" {
|
|
gen double `qhet' =( (`lnor'-`lnOR')^2 )/`v'
|
|
sum `qhet', meanonly
|
|
global S_7 =r(sum) /*Chi-squared */
|
|
global S_9 =chiprob($S_8,$S_7) /*p(chi2 het) */
|
|
global S_51 =max(0, ( 100*($S_7-$S_8))/($S_7) )
|
|
}
|
|
} /* end M-H method */
|
|
|
|
if "`wgt'"!="" {
|
|
cap gen `weight'=.
|
|
udw `lnor' `v' , wgt(`wgt') `exp'
|
|
replace `weight'=`wgt'*100/$MA_W
|
|
local udwind "wgt(`wgt')"
|
|
}
|
|
else if "`method'"!="M-H" & "`method'"!= "USER"{
|
|
cap gen `weight'=.
|
|
iv `lnor' `v', method(`method') `randomi' `exp'
|
|
replace `weight'=100/( (`v'+$S_12)*($MA_W) )
|
|
}
|
|
|
|
if "`breslow'"!="" {
|
|
|
|
*Calculate heterogeneity by Breslow-Day test: need to reset zero cells and margins
|
|
if "`log'"=="" {
|
|
local bexp
|
|
}
|
|
else {
|
|
local bexp "exp"
|
|
}
|
|
|
|
replace `a'=`a'-`cont_a' if `zeros'==1
|
|
replace `b'=`b'-`cont_b' if `zeros'==1
|
|
replace `c'=`c'-`cont_c' if `zeros'==1
|
|
replace `d'=`d'-`cont_d' if `zeros'==1
|
|
replace `r1'=`r1'-(`cont_a'+`cont_b') if `zeros'==1
|
|
replace `r2'=`r2'-(`cont_c'+`cont_d') if `zeros'==1
|
|
replace `t' =`t' -(`cont_a'+`cont_b')-(`cont_c'+`cont_d') if `zeros'==1
|
|
|
|
if abs(`bexp'($S_1) - 1)<0.0001 {
|
|
gen afit = `r1'*`c1'/`t'
|
|
gen bfit = `r1'*`c2'/`t'
|
|
gen cfit = `r2'*`c1'/`t'
|
|
gen dfit = `r2'*`c2'/`t'
|
|
}
|
|
else {
|
|
tempvar sterm cterm root1 root2 afit bfit cfit dfit bresd_q
|
|
tempname qterm
|
|
scalar `qterm' = 1-`bexp'($S_1)
|
|
gen `sterm' = `r2' - `c1' + (`bexp'($S_1))*(`r1'+`c1')
|
|
gen `cterm' = -(`bexp'($S_1))*`c1'*`r1'
|
|
gen `root1' = (-`sterm' + sqrt(`sterm'*`sterm' - 4*`qterm'*`cterm'))/(2*`qterm')
|
|
gen `root2' = (-`sterm' - sqrt(`sterm'*`sterm' - 4*`qterm'*`cterm'))/(2*`qterm')
|
|
gen `afit' = `root1' if `root2'<0
|
|
replace `afit' = `root2' if `root1'<0
|
|
replace `afit' = `root1' if (`root2'>`c1') | (`root2'>`r1')
|
|
replace `afit' = `root2' if (`root1'>`c1') | (`root1'>`r1')
|
|
gen `bfit' = `r1' - `afit'
|
|
gen `cfit' = `c1' - `afit'
|
|
gen `dfit' = `r2' - `cfit'
|
|
}
|
|
|
|
gen `qhet' = ((`a'-`afit')^2)*((1/`afit')+(1/`bfit')+(1/`cfit')+(1/`dfit'))
|
|
sum `qhet', meanonly
|
|
global S_7 =r(sum) /*Het. Chi-squared */
|
|
global S_9 =chiprob($S_8,$S_7) /*p(chi2 het) */
|
|
global S_51 =max(0, ( 100*($S_7-$S_8))/($S_7) )
|
|
}
|
|
|
|
if "`method'" == "USER"{
|
|
forvalues i = 1/15{
|
|
global S_`i' = .
|
|
}
|
|
cap drop `weight'
|
|
gen `weight'=.
|
|
if "`rjhsecond'" != ""{
|
|
global S_1 = $MA_userES
|
|
global S_3 = $MA_userCIlow
|
|
global S_4 = $MA_userCIupp
|
|
}
|
|
else{
|
|
global S_1 = $MA_userESM
|
|
global S_3 = $MA_userCIlowM
|
|
global S_4 = $MA_userCIuppM
|
|
}
|
|
}
|
|
replace `weight'=0 if `weight'==.
|
|
|
|
|
|
} /* End of "quietly" loop */
|
|
|
|
|
|
_disptab `es' `se' `ill' `iul' `weight' `use' `label' `rawdata', `keep' `sortby' /*
|
|
*/ `table' method(`method') sumstat(OR) `chi2' `xlabel' `xtick' `force' `graph' /*
|
|
*/ `box' `saving' t1("`t1'") t2("`t2'") b1("`b1'") b2("`b2'") lcols("`lcols'") rcols("`rcols'") `overall' `wt' /*
|
|
*/ `stats' `counts' `log' `groupla' `udwind' `cornfield' `rjhsecond'
|
|
|
|
end
|
|
|
|
|
|
|
|
program define Peto
|
|
|
|
version 9.0
|
|
|
|
#delimit ;
|
|
syntax varlist(min=4 max=4 default=none numeric) [if] [in] [,
|
|
LABEL(string) ORDER(string) noGRAPH METHOD(string) CHI2 XLAbel(passthru)
|
|
XTICK(passthru) FORCE noKEEP SAVING(passthru) noBOX noTABLE SORTBY(passthru) T1(string)
|
|
T2(string) B1(string) B2(string) LCOLS(string) RCOLS(string) noOVERALL noWT noSTATS LOG COUNTS RJHSECOND] ;
|
|
|
|
#delimit cr
|
|
|
|
qui {
|
|
|
|
tempvar a b c d use r1 r2 t ea olesse v lnor or es se /*
|
|
*/ ill iul p weight id rawdata
|
|
tempname ernum erden OLESSE V SE P lnOR A C R1 R2
|
|
|
|
tokenize "`varlist'", parse(" ")
|
|
|
|
if "`log'"!="" {
|
|
local exp
|
|
}
|
|
else {
|
|
local exp "exp"
|
|
}
|
|
|
|
gen double `a' =`1' `if' `in'
|
|
gen double `b' =`2' `if' `in'
|
|
gen double `c' =`3' `if' `in'
|
|
gen double `d' =`4' `if' `in'
|
|
gen double `r1' =`a'+`b'
|
|
gen double `r2' =`c'+`d'
|
|
gen byte `use'=1 `if' `in'
|
|
replace `use'=9 if `use'==.
|
|
replace `use'=9 if (`r1'==.) | (`r2'==.)
|
|
replace `use'=2 if (`use'==1) & (`r1'==0 | `r2'==0 )
|
|
replace `use'=2 if (`use'==1) & ((`a'==0 & `c'==0 ) | (`b'==0 & `d'==0))
|
|
count if `use'==1
|
|
global S_8 =r(N)-1
|
|
|
|
if $S_8<0 {
|
|
exit
|
|
}
|
|
|
|
if "`counts'"!="" {
|
|
*Display raw counts
|
|
gen str `rawdata'= string(`a') + "/" + string(`r1') +";" + /*
|
|
*/ string(`c') + "/"+ string(`r2') if `use'!=9
|
|
replace `rawdata'= trim(`rawdata')
|
|
if "`overall'"=="" {
|
|
sum `a' if (`use'==1 | `use'==2)
|
|
local sum1 =r(sum)
|
|
sum `r1' if (`use'==1 | `use'==2)
|
|
local sum2 =r(sum)
|
|
sum `c' if (`use'==1 | `use'==2)
|
|
local sum3 =r(sum)
|
|
sum `r2' if (`use'==1 | `use'==2)
|
|
local sum4 =r(sum)
|
|
global MA_ODC "`sum1'/`sum2';`sum3'/`sum4'"
|
|
}
|
|
}
|
|
|
|
else {
|
|
gen str1 `rawdata'="."
|
|
} /* end counts */
|
|
|
|
*Get average event rate for each group (before any 0.5 adjustments or excluding 0-0 studies)
|
|
sum `a' if `use'<3
|
|
scalar `ernum'=r(sum)
|
|
sum `r1' if `use'<3
|
|
scalar `erden'=r(sum)
|
|
global S_13=`ernum'/`erden'
|
|
sum `c' if `use'<3
|
|
scalar `ernum'=r(sum)
|
|
sum `r2' if `use'<3
|
|
scalar `erden'=r(sum)
|
|
global S_14=`ernum'/`erden'
|
|
|
|
*Remove "uninformative" studies
|
|
replace `a'=. if `use'!=1
|
|
replace `b'=. if `use'!=1
|
|
replace `c'=. if `use'!=1
|
|
replace `d'=. if `use'!=1
|
|
replace `r1'=. if `use'!=1
|
|
replace `r2'=. if `use'!=1
|
|
gen double `t' =`r1'+`r2'
|
|
gen double `ea' =`r1'*(`a'+`c')/`t'
|
|
gen double `olesse'=`a'-`ea'
|
|
gen double `v' =`r1'*`r2'*(`a'+`c')*(`b'+`d')/( `t'*`t'*(`t'-1) )
|
|
gen double `lnor' =`olesse'/`v'
|
|
gen double `es' = `exp'(`lnor')
|
|
gen double `se' = 1/(sqrt(`v'))
|
|
gen double `ill' = `exp'(`lnor'-$ZIND*`se')
|
|
gen double `iul' = `exp'(`lnor'+$ZIND*`se')
|
|
gen double `p' =(`olesse')*(`olesse')/`v'
|
|
sum `olesse', meanonly
|
|
scalar `OLESSE'=r(sum)
|
|
sum `v', meanonly
|
|
scalar `V' =r(sum)
|
|
sum `p', meanonly
|
|
scalar `P' =r(sum)
|
|
scalar `lnOR' =`OLESSE'/`V'
|
|
global S_1 =`exp'(`lnOR')
|
|
global S_2 =1/sqrt(`V')
|
|
global S_3 =`exp'(`lnOR'-$ZOVE*($S_2))
|
|
global S_4 =`exp'(`lnOR'+$ZOVE*($S_2))
|
|
sum `a', meanonly
|
|
scalar `A' =r(sum)
|
|
sum `c', meanonly
|
|
scalar `C' =r(sum)
|
|
sum `r1', meanonly
|
|
scalar `R1' =r(sum)
|
|
sum `r2', meanonly
|
|
scalar `R2' =r(sum)
|
|
global S_10 =(`OLESSE'^2)/`V' /*Chi-squared effect*/
|
|
global S_11 =chiprob(1,$S_10)
|
|
global S_5 =abs(`lnOR')/($S_2)
|
|
global S_6 =normprob(-abs($S_5))*2
|
|
|
|
/*Heterogeneity */
|
|
global S_7=`P'-$S_10
|
|
global S_9 =chiprob($S_8,$S_7)
|
|
global S_51 =max(0, ( 100*($S_7-$S_8))/($S_7) )
|
|
gen `weight' =100*`v'/`V'
|
|
|
|
if "`method'" == "USER"{
|
|
forvalues i = 1/15{
|
|
global S_`i' = .
|
|
}
|
|
cap drop `weight'
|
|
gen `weight'=.
|
|
if "`rjhsecond'" != ""{
|
|
global S_1 = $MA_userES
|
|
global S_3 = $MA_userCIlow
|
|
global S_4 = $MA_userCIupp
|
|
}
|
|
else{
|
|
global S_1 = $MA_userESM
|
|
global S_3 = $MA_userCIlowM
|
|
global S_4 = $MA_userCIuppM
|
|
}
|
|
}
|
|
replace `weight'=0 if `weight'==.
|
|
|
|
} /* End of quietly loop */
|
|
|
|
_disptab `es' `se' `ill' `iul' `weight' `use' `label' `rawdata' , `keep' `sortby' /*
|
|
*/ `table' method(`method') sumstat(OR) `chi2' `xlabel' `xtick' `force' `graph' `box' /*
|
|
*/ `saving' t1("`t1'") t2("`t2'") b1("`b1'") b2("`b2'") lcols("`lcols'") rcols("`rcols'") /*
|
|
*/ `rjhsecond' `overall' `wt' `stats' `counts' `log'
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
program define RR
|
|
version 9.0
|
|
#delimit ;
|
|
syntax varlist(min=4 max=4 default=none numeric) [if] [in] [,
|
|
LABEL(string) SORTBY(passthru) noGRAPH noTABLE RANDOMI METHOD(string) CC(string)
|
|
XLAbel(passthru) XTICK(passthru) FORCE noKEEP SAVING(passthru) noBOX T1(string)
|
|
T2(string) B1(string) B2(string) LCOLS(string) RCOLS(string) noOVERALL noWT noSTATS LOG COUNTS RJHSECOND
|
|
WGT(varlist numeric max=1) ] ;
|
|
#delimit cr
|
|
|
|
qui {
|
|
|
|
tempvar a b c d use zeros r1 r2 t p r s rr lnrr es v se ill iul q /*
|
|
*/ weight id rawdata cont_a cont_b cont_c cont_d
|
|
tempname ernum erden P R S RR lnRR vlnRR
|
|
|
|
tokenize "`varlist'", parse(" ")
|
|
|
|
if "`log'"!="" {
|
|
local exp
|
|
}
|
|
else {
|
|
local exp "exp"
|
|
}
|
|
|
|
gen double `a' =`1'
|
|
gen double `b' =`2'
|
|
gen double `c' =`3'
|
|
gen double `d' =`4'
|
|
gen double `r1' =`a'+`b'
|
|
gen double `r2' =`c'+`d'
|
|
gen byte `use'=1 `if' `in'
|
|
replace `use'=9 if `use'==.
|
|
replace `use'=9 if (`r1'==.) | (`r2'==.)
|
|
replace `use'=2 if (`use'==1) & (`r1'==0 | `r2'==0 )
|
|
replace `use'=2 if (`use'==1) & ((`a'==0 & `c'==0 ) | (`b'==0 & `d'==0))
|
|
count if `use'==1
|
|
global S_8 =r(N)-1
|
|
if $S_8<0 {
|
|
exit
|
|
}
|
|
|
|
if "`counts'"!="" {
|
|
*Display raw counts
|
|
gen str `rawdata'= string(`a') + "/" + string(`r1') +";" + /*
|
|
*/ string(`c') + "/"+ string(`r2') if `use'!=9
|
|
replace `rawdata'= trim(`rawdata')
|
|
if "`overall'"=="" {
|
|
sum `a' if (`use'==1 | `use'==2)
|
|
local sum1 =r(sum)
|
|
sum `r1' if (`use'==1 | `use'==2)
|
|
local sum2 =r(sum)
|
|
sum `c' if (`use'==1 | `use'==2)
|
|
local sum3 =r(sum)
|
|
sum `r2' if (`use'==1 | `use'==2)
|
|
local sum4 =r(sum)
|
|
global MA_ODC "`sum1'/`sum2';`sum3'/`sum4'"
|
|
}
|
|
}
|
|
|
|
else {
|
|
gen str1 `rawdata'="."
|
|
} /* end counts */
|
|
|
|
if "`method'"=="D+L" & ($S_8==0) {
|
|
local method "M-H"
|
|
}
|
|
|
|
*Get average event rate for each group (before any 0.5 adjustments or excluding 0-0 studies)
|
|
sum `a' if `use'<3
|
|
scalar `ernum'=r(sum)
|
|
sum `r1' if `use'<3
|
|
scalar `erden'=r(sum)
|
|
global S_13=`ernum'/`erden'
|
|
sum `c' if `use'<3
|
|
scalar `ernum'=r(sum)
|
|
sum `r2' if `use'<3
|
|
scalar `erden'=r(sum)
|
|
global S_14=`ernum'/`erden'
|
|
|
|
*Adjustment for zero cells in calcn of OR and var(OR)
|
|
gen `zeros'=1 if `use'==1 & (`a'==0 | `b'==0 | `c'==0 | `d'==0 )
|
|
gen `cont_a'=`cc'
|
|
gen `cont_b'=`cc'
|
|
gen `cont_c'=`cc'
|
|
gen `cont_d'=`cc'
|
|
replace `a'=`a'+`cont_a' if `zeros'==1
|
|
replace `b'=`b'+`cont_b' if `zeros'==1
|
|
replace `c'=`c'+`cont_c' if `zeros'==1
|
|
replace `d'=`d'+`cont_d' if `zeros'==1
|
|
replace `r1'=`r1'+(`cont_a'+`cont_b') if `zeros'==1
|
|
replace `r2'=`r2'+(`cont_c'+`cont_d') if `zeros'==1
|
|
|
|
*Remove "uninformative" studies
|
|
replace `a'=. if `use'!=1
|
|
replace `b'=. if `use'!=1
|
|
replace `c'=. if `use'!=1
|
|
replace `d'=. if `use'!=1
|
|
replace `r1'=. if `use'!=1
|
|
replace `r2'=. if `use'!=1
|
|
|
|
gen double `t' =`r1'+`r2'
|
|
gen double `r' =`a'*`r2'/`t'
|
|
gen double `s' =`c'*`r1'/`t'
|
|
gen double `rr' =`r'/`s'
|
|
gen double `lnrr'=log(`rr')
|
|
gen double `es' =`log'(`rr')
|
|
gen double `v' =1/`a' +1/`c' - 1/`r1' - 1/`r2'
|
|
gen double `se' =sqrt(`v')
|
|
gen double `ill' =`exp'(`lnrr'-$ZIND*`se')
|
|
gen double `iul' =`exp'(`lnrr'+$ZIND*`se')
|
|
|
|
if "`method'"=="M-H" | "`method'"=="D+L" & "`randomi'"=="" {
|
|
*MH method for pooling/calculating heterogeneity in DL method
|
|
gen double `p' =`r1'*`r2'*(`a'+`c')/(`t'*`t') - `a'*`c'/`t'
|
|
sum `p', meanonly
|
|
scalar `P' =r(sum)
|
|
sum `r', meanonly
|
|
scalar `R' =r(sum)
|
|
sum `s', meanonly
|
|
scalar `S' =r(sum)
|
|
scalar `RR'=`R'/`S'
|
|
scalar `lnRR'=log(`RR')
|
|
|
|
* Heterogeneity
|
|
gen double `q' =( (`lnrr'-`lnRR')^2 )/`v'
|
|
sum `q', meanonly
|
|
global S_7 =r(sum)
|
|
global S_9 =chiprob($S_8,$S_7)
|
|
global S_51 =max(0, ( 100*($S_7-$S_8))/($S_7) )
|
|
gen `weight'=100*`s'/`S'
|
|
global S_1 =`log'(`RR')
|
|
global S_2 =sqrt( `P'/(`R'*`S') )
|
|
global S_3 =`exp'(`lnRR' -$ZOVE*($S_2))
|
|
global S_4 =`exp'(`lnRR' +$ZOVE*($S_2))
|
|
global S_5 =abs(`lnRR')/($S_2)
|
|
global S_6 =normprob(-abs($S_5))*2
|
|
}
|
|
|
|
if "`wgt'"!="" {
|
|
cap gen `weight'=.
|
|
udw `lnrr' `v' , wgt(`wgt') `exp'
|
|
replace `weight'=`wgt'*100/$MA_W
|
|
local udwind "wgt(`wgt')"
|
|
}
|
|
|
|
else if "`method'"!="M-H" & "`method'"!="USER"{
|
|
cap gen `weight'=.
|
|
iv `lnrr' `v', method(`method') `randomi' `exp'
|
|
replace `weight'=100/( (`v'+$S_12)*($MA_W) )
|
|
}
|
|
|
|
|
|
if "`method'" == "USER"{
|
|
forvalues i = 1/15{
|
|
global S_`i' = .
|
|
}
|
|
cap drop `weight'
|
|
gen `weight'=.
|
|
if "`rjhsecond'" != ""{
|
|
global S_1 = $MA_userES
|
|
global S_3 = $MA_userCIlow
|
|
global S_4 = $MA_userCIupp
|
|
}
|
|
else{
|
|
global S_1 = $MA_userESM
|
|
global S_3 = $MA_userCIlowM
|
|
global S_4 = $MA_userCIuppM
|
|
}
|
|
}
|
|
replace `weight'=0 if `weight'==.
|
|
|
|
|
|
|
|
|
|
} /* End of "quietly" loop */
|
|
|
|
|
|
_disptab `es' `se' `ill' `iul' `weight' `use' `label' `rawdata' , `keep' `sortby' /*
|
|
*/ `table' method(`method') sumstat(RR) `xlabel' `xtick' `force' `graph' `box' /*
|
|
*/ `saving' t1("`t1'") t2("`t2'") b1("`b1'") b2("`b2'") lcols("`lcols'") rcols("`rcols'") `overall' `wt' /*
|
|
*/ `stats' `counts' `log' `udwind' `rjhsecond'
|
|
|
|
end
|
|
|
|
|
|
|
|
program define RD
|
|
|
|
version 9.0
|
|
|
|
#delimit ;
|
|
syntax varlist(min=4 max=4 default=none numeric) [if] [in] [,
|
|
LABEL(string) SORTBY(passthru) noGRAPH noTABLE RANDOMI METHOD(string) CC(string) noKEEP
|
|
SAVING(passthru) XLAbel(passthru) XTICK(passthru) noBOX FORCE T1(string) T2(string)
|
|
B1(string) B2(string) LCOLS(string) RCOLS(string) noOVERALL noWT noSTATS COUNTS WGT(varlist numeric max=1) RJHSECOND ] ;
|
|
#delimit cr
|
|
|
|
qui {
|
|
|
|
tempvar a b c d use zeros r1 r2 t rd weight rdnum v se ill iul vnum q /*
|
|
*/ id w rawdata cont_a cont_b cont_c cont_d
|
|
tempname ernum erden RDNUM VNUM W
|
|
|
|
tokenize "`varlist'", parse(" ")
|
|
gen double `a' =`1'
|
|
gen double `b' =`2'
|
|
gen double `c' =`3'
|
|
gen double `d' =`4'
|
|
gen double `r1' =`a'+`b'
|
|
gen double `r2' =`c'+`d'
|
|
gen byte `use'=1 `if' `in'
|
|
replace `use'=9 if `use'==.
|
|
replace `use'=9 if (`r1'==.) | (`r2'==.)
|
|
replace `use'=2 if ( `use'==1) & (`r1'==0 | `r2'==0 )
|
|
count if `use'==1
|
|
global S_8 =r(N)-1
|
|
|
|
if $S_8<0 {
|
|
exit
|
|
}
|
|
|
|
if "`counts'"!="" {
|
|
*Display raw counts
|
|
gen str `rawdata'= string(`a') + "/" + string(`r1') +";" + /*
|
|
*/ string(`c') + "/"+ string(`r2') if `use'!=9
|
|
replace `rawdata'= trim(`rawdata')
|
|
|
|
if "`overall'"=="" {
|
|
sum `a' if (`use'==1 | `use'==2)
|
|
local sum1 =r(sum)
|
|
sum `r1' if (`use'==1 | `use'==2)
|
|
local sum2 =r(sum)
|
|
sum `c' if (`use'==1 | `use'==2)
|
|
local sum3 =r(sum)
|
|
sum `r2' if (`use'==1 | `use'==2)
|
|
local sum4 =r(sum)
|
|
global MA_ODC "`sum1'/`sum2';`sum3'/`sum4'"
|
|
}
|
|
}
|
|
|
|
else {
|
|
gen str1 `rawdata'="."
|
|
} /* end counts */
|
|
|
|
if "`method'"=="D+L" & ($S_8==0) {
|
|
local method "M-H"
|
|
}
|
|
|
|
*Get average event rate for each group (before any cont adjustments or excluding 0-0 studies)
|
|
sum `a' if `use'<3
|
|
scalar `ernum'=r(sum)
|
|
sum `r1' if `use'<3
|
|
scalar `erden'=r(sum)
|
|
global S_13=`ernum'/`erden'
|
|
sum `c' if `use'<3
|
|
scalar `ernum'=r(sum)
|
|
sum `r2' if `use'<3
|
|
scalar `erden'=r(sum)
|
|
global S_14=`ernum'/`erden'
|
|
|
|
*Remove "uninformative" studies
|
|
replace `a'=. if `use'!=1
|
|
replace `b'=. if `use'!=1
|
|
replace `c'=. if `use'!=1
|
|
replace `d'=. if `use'!=1
|
|
replace `r1'=. if `use'!=1
|
|
replace `r2'=. if `use'!=1
|
|
gen double `t' =`r1'+`r2'
|
|
gen double `rd' =`a'/`r1' - `c'/`r2'
|
|
gen `weight'=`r1'*`r2'/`t'
|
|
sum `weight',meanonly
|
|
scalar `W' =r(sum)
|
|
gen double `rdnum'=( (`a'*`r2')-(`c'*`r1') )/`t'
|
|
|
|
* Zero cell adjustments, placed here to ensure 0/n1 v 0/n2 really IS RD=0
|
|
*Adjustment for zero cells in calcn of OR and var(OR)
|
|
|
|
gen `zeros'=1 if `use'==1 & (`a'==0 | `b'==0 | `c'==0 | `d'==0 )
|
|
gen `cont_a'=`cc'
|
|
gen `cont_b'=`cc'
|
|
gen `cont_c'=`cc'
|
|
gen `cont_d'=`cc'
|
|
replace `a'=`a'+`cont_a' if `zeros'==1
|
|
replace `b'=`b'+`cont_b' if `zeros'==1
|
|
replace `c'=`c'+`cont_c' if `zeros'==1
|
|
replace `d'=`d'+`cont_d' if `zeros'==1
|
|
replace `r1'=`r1'+(`cont_a'+`cont_b') if `zeros'==1
|
|
replace `r2'=`r2'+(`cont_c'+`cont_d') if `zeros'==1
|
|
replace `t' =`t' +(`cont_a'+`cont_b')+(`cont_c'+`cont_d') if `zeros'==1
|
|
|
|
gen double `v' =`a'*`b'/(`r1'^3)+`c'*`d'/(`r2'^3)
|
|
gen double `se' =sqrt(`v')
|
|
gen double `ill' = `rd'-$ZIND*`se'
|
|
gen double `iul' = `rd'+$ZIND*`se'
|
|
|
|
if "`method'"=="M-H" | ("`method'"=="D+L" & "`randomi'"=="" ) {
|
|
sum `rdnum',meanonly
|
|
scalar `RDNUM'=r(sum)
|
|
global S_1 =`RDNUM'/`W'
|
|
gen double `q' =( (`rd'-$S_1)^2 )/`v'
|
|
sum `q', meanonly
|
|
global S_7 =r(sum)
|
|
global S_9 =chiprob($S_8,$S_7)
|
|
global S_51 =max(0, ( 100*($S_7-$S_8))/($S_7) )
|
|
gen double `vnum'=( (`a'*`b'*(`r2'^3) )+(`c'*`d'*(`r1'^3))) /*
|
|
*/ /(`r1'*`r2'*`t'*`t')
|
|
sum `vnum',meanonly
|
|
scalar `VNUM'=r(sum)
|
|
global S_2 =sqrt( `VNUM'/(`W'*`W') )
|
|
replace `weight'=`weight'*100/`W'
|
|
global S_3 =$S_1 -$ZOVE*($S_2)
|
|
global S_4 =$S_1 +$ZOVE*($S_2)
|
|
global S_5 =abs($S_1)/($S_2)
|
|
global S_6 =normprob(-abs($S_5))*2
|
|
}
|
|
|
|
if "`wgt'"!="" {
|
|
udw `rd' `v' ,wgt(`wgt')
|
|
replace `weight'=`wgt'*100/$MA_W
|
|
local udwind "wgt(`wgt')"
|
|
}
|
|
else if "`method'"!="M-H" & "`method'"!= "USER" {
|
|
iv `rd' `v', method(`method') `randomi'
|
|
replace `weight'=100/( (`v'+$S_12)*($MA_W) )
|
|
}
|
|
|
|
if "`method'" == "USER"{
|
|
forvalues i = 1/15{
|
|
global S_`i' = .
|
|
}
|
|
cap drop `weight'
|
|
gen `weight'=.
|
|
if "`rjhsecond'" != ""{
|
|
global S_1 = $MA_userES
|
|
global S_3 = $MA_userCIlow
|
|
global S_4 = $MA_userCIupp
|
|
}
|
|
else{
|
|
global S_1 = $MA_userESM
|
|
global S_3 = $MA_userCIlowM
|
|
global S_4 = $MA_userCIuppM
|
|
}
|
|
}
|
|
replace `weight'=0 if `weight'==.
|
|
|
|
} /* End of "quietly" loop */
|
|
|
|
|
|
_disptab `rd' `se' `ill' `iul' `weight' `use' `label' `rawdata', `keep' `sortby' /*
|
|
*/ `table' method(`method') sumstat(RD) `xlabel' `xtick'`force' `graph' `box' /*
|
|
*/ `saving' t1("`t1'") t2("`t2'") b1("`b1'") b2("`b2'") lcols("`lcols'") rcols("`rcols'") /*
|
|
*/ `rjhsecond' `overall' `wt' `stats' `counts' `udwind'
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
program define MD
|
|
|
|
version 9.0
|
|
|
|
#delimit ;
|
|
|
|
syntax varlist(min=6 max=6 default=none numeric) [if] [in] [,
|
|
LABEL(string) SORTBY(passthru) noGRAPH METHOD(string) noKEEP SAVING(passthru) noBOX
|
|
noTABLE STANDARD(string) XLAbel(passthru) XTICK(passthru) FORCE T1(string) T2(string)
|
|
B1(string) B2(string) LCOLS(string) RCOLS(string) noOVERALL noWT noSTATS COUNTS WGT(string) RJHSECOND ] ;
|
|
|
|
#delimit cr
|
|
|
|
qui {
|
|
|
|
tempvar n1 x1 sd1 n2 x2 sd2 use n s md v se ill iul weight id qhet rawdata
|
|
tokenize "`varlist'", parse(" ")
|
|
gen double `n1' =`1'
|
|
gen double `x1' =`2'
|
|
gen double `sd1'=`3'
|
|
gen double `n2' =`4'
|
|
gen double `x2' =`5'
|
|
gen double `sd2'=`6'
|
|
|
|
gen `use'=1 `if' `in'
|
|
|
|
replace `use'=9 if `use'==.
|
|
replace `use'=9 if (`n1'==.) | (`n2'==.) | (`x1'==.) | (`x2'==.) | /*
|
|
*/ (`sd1'==.) | (`sd2'==.)
|
|
replace `use'=2 if ( `use'==1) & (`n1' <2 | `n2' <2 )
|
|
replace `use'=2 if ( `use'==1) & (`sd1'<=0 | `sd2'<=0 )
|
|
count if `use'==1
|
|
global S_8 =r(N)-1
|
|
|
|
if $S_8<0 {
|
|
exit
|
|
}
|
|
|
|
if "`counts'"!="" {
|
|
*Display raw counts instead of default
|
|
gen `rawdata'= string(`n1') + ", " + string(`x1',"%7.3g") +" (" + string(`sd1',"%7.3g") + /*
|
|
*/ ") ; " + string(`n2') + ", " + string(`x2',"%7.3g") +" (" + string(`sd2',"%7.3g") +") "
|
|
replace `rawdata'= trim(`rawdata')
|
|
qui summ `n1'
|
|
local sum1 = r(sum)
|
|
qui summ `n2'
|
|
local sum2 = r(sum)
|
|
global MA_ODC = string(`sum1') + "; " + string(`sum2')
|
|
}
|
|
else {
|
|
gen str1 `rawdata'="."
|
|
} /* end counts */
|
|
|
|
if "`method'"=="D+L" & ($S_8==0) {
|
|
local method "I-V"
|
|
}
|
|
|
|
replace `n1' =. if `use'!=1
|
|
replace `x1' =. if `use'!=1
|
|
replace `sd1'=. if `use'!=1
|
|
replace `n2' =. if `use'!=1
|
|
replace `x2' =. if `use'!=1
|
|
replace `sd2'=. if `use'!=1
|
|
gen double `n' =`n1'+`n2'
|
|
|
|
if "`standard'"=="none" {
|
|
gen double `md' =`x1'-`x2'
|
|
gen double `v'=(`sd1'^2)/`n1' + (`sd2'^2)/`n2'
|
|
local prefix "W"
|
|
}
|
|
else {
|
|
gen double `s'=sqrt( ((`n1'-1)*(`sd1'^2)+(`n2'-1)*(`sd2'^2) )/(`n'-2) )
|
|
if "`standard'"=="cohen" {
|
|
gen double `md' = (`x1'-`x2')/`s'
|
|
gen double `v'= ( `n'/(`n1'*`n2') )+( (`md'^2)/(2*(`n'-2)) )
|
|
}
|
|
else if "`standard'"=="hedges" {
|
|
gen double `md' =( (`x1'-`x2')/`s' )*( 1- 3/(4*`n'-9) )
|
|
gen double `v'=( `n'/(`n1'*`n2') ) + ( (`md'^2)/(2*(`n'-3.94)) )
|
|
}
|
|
else if "`standard'"=="glass" {
|
|
gen double `md' = (`x1'-`x2')/`sd2'
|
|
gen double `v'= (`n'/(`n1'*`n2')) + ( (`md'^2)/(2*(`n2'-1)) )
|
|
}
|
|
local prefix "S"
|
|
}
|
|
|
|
gen double `se' =sqrt(`v')
|
|
gen double `ill' =`md'-$ZIND*`se'
|
|
gen double `iul' =`md'+$ZIND*`se'
|
|
if "`wgt'"!="" {
|
|
udw `md' `v' , wgt(`wgt')
|
|
gen `weight'=`wgt'*100/$MA_W
|
|
local udwind "wgt(`wgt')"
|
|
}
|
|
|
|
else {
|
|
iv `md' `v', method(`method') randomi
|
|
gen `weight'=100/( (`v'+$S_12)*($MA_W) )
|
|
}
|
|
|
|
|
|
if "`method'" == "USER"{
|
|
forvalues i = 1/15{
|
|
global S_`i' = .
|
|
}
|
|
cap drop `weight'
|
|
gen `weight'=.
|
|
if "`rjhsecond'" != ""{
|
|
global S_1 = $MA_userES
|
|
global S_3 = $MA_userCIlow
|
|
global S_4 = $MA_userCIupp
|
|
}
|
|
else{
|
|
global S_1 = $MA_userESM
|
|
global S_3 = $MA_userCIlowM
|
|
global S_4 = $MA_userCIuppM
|
|
}
|
|
}
|
|
replace `weight'=0 if `weight'==.
|
|
|
|
} /* End of quietly loop */
|
|
|
|
|
|
_disptab `md' `se' `ill' `iul' `weight' `use' `label' `rawdata', `keep' `sortby' /*
|
|
*/ `table' method(`method') sumstat(`prefix'MD) `xlabel' `xtick' `force' `graph' /*
|
|
*/ `box' `saving' t1("`t1'") t2("`t2'") b1("`b1'") b2("`b2'") lcols("`lcols'") rcols("`rcols'") /*
|
|
*/ `rjhsecond' `overall' `wt' `stats' `udwind' `counts'
|
|
|
|
end
|
|
|
|
|
|
|
|
program define iv_init
|
|
|
|
version 9.0
|
|
|
|
#delimit ;
|
|
|
|
syntax varlist(min=2 max=3 default=none numeric) [if] [in] [,
|
|
LABEL(string) SORTBY(passthru) noGRAPH METHOD(string) noKEEP SAVING(passthru) noBOX
|
|
noTABLE XLAbel(passthru) XTICK(passthru) FORCE T1(string) T2(string) B1(string)
|
|
B2(string) LCOLS(string) RCOLS(string) noOVERALL noWT noSTATS EFORM WGT(string) RJHSECOND ] ;
|
|
|
|
#delimit cr
|
|
|
|
qui {
|
|
|
|
tempvar es se use v ill iul weight id rawdata
|
|
tokenize "`varlist'", parse(" ")
|
|
gen `es'=`1'
|
|
if "`eform'"!="" {
|
|
local exp "exp"
|
|
}
|
|
|
|
if "`3'"=="" {
|
|
gen double `se'=`2'
|
|
gen double `ill' =`exp'(`es'-$ZIND*`se' )
|
|
gen double `iul' =`exp'(`es'+$ZIND*`se' )
|
|
}
|
|
|
|
if "`3'"!="" {
|
|
gen double `se'=(`3'-`2')/($ZIND*2)
|
|
gen double `ill' =`exp'(`2')
|
|
gen double `iul' =`exp'(`3')
|
|
local var3 "var3"
|
|
}
|
|
|
|
gen double `use'=1 `if' `in'
|
|
replace `use'=9 if `use'==.
|
|
replace `use'=9 if (`es'==. | `se'==.)
|
|
replace `use'=2 if (`use'==1 & `se'<=0 )
|
|
count if `use'==1
|
|
global S_8 =r(N)-1
|
|
|
|
if $S_8<0 {
|
|
exit
|
|
}
|
|
|
|
if "`method'"=="D+L" & ($S_8==0) {
|
|
local method "I-V"
|
|
}
|
|
|
|
replace `es' =. if `use'!=1
|
|
replace `se' =. if `use'!=1
|
|
gen double `v'=(`se')^2
|
|
gen str1 `rawdata'="."
|
|
|
|
if "`wgt'"!=""{
|
|
cap drop `weight'
|
|
gen `weight' = `wgt' if `use'==1
|
|
udw `es' `v', wgt(`weight') `exp' `rjhsecond'
|
|
replace `weight'=100*`wgt'/($MA_W)
|
|
local udwind "wgt(`wgt')"
|
|
}
|
|
else {
|
|
iv `es' `v', method(`method') `exp' randomi `rjhsecond'
|
|
*NB randomi necc to calculate heterogeneity
|
|
gen `weight'=100/( (`v'+$S_12)*($MA_W) )
|
|
}
|
|
|
|
|
|
replace `weight'=0 if `weight'==.
|
|
replace `es'=`exp'(`es')
|
|
|
|
} /* End of quietly loop */
|
|
|
|
_disptab `es' `se' `ill' `iul' `weight' `use' `label' `rawdata', `keep' `sortby' /*
|
|
*/`table' method(`method') sumstat(ES) `xlabel' `xtick' `force' `graph' `box' /*
|
|
*/ `saving' t1("`t1'") t2("`t2'") b1("`b1'") b2("`b2'") lcols("`lcols'") rcols("`rcols'") `overall' `wt' `stats' `eform' /*
|
|
*/ `var3' `udwind' `rjhsecond'
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
program define iv
|
|
|
|
version 9.0
|
|
|
|
#delimit ;
|
|
|
|
syntax varlist(min=2 max=2 default=none numeric) [if] [in] [,
|
|
METHOD(string) RANDOMI EXP RJHSECOND ] ;
|
|
|
|
#delimit cr
|
|
|
|
tempvar stat v w qhet w2 wnew e_w e_wnew
|
|
tempname W W2 C T2 E_W E_WNEW OV vOV QHET
|
|
|
|
tokenize "`varlist'", parse(" ")
|
|
gen `stat'=`1'
|
|
gen `v' =`2'
|
|
gen `w' =1/`v'
|
|
sum `w',meanonly
|
|
scalar `W'=r(sum)
|
|
global S_12=0
|
|
global MA_W =`W'
|
|
|
|
if ("`randomi'"=="" & "`method'"=="D+L") {
|
|
scalar `QHET'=$S_7
|
|
}
|
|
else {
|
|
gen `e_w' =`stat'*`w'
|
|
sum `e_w',meanonly
|
|
scalar `E_W'=r(sum)
|
|
scalar `OV' =`E_W'/`W'
|
|
|
|
* Heterogeneity
|
|
gen `qhet' =( (`stat'-`OV')^2 )/`v'
|
|
sum `qhet', meanonly
|
|
scalar `QHET'=r(sum)
|
|
global S_7=`QHET'
|
|
}
|
|
|
|
if "`method'"=="D+L" {
|
|
gen `w2' =`w'*`w'
|
|
sum `w2',meanonly
|
|
scalar `W2' =r(sum)
|
|
scalar `C' =`W' - `W2'/`W'
|
|
global S_12 =max(0, ((`QHET'-$S_8)/`C') )
|
|
global RJH_TAU2 = $S_12
|
|
gen `wnew' =1/(`v'+$S_12)
|
|
gen `e_wnew'=`stat'*`wnew'
|
|
sum `wnew',meanonly
|
|
global MA_W =r(sum)
|
|
sum `e_wnew',meanonly
|
|
scalar `E_WNEW'=r(sum)
|
|
scalar `OV' =`E_WNEW'/$MA_W
|
|
}
|
|
|
|
|
|
global S_1 =`exp'(`OV')
|
|
global S_2 =sqrt( 1/$MA_W )
|
|
global S_3 =`exp'(`OV' -$ZOVE*($S_2))
|
|
global S_4 =`exp'(`OV' +$ZOVE*($S_2))
|
|
global S_5 =abs(`OV')/($S_2)
|
|
global S_6 =normprob(-abs($S_5))*2
|
|
global S_9 =chiprob($S_8,$S_7)
|
|
global S_51 =max(0, ( 100*($S_7-$S_8))/($S_7) )
|
|
|
|
if "`method'" == "USER"{
|
|
forvalues i = 1/15{
|
|
global S_`i' = .
|
|
}
|
|
cap drop `weight'
|
|
tempvar weight
|
|
gen `weight'=.
|
|
if "`rjhsecond'" != ""{
|
|
global S_1 = $MA_userES
|
|
global S_3 = $MA_userCIlow
|
|
global S_4 = $MA_userCIupp
|
|
}
|
|
else{
|
|
global S_1 = $MA_userESM
|
|
global S_3 = $MA_userCIlowM
|
|
global S_4 = $MA_userCIuppM
|
|
}
|
|
}
|
|
end
|
|
|
|
|
|
program define udw
|
|
|
|
* user defined weights to combine trials
|
|
|
|
version 9.0
|
|
#delimit ;
|
|
|
|
syntax varlist(min=2 max=2 default=none numeric) [if] [in] [,
|
|
METHOD(string) EXP WGT(varlist numeric max=1) RJHSECOND ] ;
|
|
|
|
#delimit cr
|
|
tempvar stat v w e_w varcomp qhet
|
|
tempname W E_W OV W2 Vnum V QHET
|
|
|
|
tokenize "`varlist'", parse(" ")
|
|
gen `stat'=`1'
|
|
gen `v' =`2'
|
|
gen `w' =`wgt' if `stat'!=.
|
|
sum `w',meanonly
|
|
scalar `W'=r(sum)
|
|
if `W'==0 {
|
|
di as err "Usable weights sum to zero: the table below will probably be nonsense"
|
|
}
|
|
|
|
global MA_W =`W'
|
|
|
|
*eff size = SIGMA(wi * thetai)/SIGMA(wi)
|
|
gen `e_w' =`stat'*`w'
|
|
sum `e_w',meanonly
|
|
scalar `E_W'=r(sum)
|
|
scalar `OV' =`E_W'/`W'
|
|
|
|
*VAR = SIGMA{wi^2 * var(thetai) }/[SIGMA(wi)]^2
|
|
sum `w',meanonly
|
|
scalar `W2'=(r(sum))^2
|
|
gen `varcomp' = `w'*`w'*`v'
|
|
sum `varcomp' ,meanonly
|
|
scalar `Vnum'=r(sum)
|
|
scalar `V' =`Vnum'/`W2'
|
|
|
|
*Heterogeneity (need to use variance weights here - BUT use ES=wgt*es/wgt, not necc var wts)
|
|
gen `qhet' =( (`stat'-`OV')^2 )/`v'
|
|
sum `qhet', meanonly
|
|
scalar `QHET'=r(sum)
|
|
|
|
global S_1 =`exp'(`OV')
|
|
global S_2 =sqrt( `V' )
|
|
global S_3 =`exp'(`OV' -$ZOVE*($S_2))
|
|
global S_4 =`exp'(`OV' +$ZOVE*($S_2))
|
|
global S_5 =abs(`OV')/($S_2)
|
|
global S_6 =normprob(-abs($S_5))*2
|
|
global S_7=`QHET'
|
|
global S_9 =chiprob($S_8,$S_7)
|
|
global S_51 =max(0, ( 100*($S_7-$S_8))/($S_7) )
|
|
|
|
if "$MA_method1" == "USER"{
|
|
cap drop `weight'
|
|
tempvar weight
|
|
gen `weight'=.
|
|
forvalues i = 1/15{
|
|
global S_`i' = .
|
|
}
|
|
if "`rjhsecond'" != ""{
|
|
global S_1 = $MA_userES
|
|
global S_3 = $MA_userCIlow
|
|
global S_4 = $MA_userCIupp
|
|
}
|
|
else{
|
|
global S_1 = $MA_userESM
|
|
global S_3 = $MA_userCIlowM
|
|
global S_4 = $MA_userCIuppM
|
|
}
|
|
global S_8 = 0
|
|
}
|
|
|
|
end
|
|
|
|
|
|
program define _disptab
|
|
|
|
version 9.0
|
|
|
|
#delimit ;
|
|
|
|
syntax varlist(min=7 max=8 default=none) [if] [in] [,
|
|
XLAbel(passthru) XTICK(passthru) FORCE noKEEP SAVING(passthru) noBOX noTABLE
|
|
noGRAPH METHOD(string) SUMSTAT(string) CHI2 T1(string) T2(string) B1(string)
|
|
B2(string) LCOLS(string) RCOLS(string) noOVERALL noWT noSTATS COUNTS LOG EFORM noGROUPLA SORTBY(string)
|
|
WGT(string) VAR3 CORNFIELD /* RJH */ RJHSECOND ] ;
|
|
|
|
#delimit cr
|
|
|
|
tempvar effect se lci uci weight use label tlabel rawdata id tau2 df
|
|
tokenize "`varlist'", parse(" ")
|
|
|
|
qui {
|
|
|
|
gen `effect'=`1'
|
|
gen `se' =`2'
|
|
gen `lci' =`3'
|
|
gen `uci' =`4'
|
|
gen `weight'=`5'
|
|
gen byte `use'=`6'
|
|
format `weight' %5.1f
|
|
gen str10 `label'=""
|
|
replace `label'=`7'
|
|
global IND: displ %2.0f $IND
|
|
gen `rawdata' = `8'
|
|
gen `tau2' = .
|
|
gen `df' = .
|
|
|
|
if "`keep'"=="" {
|
|
|
|
if ("`sumstat'"=="OR" | "`sumstat'"=="RR") & ("`log'"=="") {
|
|
local ln "log"
|
|
}
|
|
else {
|
|
local ln
|
|
}
|
|
|
|
cap drop _ES
|
|
cap drop _seES
|
|
cap drop _selogES
|
|
|
|
if "`sumstat'"!="ES" {
|
|
replace _SS =. if `use'!=1
|
|
label var _SS "Sample size"
|
|
gen _ES =`effect'
|
|
label var _ES "`log'`sumstat'"
|
|
gen _se`ln'ES=`se'
|
|
label var _se`ln'ES "se(`ln'`log'`sumstat')"
|
|
}
|
|
|
|
cap drop _LCI
|
|
cap drop _UCI
|
|
cap drop _WT
|
|
gen _LCI =`lci'
|
|
label var _LCI "Lower CI (`log'`sumstat')"
|
|
gen _UCI =`uci'
|
|
label var _UCI "Upper CI (`log'`sumstat')"
|
|
gen _WT=`weight'
|
|
label var _WT "`method' weight"
|
|
|
|
} /* end if-keep */
|
|
|
|
preserve
|
|
|
|
if "`overall'"=="" & "`rjhsecond'" == ""{ // only do this on main run
|
|
|
|
**If overall figure requested, add an extra line to contain overall stats
|
|
|
|
local nobs1=_N+1
|
|
set obs `nobs1'
|
|
replace `weight'=100 in `nobs1'
|
|
replace `effect'= ($S_1) in `nobs1'
|
|
replace `lci'=($S_3) in `nobs1'
|
|
replace `uci'=($S_4) in `nobs1'
|
|
replace `use'=5 in `nobs1'
|
|
replace `tau2' = $S_12 in `nobs1'
|
|
replace `df' = $S_8 in `nobs1'
|
|
|
|
if "`counts'"!="" {
|
|
replace `rawdata'="$MA_ODC" in `nobs1'
|
|
}
|
|
local i2=max(0, (100*($S_7-$S_8)/($S_7)) )
|
|
local hetp=$S_9
|
|
replace `label' = "Overall (I-squared = " + string(`i2', "%5.1f")+ "%, p = " + ///
|
|
string(`hetp', "%5.3f") + ")" in `nobs1'
|
|
|
|
* RJH code for second method
|
|
if "$MA_method2" != "" {
|
|
local nobs1=_N+1
|
|
set obs `nobs1'
|
|
replace `weight'=100 in `nobs1'
|
|
replace `effect'= $MA_second_ES in `nobs1'
|
|
replace `lci'=$MA_second_LCI in `nobs1'
|
|
replace `uci'=$MA_second_UCI in `nobs1'
|
|
replace `use'=17 in `nobs1'
|
|
if "$MA_second_TAU2" != ""{
|
|
replace `tau2' = $MA_second_TAU2 in `nobs1'
|
|
replace `df' = $MA_second_DF in `nobs1'
|
|
}
|
|
replace `label' = "Overall" in `nobs1'
|
|
}
|
|
|
|
} /* end overall stuff */
|
|
|
|
local usetot=$S_8+1
|
|
count if `use'==2
|
|
local alltot=r(N)+`usetot'
|
|
gen `id'=_n
|
|
|
|
tempvar rjhorder
|
|
qui gen `rjhorder' = `use'
|
|
qui replace `rjhorder' = 3.5 if `use' == 19 // SWAP ROUND SO BLANK IN RIGHT PLACE
|
|
sort `rjhorder' `sortby' `id'
|
|
|
|
|
|
} /* End of quietly loop */
|
|
|
|
|
|
if "`table'"=="" {
|
|
|
|
qui gen str20 `tlabel'=`7' /*needs to be own label so as not to overrun!*/
|
|
|
|
if "`overall'`wt'"=="" {
|
|
local ww "% Weight"
|
|
}
|
|
|
|
if $IND!=$OVE {
|
|
global OVE: displ %2.0f $OVE
|
|
local insert "[$OVE% Conf. Interval]"
|
|
}
|
|
else {
|
|
local insert "--------------------"
|
|
}
|
|
|
|
di _n in gr _col(12) "Study" _col(22) "|" _col(24) "`log'" _col(28) "`sumstat'" /*
|
|
*/ _col(34) "[$IND% Conf. Interval]" _col(59) "`ww'" _n _dup(21) "-" "+" _dup(51) "-"
|
|
|
|
|
|
local i=1
|
|
while `i'<=_N { // BEGIN WHILE LOOP
|
|
|
|
if "`overall'`wt'"=="" {
|
|
local ww=`weight'[`i']
|
|
}
|
|
else {
|
|
local ww
|
|
}
|
|
if (`use'[`i'])==2 {
|
|
*excluded trial
|
|
di in gr `tlabel'[`i'] _col(22) "| (Excluded)"
|
|
}
|
|
|
|
* IF NORMAL TRIAL, OR OVERALL EFFECT
|
|
if ( (`use'[`i']==1) | (`use'[`i']==5) | `use'[`i'] == 17 ) {
|
|
if (`use'[`i'])==1 {
|
|
*trial results
|
|
di in gr `tlabel'[`i'] _cont
|
|
}
|
|
else {
|
|
*overall
|
|
// RJH
|
|
if `use'[`i'] == 5 {
|
|
local dispM1 = "$MA_method1"
|
|
if "$MA_method1" == "USER"{
|
|
local dispM1 = "$MA_userDescM"
|
|
}
|
|
di in gr _dup(21) "-" "+" _dup(11) "-" "`insert'" _dup(20) "-" _n /*
|
|
*/ "`dispM1' pooled `log'`sumstat'" _cont
|
|
}
|
|
if `use'[`i'] == 17{ // SECOND EST
|
|
local dispM2 = "$MA_method2"
|
|
if "$MA_method2" == "USER"{
|
|
local dispM2 = "$MA_userDesc"
|
|
}
|
|
di in gr "`dispM2' pooled `log'`sumstat'" _cont
|
|
}
|
|
} // end else
|
|
|
|
di in gr _col(22) "|" in ye %7.3f `effect'[`i'] /*
|
|
*/ _col(35) %7.3f `lci'[`i'] " " %7.3f `uci'[`i'] _col(60) %6.2f `ww'
|
|
}
|
|
local i=`i'+1
|
|
|
|
} /* END WHILE */
|
|
|
|
di in gr _dup(21) "-" "+" _dup(51) "-"
|
|
|
|
if "`overall'"=="" & "$MA_method1" != "USER"{
|
|
|
|
if ("`method'"=="*" | "`var3'"!="") {
|
|
|
|
if "`method'"=="*" {
|
|
di in gr "* note: trials pooled by user defined weight `wgt'"
|
|
}
|
|
|
|
di in gr " Heterogeneity calculated by formula" _n /*
|
|
*/ " Q = SIGMA_i{ (1/variance_i)*(effect_i - effect_pooled)^2 } "
|
|
|
|
if "`var3'"!="" {
|
|
di in gr "where variance_i = ((upper limit - lower limit)/(2*z))^2 "
|
|
}
|
|
|
|
}
|
|
|
|
*Heterogeneity etc
|
|
if ( ("`sumstat'"=="OR" | "`sumstat'"=="RR") & "`log'"=="") {
|
|
local h0=1
|
|
}
|
|
else if ("`sumstat'"=="ES" & "`eform'"!="") {
|
|
local h0=1
|
|
}
|
|
else {
|
|
local h0=0
|
|
}
|
|
|
|
di _n in gr " Heterogeneity chi-squared = " in ye %6.2f $S_7 in gr /*
|
|
*/ " (d.f. = " in ye $S_8 in gr ") p = " in ye %4.3f $S_9
|
|
local i2=max(0, (100*($S_7-$S_8)/($S_7)) )
|
|
if $S_8<1 {
|
|
local i2=.
|
|
}
|
|
di in gr " I-squared (variation in `sumstat' attributable to " /*
|
|
*/ "heterogeneity) =" in ye %6.1f `i2' "%"
|
|
|
|
if "`method'"=="D+L" {
|
|
di in gr " Estimate of between-study variance " /*
|
|
*/ "Tau-squared = " in ye %7.4f $S_12
|
|
}
|
|
|
|
if "`chi2'"!="" {
|
|
di _n in gr " Test of OR=1: chi-squared = " in ye %4.2f /*
|
|
*/ $S_10 in gr " (d.f. = 1) p = " in ye %4.3f $S_11
|
|
}
|
|
else {
|
|
di _n in gr " Test of `log'`sumstat'=`h0' : z= " in ye %6.2f $S_5 /*
|
|
*/ in gr " p = " in ye %4.3f $S_6
|
|
}
|
|
}
|
|
|
|
*capture only 1 trial scenario
|
|
|
|
qui {
|
|
count
|
|
|
|
if r(N)==1 {
|
|
set obs 2
|
|
replace `use'=99 in 2
|
|
replace `weight'=0 if `use'==99
|
|
}
|
|
|
|
} /*end of qui. */
|
|
|
|
} // end if table
|
|
|
|
if "`graph'"=="" & `usetot'>0 {
|
|
|
|
qui drop if `use' == 9
|
|
|
|
|
|
_dispgby `effect' `lci' `uci' `weight' `use' `label' `rawdata' `tau2' `df', `log' /*
|
|
*/ `xlabel' `xtick' `force' sumstat(`sumstat') `saving' `box' t1("`t1'") /*
|
|
*/ t2("`t2'") b1("`b1'") b2("`b2'") lcols("`lcols'") rcols("`rcols'") `overall' `wt' `stats' `counts' `eform' /*
|
|
*/ `groupla' `cornfield'
|
|
|
|
}
|
|
|
|
|
|
restore
|
|
|
|
end
|
|
|
|
|
|
program define metanby
|
|
|
|
version 9.0
|
|
|
|
#delimit ;
|
|
|
|
syntax varlist(min=2 max=6 default=none numeric) [if] [in] [, BY(string)
|
|
LABEL(string) SORTBY(string) noGRAPH noTABLE noKEEP NEXTCALL(string)
|
|
METHOD(string) METHOD2(string) SUMSTAT(string) RANDOMI WGT(passthru) noSUBGROUP SGWEIGHT
|
|
CORNFIELD CHI2 CC(passthru) STANDARD(passthru) noOVERALL LOG EFORM BRESLOW
|
|
XLAbel(passthru) XTICK(passthru) FORCE SAVING(passthru) T1(string) T2(string)
|
|
B1(string) B2(string) LCOLS(string) RCOLS(string) noWT noSTATS COUNTS noBOX noGROUPLA NOSECSUB ] ;
|
|
|
|
#delimit cr
|
|
|
|
if ("`subgroup'"!="" & "`overall'`sgweight'"!="") {
|
|
local wt "nowt"
|
|
}
|
|
|
|
tempvar use by2 newby r1 r2 rawdata effect se lci uci weight wtdisp /*
|
|
*/ hetc hetdf hetp i2 tau2 df tsig psig expand tlabel id
|
|
|
|
qui {
|
|
|
|
gen `use'=1 `if' `in'
|
|
replace `use'=9 if `use'==.
|
|
|
|
gen str1 `rawdata'="."
|
|
|
|
tokenize `varlist'
|
|
|
|
if ("`nextcall'"=="RR" | "`nextcall'"=="OR" | "`nextcall'"=="RD" |"`nextcall'"=="Peto" ) {
|
|
|
|
*Sort out r1 & r2 for 2x2 table: might be needed in counts and mh/use
|
|
gen `r1' = `1'+`2'
|
|
gen `r2' = `3'+`4'
|
|
replace `use'=2 if ((`use'==1) & (`r1'==0 | `r2'==0 ))
|
|
replace `use'=2 if ((`use'==1) & ((`1'+`3'==0) | (`2'+`4'==0) ) & "`nextcall'"!="RD")
|
|
replace `use'=9 if (`r1'==.) | (`r2'==.)
|
|
|
|
if "`counts'"!="" {
|
|
*create new variable with count data (if requested)
|
|
replace `rawdata'= trim( string(`1') + "/" + string(`r1') +";" + /*
|
|
*/ string(`3') + "/"+ string(`r2') ) if `use'!=9
|
|
}
|
|
|
|
}
|
|
|
|
if "`nextcall'"=="MD" {
|
|
|
|
*Sort out n1 & n2
|
|
replace `use'=9 if (`1'==.) | (`2'==.) | (`3'==.) | (`4'==.) | (`5'==.) | (`6'==.)
|
|
replace `use'=2 if ( `use'==1) & (`1' <2 | `4' <2 )
|
|
replace `use'=2 if ( `use'==1) & (`3'<=0 | `6'<=0 )
|
|
|
|
if "`counts'"!="" {
|
|
replace `rawdata'= string(`1') + ", " + string(`2',"%7.3g") +" (" + string(`3',"%7.3g") + /*
|
|
*/ ") ; " + string(`4') + ", " + string(`5',"%7.3g") +" (" + string(`6',"%7.3g") +") "
|
|
replace `rawdata'= trim(`rawdata') if `use' != 9
|
|
}
|
|
}
|
|
|
|
if "`nextcall'"=="iv_init" {
|
|
replace `use'=9 if (`1'==. | `2'==.)
|
|
if "`3'"=="" {
|
|
replace `use'=2 if (`use'==1 & `2'<=0 )
|
|
}
|
|
else {
|
|
replace `use'=9 if (`3'==.)
|
|
replace `use'=2 if ( `2'>`1' | `3'<`1' | `3'<`2')
|
|
}
|
|
}
|
|
|
|
if (("`sumstat'"=="OR" | "`sumstat'"=="RR") & "`log'"=="" ) {
|
|
local h0=1
|
|
}
|
|
else if ("`sumstat'"=="ES" & "`eform'"!="") {
|
|
local h0=1
|
|
}
|
|
else {
|
|
local h0=0
|
|
}
|
|
|
|
|
|
if "`eform'"!="" {
|
|
local exp "exp"
|
|
}
|
|
|
|
|
|
*RJH- second estimate
|
|
|
|
if "`method2'" != ""{
|
|
|
|
`nextcall' `varlist' if `use'==1, nograph notable method(`method2') `randomi' /*
|
|
*/ label(`label') `wgt' `cornfield' `chi2' `cc' `standard' `log' `eform' `breslow' rjhsecond
|
|
|
|
global MA_second_ES = $S_1 // KEEP ESTIMATES AND STICK IN SOMEWHERE LATER
|
|
global MA_second_SE_ES = $S_2
|
|
global MA_second_LCI = $S_3
|
|
global MA_second_UCI = $S_4
|
|
global MA_second_TAU2 = $S_12
|
|
global MA_second_DF = $S_8
|
|
|
|
}
|
|
|
|
*Get the individual trial stats
|
|
`nextcall' `varlist' if `use'==1, nograph notable method(`method') `randomi' /*
|
|
*/ label(`label') `wgt' `cornfield' `chi2' `cc' `standard' `log' `eform' `breslow'
|
|
|
|
if $S_8<0 {
|
|
*no trials - bomb out
|
|
exit
|
|
}
|
|
|
|
local nostud=$S_8
|
|
|
|
|
|
*need to calculate from variable itself if only 2 variables (ES, SE(ES) syntax used)
|
|
if "`sumstat'"=="ES" {
|
|
gen `effect'=`exp'(`1')
|
|
if "`3'"=="" {
|
|
gen `se'=`2'
|
|
}
|
|
else {
|
|
gen `se'=.
|
|
local var3 "var3"
|
|
}
|
|
}
|
|
else {
|
|
gen `effect'=_ES
|
|
if `h0'<0.01 {
|
|
gen `se'=_seES
|
|
}
|
|
else {
|
|
gen `se'=_selogES
|
|
}
|
|
}
|
|
|
|
gen `lci'=_LCI
|
|
gen `uci'=_UCI
|
|
gen `weight'=_WT
|
|
|
|
*put overall weight into var if requested
|
|
if ("`sgweight'"=="" & "`overall'"=="" ) {
|
|
gen `wtdisp'=_WT
|
|
}
|
|
else {
|
|
gen `wtdisp'=.
|
|
}
|
|
|
|
gen `id'=_n
|
|
|
|
*Convert "by" variable to string
|
|
* modified July 2008- keeps original order if by variable is numeric (was ignored before)
|
|
cap confirm numeric var `by'
|
|
if _rc == 0{
|
|
tempvar by_num
|
|
cap decode `by', gen(`by_num')
|
|
if _rc != 0{
|
|
local f: format `by'
|
|
gen `by_num' = string(`by', "`f'")
|
|
}
|
|
qui drop `by'
|
|
rename `by_num' `by'
|
|
}
|
|
cap confirm numeric var `by'
|
|
|
|
* This replaces the old encode statement
|
|
* The _by variable is generated according to the original
|
|
* sort order of the data, and not done alpha-numerically
|
|
|
|
qui count
|
|
local N = r(N)
|
|
gen `by2' = 1 in 1
|
|
local lab = `by'[1]
|
|
cap label drop bylab
|
|
label define bylab 1 "`lab'"
|
|
local found1 "`lab'"
|
|
local max = 1
|
|
forvalues i = 2/`N'{
|
|
|
|
local thisval = `by'[`i']
|
|
local already = 0
|
|
forvalues j = 1/`max'{
|
|
if "`thisval'" == "`found`j''"{
|
|
local already = `j'
|
|
}
|
|
}
|
|
if `already' > 0{
|
|
replace `by2' = `already' in `i'
|
|
}
|
|
else{
|
|
local max = `max' + 1
|
|
replace `by2' = `max' in `i'
|
|
local lab = `by'[`i']
|
|
label define bylab `max' "`lab'", modify
|
|
local found`max' "`lab'"
|
|
}
|
|
}
|
|
|
|
label values `by2' bylab
|
|
|
|
|
|
|
|
*Keep only neccesary data (have to put preserve here in order to keep _ES etc)
|
|
preserve
|
|
|
|
sort `by2' `sortby' `id'
|
|
qui drop if `use' == 9
|
|
|
|
*Can now forget about the if/in conditions specified: unnecc rows have been removed
|
|
|
|
*Keep tger and cger here (otherwise it ends up in last subgroup only)
|
|
if ("`sumstat'"=="OR" | "`sumstat'"=="RR" | "`sumstat'"=="RD" ) {
|
|
local tger=$S_13
|
|
local cger=$S_14
|
|
}
|
|
|
|
*subgroup component of heterogeneity
|
|
gen `hetc'=.
|
|
gen `hetdf'=.
|
|
gen `hetp'=.
|
|
gen `i2'=.
|
|
gen `tau2'=.
|
|
gen `df' = .
|
|
gen `tsig'=.
|
|
gen `psig'=.
|
|
|
|
|
|
*Create new "by" variable to take on codes 1,2,3..
|
|
gen `newby'=(`by2'>`by2'[_n-1])
|
|
replace `newby'=1+sum(`newby')
|
|
local ngroups=`newby'[_N]
|
|
|
|
if "`overall'"=="" {
|
|
|
|
*If requested, add an extra line to contain overall stats
|
|
local nobs1=_N+1
|
|
set obs `nobs1'
|
|
replace `use'=5 in `nobs1'
|
|
replace `newby'=`ngroups'+1 in `nobs1'
|
|
replace `effect'= ($S_1) in `nobs1'
|
|
replace `lci'=($S_3) in `nobs1'
|
|
replace `uci'=($S_4) in `nobs1'
|
|
*RJH plus another line if second estimate
|
|
if "`method2'" != ""{
|
|
local nobs2=_N+1
|
|
set obs `nobs2'
|
|
replace `use'=17 in `nobs2'
|
|
replace `newby'=`ngroups'+1 in `nobs2'
|
|
replace `effect'= ($MA_second_ES) in `nobs2'
|
|
replace `lci'=($MA_second_LCI) in `nobs2'
|
|
replace `uci'=($MA_second_UCI) in `nobs2'
|
|
if "`method2'" == "D+L"{
|
|
replace `tau2' = $MA_second_TAU2 in `nobs2'
|
|
replace `hetdf' = $MA_second_DF in `nobs2'
|
|
}
|
|
}
|
|
|
|
*Put cell counts in subtotal row
|
|
if ("`counts'"!="") {
|
|
if "`nextcall'"!="MD"{
|
|
*put up overall binary count data
|
|
sum `1' if (`use'==1 | `use'==2)
|
|
local sum1 =r(sum)
|
|
sum `r1' if (`use'==1 | `use'==2)
|
|
local sum2 =r(sum)
|
|
sum `3' if (`use'==1 | `use'==2)
|
|
local sum3 =r(sum)
|
|
sum `r2' if (`use'==1 | `use'==2)
|
|
local sum4 =r(sum)
|
|
replace `rawdata'= "`sum1'/`sum2';`sum3'/`sum4'" in `nobs1'
|
|
}
|
|
if "`nextcall'"=="MD" {
|
|
sum `1' if (`use'==1 | `use'==2)
|
|
local sum1 =r(sum)
|
|
sum `4' if (`use'==1 | `use'==2)
|
|
local sum2 =r(sum)
|
|
replace `rawdata'= "`sum1'; `sum2'" in `nobs1'
|
|
}
|
|
}
|
|
replace `hetc' =($S_7) in `nobs1'
|
|
replace `hetdf'=($S_8) in `nobs1'
|
|
replace `hetp' =($S_9) in `nobs1'
|
|
replace `i2'=max(0, ( 100*($S_7-$S_8))/($S_7) ) in `nobs1'
|
|
if $S_8<1 {
|
|
replace `i2'=. in `nobs1'
|
|
}
|
|
replace `tau2' = $S_12 in `nobs1'
|
|
replace `df' = $S_8 in `nobs1'
|
|
replace `se'=$S_2 in `nobs1'
|
|
if "`chi2'"!="" {
|
|
replace `tsig'=$S_10 in `nobs1'
|
|
replace `psig'=$S_11 in `nobs1'
|
|
local z=$S_5
|
|
local pz=$S_6
|
|
}
|
|
else {
|
|
replace `tsig'=$S_5 in `nobs1'
|
|
replace `psig'=$S_6 in `nobs1'
|
|
local echi2 =$S_10
|
|
local pchi2=$S_11
|
|
}
|
|
replace `label' = "Overall" in `nobs1'
|
|
if "`sgweight'"=="" {
|
|
replace `wtdisp'=100 in `nobs1'
|
|
}
|
|
|
|
} /* end if overall */
|
|
|
|
|
|
*Create extra 2 or 3 lines per bygroup: one to label, one for gap
|
|
*and one for overall effect size (unless no subgroup combining is done)
|
|
*RJH- add another line if SECOND sub estimates
|
|
|
|
sort `newby' `use' `sortby' `id'
|
|
|
|
by `newby': gen `expand'=1 + 2*(_n==1) + (_n==1 & "`subgroup'"=="") ///
|
|
+ (_n==1 & "`method2'"!="" & "`nosecsub'"=="")
|
|
replace `expand'=1 if `use'==5 | `use' == 17
|
|
expand `expand'
|
|
gsort `newby' -`expand' `use' `sortby' `id'
|
|
by `newby': replace `use'=0 if `expand'>1 & _n==2 /* row for by label */
|
|
by `newby': replace `use'=4 if `expand'>1 & _n==3 /* row for blank line */
|
|
by `newby': replace `use'=3 if `expand'>1 & _n==4 /* (if specified) row to hold subgp effect sizes */
|
|
by `newby': replace `use'=19 if `expand'>1 & _n==5 /* (if specified) RJH extra line for second estimate */
|
|
|
|
* blank out effect sizes in new rows
|
|
replace `effect'=. if `expand'>1 & `use'!=1
|
|
replace `lci'=. if `expand'>1 & `use'!=1
|
|
replace `uci'=. if `expand'>1 & `use'!=1
|
|
replace `weight' =. if `expand'>1 & `use'!=1
|
|
replace `rawdata' ="." if `expand'>1 & `use'!=1
|
|
|
|
|
|
*Perform subgroup analyses
|
|
|
|
local j=1
|
|
while `j'<=`ngroups' { // HUGE LOOP THROUGH EACH SUBGROUP
|
|
|
|
if "`subgroup'"=="" {
|
|
*First ensure the by() category has any data
|
|
count if (`newby'==`j' & `use'==1)
|
|
|
|
if r(N)==0 {
|
|
*No data in subgroup=> fill variables with missing and move on
|
|
replace `effect'=. if (`use'==3 & `newby'==`j')
|
|
replace `lci'=. if (`use'==3 & `newby'==`j')
|
|
replace `uci'=. if (`use'==3 & `newby'==`j')
|
|
replace `wtdisp'=0 if `newby'==`j'
|
|
replace `weight'=0 if `newby'==`j'
|
|
replace `hetc'=. if `newby'==`j'
|
|
replace `hetdf'=. if `newby'==`j'
|
|
replace `hetp'=. if `newby'==`j'
|
|
replace `i2'=. if `newby'==`j'
|
|
replace `tsig'=. if `newby'==`j'
|
|
replace `psig'=. if `newby'==`j'
|
|
replace `tau2'=. if `newby'==`j'
|
|
}
|
|
else {
|
|
|
|
/* SECOND SUB-ESTIMATES */
|
|
if "`method2'" != "" & "`nosecsub'" == ""{
|
|
`nextcall' `varlist' if (`newby'==`j' & `use'==1) , nograph /*
|
|
*/ notable label(`label') method(`method2') `randomi' `wgt' `cornfield' `chi2' /*
|
|
*/ `cc' `standard' `log' `eform' `breslow'
|
|
replace `effect'=($S_1) if `use'==19 & `newby'==`j'
|
|
replace `lci'=($S_3) if `use'==19 & `newby'==`j'
|
|
replace `uci'=($S_4) if `use'==19 & `newby'==`j'
|
|
replace `hetdf' = $S_8 if `use'==19 & `newby'==`j'
|
|
if "`method2'"=="D+L" {
|
|
replace `tau2' = $S_12 if `use'==19 & `newby'==`j'
|
|
}
|
|
}
|
|
|
|
/* THEN GET REGULAR ESTIMATES AS USUAL */
|
|
`nextcall' `varlist' if (`newby'==`j' & `use'==1) , nograph /*
|
|
*/ notable label(`label') method(`method') `randomi' `wgt' `cornfield' `chi2' /*
|
|
*/ `cc' `standard' `log' `eform' `breslow'
|
|
replace `effect'=($S_1) if `use'==3 & `newby'==`j'
|
|
replace `lci'=($S_3) if `use'==3 & `newby'==`j'
|
|
replace `uci'=($S_4) if `use'==3 & `newby'==`j'
|
|
|
|
*Put within-subg weights in if nooverall or sgweight options specified
|
|
if ("`overall'`sgweight'"!="" ) {
|
|
replace `wtdisp'=_WT if `newby'==`j'
|
|
replace `wtdisp'=100 if (`use'==3 & `newby'==`j')
|
|
}
|
|
else {
|
|
qui sum `wtdisp' if (`use'==1 & `newby'==`j')
|
|
replace `wtdisp'=r(sum) if (`use'==3 & `newby'==`j')
|
|
}
|
|
|
|
sum `weight' if `newby'==`j'
|
|
replace `weight'= r(sum) if `use'==3 & `newby'==`j'
|
|
replace `hetc' =($S_7) if `use'==3 & `newby'==`j'
|
|
replace `hetdf'=($S_8) if `use'==3 & `newby'==`j'
|
|
replace `hetp' =($S_9) if `use'==3 & `newby'==`j'
|
|
replace `i2'=max(0, ( 100*($S_7-$S_8))/($S_7) ) if `use'==3 & `newby'==`j'
|
|
|
|
if $S_8<1 {
|
|
replace `i2'=. if `use'==3 & `newby'==`j'
|
|
}
|
|
if "`chi2'"!="" {
|
|
replace `tsig'=($S_10) if `use'==3 & `newby'==`j'
|
|
replace `psig'=($S_11) if `use'==3 & `newby'==`j'
|
|
}
|
|
else {
|
|
replace `tsig'=($S_5) if `use'==3 & `newby'==`j'
|
|
replace `psig'=($S_6) if `use'==3 & `newby'==`j'
|
|
}
|
|
if "`method'"=="D+L" {
|
|
replace `tau2' = $S_12 if `use'==3 & `newby'==`j'
|
|
}
|
|
|
|
} /* END OF IF SUBGROUP N > 0 */
|
|
|
|
*Whether data or not - put cell counts in subtotal row if requested (will be 0/n1;0/n2 or blank if all use>1)
|
|
if "`counts'"!="" {
|
|
|
|
*don't put up anything for MDs:
|
|
*1 Cochrane just put up N_gi. Not sure whether weighted mean should be in..
|
|
*2 justifying N_gi is tedious!
|
|
if "`nextcall'"!="MD" {
|
|
sum `1' if (`use'==1 | `use'==2) & (`newby'==`j')
|
|
local sum1 =r(sum)
|
|
sum `r1' if (`use'==1 | `use'==2) & (`newby'==`j')
|
|
local sum2 =r(sum)
|
|
sum `3' if (`use'==1 | `use'==2) & (`newby'==`j')
|
|
local sum3 =r(sum)
|
|
sum `r2' if (`use'==1 | `use'==2) & (`newby'==`j')
|
|
local sum4 =r(sum)
|
|
replace `rawdata'= "`sum1'/`sum2';`sum3'/`sum4'" if (`use'==3 & `newby'==`j')
|
|
}
|
|
if "`nextcall'"=="MD" {
|
|
sum `1' if (`use'==1 | `use'==2) & (`newby'==`j')
|
|
local sum1 =r(sum)
|
|
sum `4' if (`use'==1 | `use'==2) & (`newby'==`j')
|
|
local sum2 =r(sum)
|
|
replace `rawdata'= "`sum1'; `sum2'" if (`use'==3 & `newby'==`j')
|
|
}
|
|
}
|
|
|
|
} /* END OF if "`subgroup'" == "" */
|
|
|
|
*Label attatched (if any) to byvar
|
|
|
|
local lbl: value label `by2'
|
|
sum `by2' if `newby'==`j'
|
|
local byvlu=r(mean)
|
|
|
|
if "`lbl'"=="" {
|
|
local lab "`by2'==`byvlu'"
|
|
}
|
|
else {
|
|
local lab: label `lbl' `byvlu'
|
|
}
|
|
|
|
replace `label' = "`lab'" if ( `use'==0 & `newby'==`j')
|
|
replace `label' = "Subtotal" if ( `use'==3 & `newby'==`j')
|
|
|
|
/* RMH I-squared added in next line
|
|
RJH- also p-val as recommended by Mike Bradburn */
|
|
|
|
replace `label' = "Subtotal (I-squared = " + string(`i2', "%5.1f")+ "%, p = " + ///
|
|
string(`hetp', "%5.3f") + ")" if ( `use'==3 & `newby'==`j' & "$MA_nohet" == "")
|
|
local j=`j'+1
|
|
|
|
} /* FINALLY, THE END OF THE WHILE LOOP! */
|
|
|
|
replace `label' = "Overall (I-squared = " + string(`i2', "%5.1f")+ "%, p = " + ///
|
|
string(`hetp', "%5.3f") + ")" if ( `use'==5 & "$MA_nohet" == "")
|
|
|
|
if "`subgroup'"==""{
|
|
qui sum `hetc' if `use' == 5
|
|
local rjhet = r(mean)
|
|
qui sum `hetc' if `use'==3
|
|
local btwghet = (`rjhet') -r(sum)
|
|
local df = `ngroups'-1
|
|
global rjhHetGrp = chiprob(`df',`btwghet')
|
|
}
|
|
|
|
} /*End of quietly loop*/
|
|
|
|
|
|
|
|
*Put table up (if requested)
|
|
|
|
tempvar rjhorder
|
|
qui gen `rjhorder' = `use'
|
|
qui replace `rjhorder' = 3.5 if `use' == 19 // SWAP ROUND SO BLANK IN RIGHT PLACE
|
|
sort `newby' `rjhorder' `sortby' `id'
|
|
|
|
// need to ditch this if SECOND specified
|
|
if "`subgroup'" != ""{
|
|
qui drop if `use' == 3 | `use' == 19
|
|
}
|
|
|
|
|
|
if "`table'"=="" {
|
|
qui gen str20 `tlabel'=`label'
|
|
if "`overall'`wt'"=="" {
|
|
local ww "% Weight"
|
|
}
|
|
di _n in gr _col(12) "Study" _col(22) "|" _col(24) "`log'" _col(28) "`sumstat'" /*
|
|
*/ _col(34) "[$IND% Conf. Interval]" _col(59) "`ww'"
|
|
di _dup(21) "-" "+" _dup(51) "-"
|
|
|
|
|
|
*legend for pooled confidence intervals
|
|
|
|
local i=1
|
|
while `i'<= _N {
|
|
|
|
if (`use'[`i'])==0 {
|
|
*by label
|
|
di _col(6) in gr `tlabel'[`i']
|
|
}
|
|
if "`overall'`wt'"=="" {
|
|
local ww=`wtdisp'[`i']
|
|
}
|
|
else {
|
|
local ww
|
|
}
|
|
|
|
if (`use'[`i'])==1 {
|
|
*trial results
|
|
di in gr `tlabel'[`i'] _col(22) "| " in ye %7.3f `effect'[`i'] /*
|
|
*/ _col(35) %7.3f `lci'[`i'] " " %7.3f `uci'[`i'] _col(60) %6.2f `ww'
|
|
}
|
|
|
|
if (`use'[`i'])==2 {
|
|
*excluded trial
|
|
di in gr `tlabel'[`i'] _col(22) "| (Excluded)"
|
|
}
|
|
|
|
if ((`use'[`i']==3 | `use'[`i']==19) & "`subgroup'"=="") | (`use'[`i']==5 | `use'[`i']==17) {
|
|
|
|
*Subgroup effect size or overall effect size
|
|
if (`use'[`i'])==3 {
|
|
di in gr " Sub-total" _col(22) "|"
|
|
}
|
|
if `use'[`i']==17 | `use'[`i']==5{
|
|
if $IND!=$OVE {
|
|
local insert "[$OVE% Conf. Interval]"
|
|
}
|
|
if `use'[`i'] == 5{
|
|
di in gr "Overall" _col(22) "|" _col(34) "`insert'"
|
|
}
|
|
}
|
|
|
|
if "`ww'"=="." {
|
|
local ww
|
|
}
|
|
|
|
// RJH
|
|
if `use'[`i'] == 3 | `use'[`i'] == 5{
|
|
di in gr " `method' pooled `log'`sumstat'" _col(22) "| " in ye %7.3f /*
|
|
*/ `effect'[`i'] _col(35) %7.3f `lci'[`i'] " " %7.3f `uci'[`i'] _col(60) %6.2f `ww'
|
|
}
|
|
if `use'[`i'] == 19 | `use'[`i'] == 17{
|
|
di in gr " $MA_method2 pooled `log'`sumstat'" _col(22) "| " in ye %7.3f /*
|
|
*/ `effect'[`i'] _col(35) %7.3f `lci'[`i'] " " %7.3f `uci'[`i']
|
|
}
|
|
if (`use'[`i'])==5 & "$MA_method2" == "" | `use'[`i'] == 17{
|
|
di in gr _dup(21) "-" "+" _dup(51) "-"
|
|
}
|
|
}
|
|
|
|
if (`use'[`i'])==4 {
|
|
*blank line separator (need to put line here in case nosubgroup was selected)
|
|
di in gr _dup(21) "-" "+" _dup(51) "-"
|
|
}
|
|
|
|
local i=`i'+1
|
|
|
|
} /* END OF WHILE LOOP */
|
|
|
|
*Skip next bits if nooverall AND nosubgroup
|
|
if ("`subgroup'"=="" | "`overall'"=="") {
|
|
|
|
*part 2: user defined weight notes and heterogeneity
|
|
if ("`method'"=="*" | "`var3'"!="") {
|
|
if "`method'"=="*" {
|
|
di in gr "* note: trials pooled by user defined weight `wgt'"
|
|
}
|
|
di in bl " Heterogeneity calculated by formula" _n /*
|
|
*/ " Q = SIGMA_i{ (1/variance_i)*(effect_i - effect_pooled)^2 } "
|
|
if "`var3'"!="" {
|
|
di in bl "where variance_i = ((upper limit - lower limit)/(2*z))^2 "
|
|
}
|
|
}
|
|
|
|
di in gr _n "Test(s) of heterogeneity:" _n _col(16) "Heterogeneity degrees of"
|
|
di in gr _col(18) "statistic freedom P I-squared**" _cont
|
|
if "`method'"=="D+L" {
|
|
di in gr " Tau-squared"
|
|
}
|
|
|
|
local maxHet = 0
|
|
local i=1
|
|
while `i'<= _N {
|
|
if ("`subgroup'"=="" & (`use'[`i'])==0) | ( (`use'[`i'])==5) {
|
|
if `use'[`i'] != 5{
|
|
di in gr _n `tlabel'[`i'] _cont
|
|
}
|
|
else{
|
|
di in gr _n "Overall" _cont
|
|
}
|
|
}
|
|
if ( ((`use'[`i'])==3) | ((`use'[`i'])==5) ) {
|
|
di in ye _col(20) %6.2f `hetc'[`i'] _col(35) %2.0f `hetdf'[`i'] /*
|
|
*/ _col(43) %4.3f `hetp'[`i'] _col(51) %6.1f `i2'[`i'] "%" _cont
|
|
if `use'[`i'] == 3{
|
|
local maxHet = max(`maxHet',`i2'[`i'])
|
|
}
|
|
if `use'[`i'] == 5{
|
|
local ovHet = `i2'[`i']
|
|
}
|
|
if "`method'"=="D+L" {
|
|
di in ye " " %7.4f `tau2'[`i'] _cont
|
|
}
|
|
if (`use'[`i']==5) & ("`subgroup'"=="") & ("$MA_method1" == "I-V") { // FIXED I-V ONLY
|
|
qui sum `hetc' if `use'==3
|
|
local btwghet = (`hetc'[`i']) -r(sum)
|
|
local df = `ngroups'-1
|
|
di _n in gr "Overall Test for heterogeneity between sub-groups: " _n /*
|
|
*/ in ye _col(20) %6.2f `btwghet' _col(35) %2.0f `df' _col(43) %4.3f /*
|
|
*/ (chiprob(`df',`btwghet'))
|
|
|
|
}
|
|
}
|
|
local i=`i'+1
|
|
}
|
|
|
|
di _n in gr "** I-squared: the variation in `sumstat' attributable to heterogeneity)" _n
|
|
|
|
// DISPLAY BETWEEN-GROUP TEST WARNINGS
|
|
if "`overall'" == ""{
|
|
if `maxHet' < 50 & `maxHet' > 0 & ("$MA_method1" == "I-V"){
|
|
di in gr "Some heterogeneity observed (up to "%4.1f `maxHet' "%) in one or more sub-groups,"
|
|
di in gr "Test for heterogeneity between sub-groups may be invalid"
|
|
}
|
|
if `maxHet' < 75 & `maxHet' >= 50 & ("$MA_method1" == "I-V"){
|
|
di in gr "Moderate heterogeneity observed (up to "%4.1f `maxHet' "%) in one or more sub-groups,"
|
|
di in gr "Test for heterogeneity between sub-groups likely to be invalid"
|
|
}
|
|
if `maxHet' < . & `maxHet' >= 75 & ("$MA_method1" == "I-V"){
|
|
di in gr "Considerable heterogeneity observed (up to "%4.1f `maxHet' "%) in one or more sub-groups,"
|
|
di in gr "Test for heterogeneity between sub-groups likely to be invalid"
|
|
}
|
|
if "$MA_method1" != "I-V"{
|
|
di in gr "Note: between group heterogeneity not calculated;"
|
|
di in gr "only valid with inverse variance method"
|
|
}
|
|
}
|
|
*part 3: test statistics
|
|
di _n in gr "Significance test(s) of `log'`sumstat'=`h0'"
|
|
|
|
local i=1
|
|
while `i'<= _N {
|
|
|
|
if ("`subgroup'"=="" & (`use'[`i'])==0) | ( (`use'[`i'])==5) {
|
|
if `use'[`i'] != 5{
|
|
di in gr _n `tlabel'[`i'] _cont
|
|
}
|
|
else{
|
|
di in gr _n "Overall" _cont
|
|
}
|
|
}
|
|
|
|
if ( ((`use'[`i'])==3) | ((`use'[`i'])==5) ) {
|
|
if "`chi2'"!="" {
|
|
di in gr _col(20) "chi-squared = " in ye %5.2f `tsig'[`i'] /*
|
|
*/ in gr _col(35) " (d.f. = 1) p = " in ye %4.3f `psig'[`i'] _cont
|
|
}
|
|
else {
|
|
di in gr _col(23) "z= " in ye %5.2f `tsig'[`i'] _col(35) in gr /*
|
|
*/ " p = " in ye %4.3f `psig'[`i'] _cont
|
|
}
|
|
}
|
|
local i=`i'+1
|
|
}
|
|
di _n in gr _dup(73) "-"
|
|
|
|
} /* end of if ("`subgroup'"=="" | "`overall'"=="") */
|
|
|
|
} /* end of table display */
|
|
|
|
|
|
|
|
if "`overall'"=="" {
|
|
|
|
*need to return overall effect to $S_1 macros and so on...
|
|
local N = _N
|
|
if "$MA_method2" != ""{
|
|
local N = _N-1
|
|
}
|
|
|
|
global S_1=`effect'[`N']
|
|
global S_2=`se'[`N']
|
|
global S_3=`lci'[`N']
|
|
global S_4=`uci'[`N']
|
|
global S_7=`hetc'[`N']
|
|
global S_8=`hetdf'[`N']
|
|
global S_9=`hetp'[`N']
|
|
global S_51 =`i2'[`N']
|
|
|
|
if "`chi2'"!="" {
|
|
global S_10=`tsig'[`N']
|
|
global S_11=`psig'[`N']
|
|
global S_5=`z'
|
|
global S_6=`pz'
|
|
}
|
|
else {
|
|
global S_5=`tsig'[`N']
|
|
global S_6=`psig'[`N']
|
|
global S_10=`echi2'
|
|
global S_11=`pchi2'
|
|
}
|
|
|
|
global S_12=`tau2'[`N']
|
|
if ("`sumstat'"=="OR" | "`sumstat'"=="RR" | "`sumstat'"=="RD" ) {
|
|
global S_13=`tger'
|
|
global S_14=`cger'
|
|
}
|
|
|
|
} /* end if overall */
|
|
|
|
else {
|
|
forvalues i = 1/14{
|
|
global S_`i' .
|
|
}
|
|
}
|
|
|
|
|
|
if "`graph'"=="" {
|
|
|
|
_dispgby `effect' `lci' `uci' `weight' `use' `label' `rawdata' `wtdisp' `tau2' `hetdf', /*
|
|
*/ `log' `xlabel' `xtick' `force' sumstat(`sumstat') `saving' `box' t1("`t1'") /*
|
|
*/ t2("`t2'") b1("`b1'") b2("`b2'") lcols("`lcols'") rcols("`rcols'") `overall' `wt' `stats' `counts' `eform' /*
|
|
*/ `groupla' `cornfield'
|
|
|
|
}
|
|
|
|
restore
|
|
|
|
if "`keep'"=="" {
|
|
|
|
qui{
|
|
|
|
if ("`sumstat'"=="OR" | "`sumstat'"=="RR") & ("`log'"=="") {
|
|
local ln "log"
|
|
}
|
|
else {
|
|
local ln
|
|
}
|
|
|
|
cap drop _ES
|
|
cap drop _seES
|
|
cap drop _selogES
|
|
|
|
if "`sumstat'"!="ES" {
|
|
#delimit ;
|
|
replace _SS =. if `use'!=1; label var _SS "Sample size";
|
|
gen _ES =`effect';label var _ES "`log'`sumstat'";
|
|
gen _se`ln'ES=`se';label var _se`ln'ES "se(`ln'`log'`sumstat')";
|
|
#delimit cr
|
|
}
|
|
#delimit ;
|
|
cap drop _LCI ; cap drop _UCI; cap drop _WT;
|
|
gen _LCI =`lci'; label var _LCI "Lower CI (`log'`sumstat')";
|
|
gen _UCI =`uci'; label var _UCI "Upper CI (`log'`sumstat')";
|
|
#delimit cr
|
|
|
|
*correct weight if subgroup weights given
|
|
if ("`sgweight'"=="" & "`overall'"=="" ) {
|
|
gen _WT=`weight'
|
|
}
|
|
else if "`subgroup'"=="" & ("`overall'`sgweight'"!="" ) {
|
|
tempvar tempsum ordering
|
|
gen `ordering' = _n
|
|
bysort `by2': gen `tempsum'=sum(`weight')
|
|
|
|
local N = _N
|
|
if "$MA_method2" != ""{
|
|
local N = _N-1
|
|
}
|
|
bysort `by2': replace `tempsum'=`tempsum'[`N']
|
|
gen _WT=`weight'*100/`tempsum'
|
|
local sg "(subgroup) "
|
|
sort `ordering'
|
|
}
|
|
cap label var _WT "`method' `sg'% weight"
|
|
|
|
} /* end qui */
|
|
|
|
} /* end if keep */
|
|
|
|
end
|
|
|
|
|
|
|
|
**********************************************************
|
|
*** ***
|
|
*** NEW ***
|
|
*** _DISPGBY PROGRAM ***
|
|
*** ROSS HARRIS ***
|
|
*** JULY 2006 ***
|
|
*** * * * ***
|
|
*** ***
|
|
**********************************************************
|
|
|
|
program define _dispgby
|
|
version 9.0
|
|
|
|
// AXmin AXmax ARE THE OVERALL LEFT AND RIGHT COORDS
|
|
// DXmin dxMAX ARE THE LEFT AND RIGHT COORDS OF THE GRAPH PART
|
|
|
|
#delimit ;
|
|
syntax varlist(min=6 max=10 default=none ) [if] [in] [,
|
|
LOG XLAbel(string) XTICK(string) FORCE SAVING(string) noBOX SUMSTAT(string)
|
|
T1(string) T2(string) B1(string) B2(string) LCOLS(string) /* JUNK NOW */
|
|
RCOLS(string) noOVERALL noWT noSTATS COUNTS EFORM
|
|
noGROUPLA CORNFIELD];
|
|
#delimit cr
|
|
tempvar effect lci uci weight wtdisp use label tlabel id yrange xrange Ghsqrwt rawdata i2 mylabel
|
|
tokenize "`varlist'", parse(" ")
|
|
|
|
qui{
|
|
|
|
gen `effect'=`1'
|
|
gen `lci' =`2'
|
|
|
|
gen `uci' =`3'
|
|
gen `weight'=`4' // was 4
|
|
gen byte `use'=`5'
|
|
gen str `label'=`6'
|
|
gen str `mylabel'=`6'
|
|
|
|
if "`lcols'" == ""{
|
|
local lcols "`mylabel'"
|
|
label var `mylabel' "Study ID"
|
|
}
|
|
|
|
gen str80 `rawdata' = `7'
|
|
compress `rawdata'
|
|
|
|
if "`8'"!="" & "$MA_rjhby" != ""{
|
|
gen `wtdisp'=`8'
|
|
}
|
|
else {
|
|
gen `wtdisp'=`weight'
|
|
}
|
|
|
|
if "`10'" != "" & "$MA_rjhby" != ""{
|
|
tempvar tau2 df
|
|
gen `tau2' = `9'
|
|
gen `df' = `10'
|
|
}
|
|
if "`9'" != "" & "$MA_rjhby" == ""{ // DIFFERENT IF FROM metan OR metanby
|
|
tempvar tau2 df
|
|
gen `tau2' = `8'
|
|
gen `df' = `9'
|
|
}
|
|
replace `weight' = `wtdisp' // bodge solu for SG weights
|
|
|
|
if "$MA_summaryonly" != ""{
|
|
drop if `use' == 1
|
|
}
|
|
|
|
// SET UP EXTENDED CIs FOR RANDOM EFFECTS DISTRIBUTION
|
|
// THIS CODE IS A BIT NASTY AS I SET THIS UP BADLY INITIALLY
|
|
// REQUIRES MAJOR REWORK IDEALLY...
|
|
|
|
tempvar tauLCI tauUCI SE tauLCIinf tauUCIinf
|
|
*replace `tau2' = .a if `tau2' == 0 // no heterogeneity
|
|
replace `tau2' = .b if `df'-1 == 0 // inestimable predictive distribution
|
|
replace `tau2' = . if (`use' == 5 | `use' == 3) & "$MA_method1" != "D+L"
|
|
replace `tau2' = . if (`use' == 17 | `use' == 19) & "$MA_method2" != "D+L"
|
|
|
|
gen `tauLCI' = .
|
|
gen `tauUCI' = .
|
|
gen `tauLCIinf' = .
|
|
gen `tauUCIinf' = .
|
|
gen `SE' = .
|
|
|
|
|
|
// modified so rf CI (rflevel) used
|
|
if "$MA_rfdist" != ""{
|
|
if ( ("`sumstat'"=="OR" | "`sumstat'"=="RR") & ("`log'"=="") ) | ("`eform'"!="") {
|
|
replace `SE' = (ln(`uci')-ln(`lci')) / (invnorm($RFL/200+0.5)*2)
|
|
replace `tauLCI' = exp( ln(`effect') - invttail((`df'-1), 0.5-$RFL/200)*sqrt( `tau2' +`SE'^2 ) )
|
|
replace `tauUCI' = exp( ln(`effect') + invttail((`df'-1), 0.5-$RFL/200)*sqrt( `tau2' +`SE'^2 ) )
|
|
replace `tauLCI' = 1e-9 if `tau2' == .b
|
|
replace `tauUCI' = 1e9 if `tau2' == .b
|
|
}
|
|
else{
|
|
replace `SE' = (`uci'-`lci') / ($RFL/200+0.5)
|
|
replace `tauLCI' = `effect'-invttail((`df'-1), 0.5-$RFL/200)*sqrt(`tau2'+`SE'^2)
|
|
replace `tauUCI' = `effect'+invttail((`df'-1), 0.5-$RFL/200)*sqrt(`tau2'+`SE'^2)
|
|
replace `tauLCI' = -1e9 if `tau2' == .b
|
|
replace `tauUCI' = 1e9 if `tau2' == .b
|
|
}
|
|
}
|
|
|
|
|
|
if "$MA_rfdist" != ""{
|
|
qui count
|
|
local prevN = r(N)
|
|
tempvar expTau orderTau
|
|
gen `orderTau' = _n
|
|
gen `expTau' = 1
|
|
replace `expTau' = 2 if `tau2' != . // but expand if .a or .b
|
|
expand `expTau'
|
|
replace `use' = 4 if _n > `prevN'
|
|
replace `orderTau' = `orderTau' + 0.5 if _n > `prevN'
|
|
sort `orderTau'
|
|
}
|
|
|
|
tempvar estText weightText RFdistText RFdistLabel
|
|
local dp = $MA_dp
|
|
gen str `estText' = string(`effect', "%10.`dp'f") + " (" + string(`lci', "%10.`dp'f") + ", " +string(`uci', "%10.`dp'f") + ")"
|
|
replace `estText' = "(Excluded)" if `use' == 2
|
|
|
|
// don't show effect size again, just CI
|
|
gen `RFdistLabel' = "with estimated predictive interval" if `use' == 4 & `tau2' < .
|
|
gen `RFdistText' = /* string(`effect', "%10.`dp'f") + */ ". (" + string(`tauLCI', "%10.`dp'f") + ", " +string(`tauUCI', "%10.`dp'f") ///
|
|
+ ")" if `use' == 4 & `tau2' < .
|
|
|
|
/* not used
|
|
replace `RFdistLabel' = "No observed heterogeneity" if `use' == 4 & `tau2' == .a
|
|
replace `RFdistText' = string(`effect', "%10.`dp'f") + " (" + string(`lci', "%10.`dp'f") + ", " +string(`uci', "%10.`dp'f") ///
|
|
+ ")" if `use' == 4 & `tau2' == .a
|
|
*/
|
|
|
|
// don't show effect size again, just CI
|
|
replace `RFdistLabel' = "Inestimable predictive distribution with <3 studies" if `use' == 4 & `tau2' == .b
|
|
replace `RFdistText' = /* string(`effect', "%4.2f") + */ ". ( - , - )" if `use' == 4 & `tau2' == .b
|
|
|
|
|
|
qui replace `estText' = " " + `estText' if `effect' >= 0 & `use' != 4
|
|
gen str `weightText' = string(`weight', "%4.2f")
|
|
|
|
replace `weightText' = "" if `use' == 17 | `use' == 19 // can cause confusion and not necessary
|
|
replace `rawdata' = "" if `use' == 17 | `use' == 19
|
|
|
|
if "`counts'" != ""{
|
|
if $MA_params == 6{
|
|
local type "N, mean (SD);"
|
|
}
|
|
else{
|
|
local type "Events,"
|
|
}
|
|
tempvar raw1 raw2
|
|
gen str `raw1' = substr(`rawdata',1,(strpos(`rawdata',";")-1) )
|
|
gen str `raw2' = substr(`rawdata',(strpos(`rawdata',";")+1), (length(`rawdata')) )
|
|
label var `raw1' "`type' $MA_G1L"
|
|
label var `raw2' "`type' $MA_G2L"
|
|
}
|
|
|
|
|
|
/* RJH - probably a better way to get this but I've just used globals from earlier */
|
|
|
|
if "`overall'" == "" & "$MA_nohet" == ""{
|
|
if "$MA_method1" == "USER"{
|
|
if "$MA_firststats" != ""{
|
|
replace `label' = "Overall ($MA_firststats)" if `use'==5
|
|
}
|
|
else{
|
|
replace `label' = "Overall" if `use'==5
|
|
}
|
|
}
|
|
replace `label' = "Overall ($MA_secondstats)" if `use' == 17 & "$MA_method2" == "USER" & "$MA_secondstats" != ""
|
|
replace `label' = "Overall" if `use' == 17 & "$MA_method2" == "USER" & "$MA_secondstats" == ""
|
|
}
|
|
if "`overall'" == "" & "$MA_nohet" != ""{
|
|
replace `label' = "Overall" if `use' == 5 | `use' == 17
|
|
}
|
|
|
|
tempvar hetGroupLabel expandOverall orderOverall
|
|
if "$MA_rjhby" != "" & "$MA_nohet" == "" & "$MA_method1" == "I-V"{
|
|
* replace `label' = `label' + ";" if `use' == 5
|
|
qui count
|
|
local prevMax = r(N)
|
|
gen `orderOverall' = _n
|
|
gen `expandOverall' = 1
|
|
replace `expandOverall' = 2 if `use' == 5
|
|
expand `expandOverall'
|
|
replace `orderOverall' = `orderOverall' -0.5 if _n > `prevMax'
|
|
gen `hetGroupLabel' = "Heterogeneity between groups: p = " + ///
|
|
string($rjhHetGrp, "%5.3f") if _n > `prevMax'
|
|
replace `use' = 4 if _n > `prevMax'
|
|
sort `orderOverall'
|
|
}
|
|
else{
|
|
gen `hetGroupLabel' = .
|
|
}
|
|
|
|
replace `label' = "Overall" if `use' == 17 & "$MA_method2" != "USER"
|
|
replace `label' = "Subtotal" if `use' == 19
|
|
|
|
qui count if (`use'==1 | `use'==2)
|
|
local ntrials=r(N)
|
|
qui count if (`use'>=0 & `use'<=5)
|
|
local ymax=r(N)
|
|
gen `id'=`ymax'-_n+1 if `use'<9 | `use' == 17 | `use' == 19
|
|
|
|
if "$MA_method2" != "" | "$MA_method1" == "USER" {
|
|
local dispM1 = "$MA_method1"
|
|
local dispM2 = "$MA_method2"
|
|
if "$MA_method1" == "USER"{
|
|
local dispM1 "$MA_userDescM"
|
|
}
|
|
if "$MA_method2" == "USER"{
|
|
local dispM2 "$MA_userDesc"
|
|
}
|
|
replace `label' = "`dispM1'" + " " + `label' if (`use' == 3 | `use' == 5) & substr(`label',1,3) != "het"
|
|
replace `label' = "`dispM2'" + " " + `label' if `use' == 17 | `use' == 19
|
|
}
|
|
|
|
|
|
// GET MIN AND MAX DISPLAY
|
|
// SORT OUT TICKS- CODE PINCHED FROM MIKE AND FIDDLED. TURNS OUT I'VE BEEN USING SIMILAR NAMES...
|
|
// AS SUGGESTED BY JS JUST ACCEPT ANYTHING AS TICKS AND RESPONSIBILITY IS TO USER!
|
|
|
|
qui summ `lci', detail
|
|
local DXmin = r(min)
|
|
qui summ `uci', detail
|
|
local DXmax = r(max)
|
|
local h0 = 0
|
|
|
|
// MIKE MAKES A MAX VALUE IF SOMETHING EXTREME OCCURS...
|
|
if (( ("`sumstat'"=="OR" | "`sumstat'"=="RR") & ("`log'"=="") ) | ("`eform'"!="")) {
|
|
local h0=1
|
|
local Glog "xlog"
|
|
local xlog "log"
|
|
local xexp "exp"
|
|
replace `lci'=1e-9 if `lci'<1e-8
|
|
replace `lci'=1e9 if `lci'>1e8 & `lci'!=.
|
|
replace `uci'=1e-9 if `uci'<1e-8
|
|
replace `uci'=1e9 if `uci'>1e8 & `uci'!=.
|
|
if `DXmin'<1e-8 {
|
|
local DXmin=1e-8
|
|
}
|
|
if `DXmax'>1e8 {
|
|
local DXmax=1e8
|
|
}
|
|
}
|
|
if "$MA_NULL" != ""{
|
|
local h0 = $MA_NULL
|
|
}
|
|
if `h0' != 0 & `h0' != 1{
|
|
noi di "Null specified as `h0' in graph- for most effect measures null is 0 or 1"
|
|
}
|
|
|
|
if "`cornfield'"!="" {
|
|
replace `lci'=`log'(1e-9) if ( (`lci'==. | `lci'==0) & (`effect'!=. & `use'==1) )
|
|
replace `uci'=`log'(1e9) if ( (`uci'==.) & (`effect'!=. & `use'==1) )
|
|
}
|
|
|
|
// THIS BIT CHANGED- THE USER CAN PUT ANYTHING IN
|
|
|
|
local flag1=0
|
|
if ("`xlabel'"=="" | "`xtick'" == "") & "$MA_nulloff" == ""{ // if no xlabel or tick
|
|
local xtick "`h0'"
|
|
}
|
|
|
|
if "`xlabel'"==""{
|
|
local Gmodxhi=max( abs(`xlog'(`DXmin')),abs(`xlog'(`DXmax')))
|
|
if `Gmodxhi'==. {
|
|
local Gmodxhi=2
|
|
}
|
|
local DXmin=`xexp'(-`Gmodxhi')
|
|
local DXmax=`xexp'( `Gmodxhi')
|
|
if "$MA_nulloff" == ""{
|
|
local xlabel "`DXmin',`h0',`DXmax'"
|
|
}
|
|
else{
|
|
local xlabel "`DXmin',`DXmax'"
|
|
}
|
|
}
|
|
|
|
local DXmin2 = min(`xlabel',`DXmin')
|
|
local DXmax2 = max(`xlabel',`DXmax')
|
|
if "`force'" == ""{
|
|
local Gmodxhi=max( abs(`xlog'(`DXmin')), abs(`xlog'(`DXmax')), ///
|
|
abs(`xlog'(`DXmin2')), abs(`xlog'(`DXmax2')) )
|
|
if `Gmodxhi'==. {
|
|
local Gmodxhi=2
|
|
}
|
|
local DXmin=`xexp'(-`Gmodxhi')
|
|
local DXmax=`xexp'( `Gmodxhi')
|
|
if "`xlabel'" != "" & "$MA_nulloff" == ""{
|
|
local xlabel "`h0',`xlabel'"
|
|
}
|
|
}
|
|
|
|
if "`force'" != ""{
|
|
local DXmin = min(`xlabel')
|
|
local DXmax = max(`xlabel')
|
|
if "$MA_nulloff" == ""{
|
|
local xlabel "`h0',`xlabel'"
|
|
}
|
|
}
|
|
|
|
// LABELS- DON'T ALLOW SILLY NO. OF DECIMAL PLACES
|
|
|
|
local lblcmd ""
|
|
tokenize "`xlabel'", parse(",")
|
|
while "`1'" != ""{
|
|
if "`1'" != ","{
|
|
local lbl = string(`1',"%7.3g")
|
|
local val = `1'
|
|
local lblcmd `lblcmd' `val' "`lbl'"
|
|
}
|
|
mac shift
|
|
}
|
|
if "`xtick'" == ""{
|
|
local xtick = "`xlabel'"
|
|
}
|
|
|
|
local xtick2 = ""
|
|
tokenize "`xtick'", parse(",")
|
|
while "`1'" != ""{
|
|
if "`1'" != ","{
|
|
local xtick2 = "`xtick2' " + string(`1')
|
|
}
|
|
if "`1'" == ","{
|
|
local xtick2 = "`xtick2'`1'"
|
|
}
|
|
mac shift
|
|
}
|
|
local xtick = "`xtick2'"
|
|
|
|
local DXmin=`xlog'(min(`xlabel',`xtick',`DXmin'))
|
|
local DXmax=`xlog'(max(`xlabel',`xtick',`DXmax'))
|
|
|
|
if ("`eform'" != "" | "`xlog'" != "") {
|
|
local lblcmd ""
|
|
tokenize "`xlabel'", parse(",")
|
|
while "`1'" != ""{
|
|
if "`1'" != ","{
|
|
local lbl = string(`1',"%7.3g")
|
|
local val = ln(`1')
|
|
local lblcmd `lblcmd' `val' "`lbl'"
|
|
}
|
|
mac shift
|
|
}
|
|
|
|
replace `effect' = ln(`effect')
|
|
replace `lci' = ln(`lci')
|
|
replace `uci' = ln(`uci')
|
|
replace `tauLCI' = ln(`tauLCI')
|
|
replace `tauUCI' = ln(`tauUCI')
|
|
local xtick2 ""
|
|
tokenize "`xtick'", parse(",")
|
|
while "`1'" != ""{
|
|
if "`1'" != ","{
|
|
local ln = ln(`1')
|
|
local xtick2 "`xtick2' `ln'"
|
|
}
|
|
if "`1'" == ","{
|
|
local xtick2 "`xtick2'`1'"
|
|
}
|
|
mac shift
|
|
}
|
|
local xtick "`xtick2'"
|
|
local h0 = 0
|
|
}
|
|
|
|
// JUNK
|
|
*noi di "min: `DXmin', `DXminLab'; h0: `h0', `h0Lab'; max: `DXmax', `DXmaxLab'"
|
|
|
|
local DXwidth = `DXmax'-`DXmin'
|
|
if `DXmin' > 0{
|
|
local h0 = 1
|
|
}
|
|
|
|
} // END QUI
|
|
|
|
// END OF TICKS AND LABLES
|
|
|
|
// MAKE OFF-SCALE ARROWS
|
|
|
|
qui{
|
|
tempvar offLeftX offLeftX2 offRightX offRightX2 offYlo offYhi
|
|
|
|
local arrowWidth = 0.02 // FRACTION OF GRAPH WIDTH
|
|
local arrowHeight = 0.5/2 // Y SCALE IS JUST ORDERED NUMBER- 2x0.25 IS 0.5 OF AVAILABLE SPACE
|
|
|
|
gen `offLeftX' = `DXmin' if `lci' < `DXmin' | `tauLCI' < `DXmin'
|
|
gen `offLeftX2' = `DXmin' + `DXwidth'*`arrowWidth' if `lci' < `DXmin' | `tauLCI' < `DXmin'
|
|
|
|
gen `offRightX' = `DXmax' if `uci' > `DXmax' | (`tauUCI' > `DXmax' & `tauLCI' < .)
|
|
gen `offRightX2' = `DXmax' - `DXwidth'*`arrowWidth' if `uci' > `DXmax' | (`tauUCI' > `DXmax' & `tauLCI' < .)
|
|
|
|
gen `offYlo' = `id' - `arrowHeight'
|
|
gen `offYhi' = `id' + `arrowHeight'
|
|
|
|
replace `lci' = `DXmin' if `lci' < `DXmin' & (`use' == 1 | `use' == 2)
|
|
replace `uci' = `DXmax' if `uci' > `DXmax' & (`use' == 1 | `use' == 2)
|
|
replace `lci' = . if `uci' < `DXmin' & (`use' == 1 | `use' == 2)
|
|
replace `uci' = . if `lci' > `DXmax' & (`use' == 1 | `use' == 2)
|
|
replace `effect' = . if `effect' < `DXmin' & (`use' == 1 | `use' == 2)
|
|
replace `effect' = . if `effect' > `DXmax' & (`use' == 1 | `use' == 2)
|
|
} // end qui
|
|
|
|
************************
|
|
** COLUMNS **
|
|
************************
|
|
|
|
// OPTIONS FOR L-R JUSTIFY?
|
|
// HAVE ONE MORE COL POSITION THAN NECESSARY, COULD THEN R-JUSTIFY
|
|
// BY ADDING 1 TO LOOP, ALSO HAVE MAX DIST FOR OUTER EDGE
|
|
// HAVE USER SPECIFY % OF GRAPH USED FOR TEXT?
|
|
|
|
qui{ // KEEP QUIET UNTIL AFTER DIAMONDS
|
|
local titleOff = 0
|
|
|
|
if "`lcols'" == ""{
|
|
local lcols = "`label'"
|
|
local titleOff = 1
|
|
}
|
|
|
|
// DOUBLE LINE OPTION
|
|
if "$MA_DOUBLE" != "" & ("`lcols'" != "" | "`rcols'" != ""){
|
|
tempvar expand orig
|
|
gen `orig' = _n
|
|
gen `expand' = 1
|
|
replace `expand' = 2 if `use' == 1
|
|
expand `expand'
|
|
sort `orig'
|
|
replace `id' = `id' - 0.45 if `id' == `id'[_n-1]
|
|
replace `use' = 2 if mod(`id',1) != 0 & `use' != 5
|
|
replace `effect' = . if mod(`id',1) != 0
|
|
replace `lci' = . if mod(`id',1) != 0
|
|
replace `uci' = . if mod(`id',1) != 0
|
|
replace `estText' = "" if mod(`id',1) != 0
|
|
cap replace `raw1' = "" if mod(`id',1) != 0
|
|
cap replace `raw2' = "" if mod(`id',1) != 0
|
|
replace `weightText' = "" if mod(`id',1) != 0
|
|
|
|
foreach var of varlist `lcols' `rcols'{
|
|
cap confirm string var `var'
|
|
if _rc == 0{
|
|
|
|
tempvar length words tosplit splitwhere best
|
|
gen `splitwhere' = 0
|
|
gen `best' = .
|
|
gen `length' = length(`var')
|
|
summ `length', det
|
|
gen `words' = wordcount(`var')
|
|
gen `tosplit' = 1 if `length' > r(max)/2+1 & `words' >= 2
|
|
summ `words', det
|
|
local max = r(max)
|
|
forvalues i = 1/`max'{
|
|
replace `splitwhere' = strpos(`var',word(`var',`i')) ///
|
|
if abs( strpos(`var',word(`var',`i')) - length(`var')/2 ) < `best' ///
|
|
& `tosplit' == 1
|
|
replace `best' = abs(strpos(`var',word(`var',`i')) - length(`var')/2) ///
|
|
if abs(strpos(`var',word(`var',`i')) - length(`var')/2) < `best'
|
|
}
|
|
|
|
replace `var' = substr(`var',1,(`splitwhere'-1)) if `tosplit' == 1 & mod(`id',1) == 0
|
|
replace `var' = substr(`var',`splitwhere',length(`var')) if `tosplit' == 1 & mod(`id',1) != 0
|
|
replace `var' = "" if `tosplit' != 1 & mod(`id',1) != 0 & `use' != 5
|
|
drop `length' `words' `tosplit' `splitwhere' `best'
|
|
}
|
|
if _rc != 0{
|
|
replace `var' = . if mod(`id',1) != 0 & `use' != 5
|
|
}
|
|
}
|
|
}
|
|
|
|
summ `id' if `use' != 9
|
|
local max = r(max)
|
|
local new = r(N)+4
|
|
if `new' > _N {
|
|
set obs `new'
|
|
}
|
|
|
|
forvalues i = 1/4{ // up to four lines for titles
|
|
local multip = 1
|
|
local add = 0
|
|
if "$MA_DOUBLE" != ""{ // DOUBLE OPTION- CLOSER TOGETHER, GAP BENEATH
|
|
local multip = 0.45
|
|
local add = 0.5
|
|
}
|
|
local idNew`i' = `max' + `i'*`multip' + `add'
|
|
local Nnew`i'=r(N)+`i'
|
|
local tmp = `Nnew`i''
|
|
replace `id' = `idNew`i'' + 1 in `tmp'
|
|
replace `use' = 1 in `tmp'
|
|
if `i' == 1{
|
|
global borderline = `idNew`i''-0.25
|
|
}
|
|
}
|
|
|
|
local maxline = 1
|
|
if "`lcols'" != ""{
|
|
tokenize "`lcols'"
|
|
local lcolsN = 0
|
|
|
|
while "`1'" != ""{
|
|
cap confirm var `1'
|
|
if _rc!=0 {
|
|
di in re "Variable `1' not defined"
|
|
exit _rc
|
|
}
|
|
local lcolsN = `lcolsN' + 1
|
|
tempvar left`lcolsN' leftLB`lcolsN' leftWD`lcolsN'
|
|
cap confirm string var `1'
|
|
if _rc == 0{
|
|
gen str `leftLB`lcolsN'' = `1'
|
|
}
|
|
if _rc != 0{
|
|
cap decode `1', gen(`leftLB`lcolsN'')
|
|
if _rc != 0{
|
|
local f: format `1'
|
|
gen str `leftLB`lcolsN'' = string(`1', "`f'")
|
|
replace `leftLB`lcolsN'' = "" if `leftLB`lcolsN'' == "."
|
|
}
|
|
}
|
|
replace `leftLB`lcolsN'' = "" if (`use' != 1 & `use' != 2)
|
|
local colName: variable label `1'
|
|
if "`colName'"==""{
|
|
local colName = "`1'"
|
|
}
|
|
|
|
// WORK OUT IF TITLE IS BIGGER THAN THE VARIABLE
|
|
// SPREAD OVER UP TO FOUR LINES IF NECESSARY
|
|
local titleln = length("`colName'")
|
|
tempvar tmpln
|
|
gen `tmpln' = length(`leftLB`lcolsN'')
|
|
qui summ `tmpln' if `use' != 0
|
|
local otherln = r(max)
|
|
drop `tmpln'
|
|
// NOW HAVE LENGTH OF TITLE AND MAX LENGTH OF VARIABLE
|
|
local spread = int(`titleln'/`otherln')+1
|
|
if `spread'>4{
|
|
local spread = 4
|
|
}
|
|
|
|
local line = 1
|
|
local end = 0
|
|
local count = -1
|
|
local c2 = -2
|
|
|
|
local first = word("`colName'",1)
|
|
local last = word("`colName'",`count')
|
|
local nextlast = word("`colName'",`c2')
|
|
|
|
while `end' == 0{
|
|
replace `leftLB`lcolsN'' = "`last'" + " " + `leftLB`lcolsN'' in `Nnew`line''
|
|
local check = `leftLB`lcolsN''[`Nnew`line''] + " `nextlast'" // what next will be
|
|
|
|
local count = `count'-1
|
|
local last = word("`colName'",`count')
|
|
if "`last'" == ""{
|
|
local end = 1
|
|
}
|
|
|
|
if length(`leftLB`lcolsN''[`Nnew`line'']) > `titleln'/`spread' | ///
|
|
length("`check'") > `titleln'/`spread' & "`first'" == "`nextlast'"{
|
|
if `end' == 0{
|
|
local line = `line'+1
|
|
}
|
|
}
|
|
}
|
|
if `line' > `maxline'{
|
|
local maxline = `line'
|
|
}
|
|
|
|
mac shift
|
|
}
|
|
}
|
|
|
|
if `titleOff' == 1 {
|
|
forvalues i = 1/4{
|
|
replace `leftLB1' = "" in `Nnew`i'' // get rid of horrible __var name
|
|
}
|
|
}
|
|
replace `leftLB1' = `label' if `use' != 1 & `use' != 2 // put titles back in (overall, sub est etc.)
|
|
|
|
// STUFF ADDED FOR JS TO INCLUDE EFFICACY AS COLUMN WITH OVERALL
|
|
|
|
*effect lci uci tempvars
|
|
if "$MA_efficacy" != ""{
|
|
tempvar vetemp ucivetemp lcivetemp vaccine_efficacy
|
|
qui {
|
|
gen `vetemp'=100*(1-exp(`effect'))
|
|
tostring `vetemp', replace force format(%4.0f)
|
|
|
|
gen `ucivetemp'=100*(1-exp(`lci'))
|
|
tostring `ucivetemp', replace force format(%4.0f)
|
|
|
|
gen `lcivetemp'=100*(1-exp(`uci'))
|
|
tostring `lcivetemp', replace force format(%4.0f)
|
|
|
|
gen str30 `vaccine_efficacy'=`vetemp'+" ("+`lcivetemp'+", "+`ucivetemp'+")" if `effect' != .
|
|
label var `vaccine_efficacy' "Vaccine efficacy (%)"
|
|
|
|
local rcols = "`vaccine_efficacy' " + "`rcols' "
|
|
|
|
}
|
|
}
|
|
|
|
if "`wt'" == ""{
|
|
local rcols = "`weightText' " + "`rcols'"
|
|
if "$MA_method2" != ""{
|
|
label var `weightText' "% Weight ($MA_method1)"
|
|
}
|
|
else{
|
|
label var `weightText' "% Weight"
|
|
}
|
|
}
|
|
if "`counts'" != ""{
|
|
local rcols = "`raw1' " + "`raw2' " + "`rcols'"
|
|
}
|
|
if "`stats'" == ""{
|
|
local rcols = "`estText' " + "`rcols'"
|
|
if "$MA_ESLA" == ""{
|
|
global MA_ESLA = "`sumstat'"
|
|
}
|
|
label var `estText' "$MA_ESLA ($IND% CI)"
|
|
}
|
|
|
|
tempvar extra
|
|
gen `extra' = ""
|
|
label var `extra' " "
|
|
local rcols = "`rcols' `extra'"
|
|
|
|
local rcolsN = 0
|
|
if "`rcols'" != ""{
|
|
tokenize "`rcols'"
|
|
local rcolsN = 0
|
|
while "`1'" != ""{
|
|
cap confirm var `1'
|
|
if _rc!=0 {
|
|
di in re "Variable `1' not defined"
|
|
exit _rc
|
|
}
|
|
local rcolsN = `rcolsN' + 1
|
|
tempvar right`rcolsN' rightLB`rcolsN' rightWD`rcolsN'
|
|
cap confirm string var `1'
|
|
if _rc == 0{
|
|
gen str `rightLB`rcolsN'' = `1'
|
|
}
|
|
if _rc != 0{
|
|
local f: format `1'
|
|
gen str `rightLB`rcolsN'' = string(`1', "`f'")
|
|
replace `rightLB`rcolsN'' = "" if `rightLB`rcolsN'' == "."
|
|
}
|
|
local colName: variable label `1'
|
|
if "`colName'"==""{
|
|
local colName = "`1'"
|
|
}
|
|
|
|
// WORK OUT IF TITLE IS BIGGER THAN THE VARIABLE
|
|
// SPREAD OVER UP TO FOUR LINES IF NECESSARY
|
|
local titleln = length("`colName'")
|
|
tempvar tmpln
|
|
gen `tmpln' = length(`rightLB`rcolsN'')
|
|
qui summ `tmpln' if `use' != 0
|
|
local otherln = r(max)
|
|
drop `tmpln'
|
|
// NOW HAVE LENGTH OF TITLE AND MAX LENGTH OF VARIABLE
|
|
local spread = int(`titleln'/`otherln')+1
|
|
if `spread'>4{
|
|
local spread = 4
|
|
}
|
|
|
|
local line = 1
|
|
local end = 0
|
|
local count = -1
|
|
local c2 = -2
|
|
|
|
local first = word("`colName'",1)
|
|
local last = word("`colName'",`count')
|
|
local nextlast = word("`colName'",`c2')
|
|
|
|
while `end' == 0{
|
|
replace `rightLB`rcolsN'' = "`last'" + " " + `rightLB`rcolsN'' in `Nnew`line''
|
|
local check = `rightLB`rcolsN''[`Nnew`line''] + " `nextlast'" // what next will be
|
|
|
|
local count = `count'-1
|
|
local last = word("`colName'",`count')
|
|
if "`last'" == ""{
|
|
local end = 1
|
|
}
|
|
if length(`rightLB`rcolsN''[`Nnew`line'']) > `titleln'/`spread' | ///
|
|
length("`check'") > `titleln'/`spread' & "`first'" == "`nextlast'"{
|
|
if `end' == 0{
|
|
local line = `line'+1
|
|
}
|
|
}
|
|
}
|
|
if `line' > `maxline'{
|
|
local maxline = `line'
|
|
}
|
|
|
|
mac shift
|
|
}
|
|
}
|
|
|
|
// now get rid of extra title rows if they weren't used
|
|
|
|
|
|
if `maxline'==3{
|
|
drop in `Nnew4'
|
|
}
|
|
if `maxline'==2{
|
|
drop in `Nnew3'/`Nnew4'
|
|
}
|
|
if `maxline'==1{
|
|
drop in `Nnew2'/`Nnew4'
|
|
}
|
|
|
|
|
|
/* BODGE SOLU- EXTRA COLS */
|
|
while `rcolsN' < 2{
|
|
local rcolsN = `rcolsN' + 1
|
|
tempvar right`rcolsN' rightLB`rcolsN' rightWD`rcolsN'
|
|
gen str `rightLB`rcolsN'' = " "
|
|
}
|
|
|
|
|
|
local skip = 1
|
|
if "`stats'" == "" & "`wt'" == ""{ // sort out titles for stats and weight, if there
|
|
local skip = 3
|
|
}
|
|
|
|
if "`stats'" != "" & "`wt'" == ""{
|
|
local skip = 2
|
|
}
|
|
if "`stats'" == "" & "`wt'" != ""{
|
|
local skip = 2
|
|
}
|
|
if "`counts'" != ""{
|
|
local skip = `skip' + 2
|
|
}
|
|
if "$MA_efficacy" != ""{
|
|
local skip = `skip' + 1
|
|
}
|
|
|
|
/* SET TWO DUMMY RCOLS IF NOSTATS NOWEIGHT */
|
|
|
|
forvalues i = `skip'/`rcolsN'{ // get rid of junk if not weight, stats or counts
|
|
replace `rightLB`i'' = "" if (`use' != 1 & `use' != 2)
|
|
}
|
|
forvalues i = 1/`rcolsN'{
|
|
replace `rightLB`i'' = "" if (`use' ==0)
|
|
}
|
|
|
|
local leftWDtot = 0
|
|
local rightWDtot = 0
|
|
local leftWDtotNoTi = 0
|
|
|
|
forvalues i = 1/`lcolsN'{
|
|
getWidth `leftLB`i'' `leftWD`i''
|
|
qui summ `leftWD`i'' if `use' != 0 & `use' != 4 & `use' != 3 & `use' != 5 & ///
|
|
`use' != 17 & `use' != 19 // DON'T INCLUDE OVERALL STATS AT THIS POINT
|
|
local maxL = r(max)
|
|
local leftWDtotNoTi = `leftWDtotNoTi' + `maxL'
|
|
replace `leftWD`i'' = `maxL'
|
|
}
|
|
tempvar titleLN // CHECK IF OVERALL LENGTH BIGGER THAN REST OF LCOLS
|
|
getWidth `leftLB1' `titleLN'
|
|
qui summ `titleLN' if `use' != 0 & `use' != 4
|
|
local leftWDtot = max(`leftWDtotNoTi', r(max))
|
|
|
|
forvalues i = 1/`rcolsN'{
|
|
getWidth `rightLB`i'' `rightWD`i''
|
|
qui summ `rightWD`i'' if `use' != 0 & `use' != 4
|
|
replace `rightWD`i'' = r(max)
|
|
local rightWDtot = `rightWDtot' + r(max)
|
|
}
|
|
|
|
// CHECK IF NOT WIDE ENOUGH (I.E., OVERALL INFO TOO WIDE)
|
|
// LOOK FOR EDGE OF DIAMOND summ `lci' if `use' == ...
|
|
|
|
tempvar maxLeft
|
|
getWidth `leftLB1' `maxLeft'
|
|
qui count if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19
|
|
if r(N) > 0{
|
|
summ `maxLeft' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19 // NOT TITLES THOUGH!
|
|
local max = r(max)
|
|
if `max' > `leftWDtotNoTi'{
|
|
// WORK OUT HOW FAR INTO PLOT CAN EXTEND
|
|
// WIDTH OF LEFT COLUMNS AS FRACTION OF WHOLE GRAPH
|
|
local x = `leftWDtot'*($MA_AS_TEXT/100)/(`leftWDtot'+`rightWDtot')
|
|
tempvar y
|
|
// SPACE TO LEFT OF DIAMOND WITHIN PLOT (FRAC OF GRAPH)
|
|
gen `y' = ((100-$MA_AS_TEXT)/100)*(`lci'-`DXmin') / (`DXmax'-`DXmin')
|
|
qui summ `y' if `use' == 3 | `use' == 5
|
|
local extend = 1*(r(min)+`x')/`x'
|
|
local leftWDtot = max(`leftWDtot'/`extend',`leftWDtotNoTi') // TRIM TO KEEP ON SAFE SIDE
|
|
// ALSO MAKE SURE NOT LESS THAN BEFORE!
|
|
}
|
|
|
|
}
|
|
|
|
global LEFT_WD = `leftWDtot'
|
|
global RIGHT_WD = `rightWDtot'
|
|
|
|
|
|
local ratio = $MA_AS_TEXT // USER SPECIFIED- % OF GRAPH TAKEN BY TEXT (ELSE NUM COLS CALC?)
|
|
local textWD = (`DXwidth'/(1-`ratio'/100)-`DXwidth') /(`leftWDtot'+`rightWDtot')
|
|
|
|
forvalues i = 1/`lcolsN'{
|
|
gen `left`i'' = `DXmin' - `leftWDtot'*`textWD'
|
|
local leftWDtot = `leftWDtot'-`leftWD`i''
|
|
}
|
|
|
|
gen `right1' = `DXmax'
|
|
forvalues i = 2/`rcolsN'{
|
|
local r2 = `i'-1
|
|
gen `right`i'' = `right`r2'' + `rightWD`r2''*`textWD'
|
|
}
|
|
|
|
local AXmin = `left1'
|
|
local AXmax = `DXmax' + `rightWDtot'*`textWD'
|
|
|
|
foreach type in "" "inf"{
|
|
replace `tauLCI`inf'' = `DXmin' if `tauLCI' < `DXmin' & `tauLCI`inf'' != .
|
|
replace `tauLCI`inf'' = . if `lci' < `DXmin'
|
|
replace `tauLCI`inf'' = . if `tauLCI`inf'' > `lci'
|
|
|
|
replace `tauUCI`inf'' = `DXmax' if `tauUCI`inf'' > `DXmax' & `tauUCI`inf'' != .
|
|
replace `tauUCI`inf'' = . if `uci' > `DXmax'
|
|
replace `tauUCI`inf'' = . if `tauUCI`inf'' < `uci'
|
|
|
|
replace `tauLCI`inf'' = . if (`use' == 3 | `use' == 5) & "$MA_method1" != "D+L"
|
|
replace `tauUCI`inf'' = . if (`use' == 3 | `use' == 5) & "$MA_method1" != "D+L"
|
|
replace `tauLCI`inf'' = . if (`use' == 17 | `use' == 19) & "$MA_method2" != "D+L"
|
|
replace `tauUCI`inf'' = . if (`use' == 17 | `use' == 19) & "$MA_method2" != "D+L"
|
|
}
|
|
|
|
|
|
// DIAMONDS TAKE FOREVER...I DON'T THINK THIS IS WHAT MIKE DID
|
|
tempvar DIAMleftX DIAMrightX DIAMbottomX DIAMtopX DIAMleftY1 DIAMrightY1 DIAMleftY2 DIAMrightY2 DIAMbottomY DIAMtopY
|
|
|
|
gen `DIAMleftX' = `lci' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19
|
|
replace `DIAMleftX' = `DXmin' if `lci' < `DXmin' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
replace `DIAMleftX' = . if `effect' < `DXmin' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
gen `DIAMleftY1' = `id' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19
|
|
replace `DIAMleftY1' = `id' + 0.4*( abs((`DXmin'-`lci')/(`effect'-`lci')) ) if `lci' < `DXmin' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
replace `DIAMleftY1' = . if `effect' < `DXmin' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
gen `DIAMleftY2' = `id' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19
|
|
replace `DIAMleftY2' = `id' - 0.4*( abs((`DXmin'-`lci')/(`effect'-`lci')) ) if `lci' < `DXmin' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
replace `DIAMleftY2' = . if `effect' < `DXmin' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
|
|
gen `DIAMrightX' = `uci' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19
|
|
replace `DIAMrightX' = `DXmax' if `uci' > `DXmax' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
replace `DIAMrightX' = . if `effect' > `DXmax' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
gen `DIAMrightY1' = `id' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19
|
|
replace `DIAMrightY1' = `id' + 0.4*( abs((`uci'-`DXmax')/(`uci'-`effect')) ) if `uci' > `DXmax' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
replace `DIAMrightY1' = . if `effect' > `DXmax' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
gen `DIAMrightY2' = `id' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19
|
|
replace `DIAMrightY2' = `id' - 0.4*( abs((`uci'-`DXmax')/(`uci'-`effect')) ) if `uci' > `DXmax' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
|
|
replace `DIAMrightY2' = . if `effect' > `DXmax' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
gen `DIAMbottomY' = `id' - 0.4 if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19
|
|
replace `DIAMbottomY' = `id' - 0.4*( abs((`uci'-`DXmin')/(`uci'-`effect')) ) if `effect' < `DXmin' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
replace `DIAMbottomY' = `id' - 0.4*( abs((`DXmax'-`lci')/(`effect'-`lci')) ) if `effect' > `DXmax' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
gen `DIAMtopY' = `id' + 0.4 if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19
|
|
replace `DIAMtopY' = `id' + 0.4*( abs((`uci'-`DXmin')/(`uci'-`effect')) ) if `effect' < `DXmin' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
replace `DIAMtopY' = `id' + 0.4*( abs((`DXmax'-`lci')/(`effect'-`lci')) ) if `effect' > `DXmax' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
|
|
gen `DIAMtopX' = `effect' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19
|
|
replace `DIAMtopX' = `DXmin' if `effect' < `DXmin' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
replace `DIAMtopX' = `DXmax' if `effect' > `DXmax' & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
replace `DIAMtopX' = . if (`uci' < `DXmin' | `lci' > `DXmax') & (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19)
|
|
gen `DIAMbottomX' = `DIAMtopX'
|
|
|
|
} // END QUI
|
|
|
|
// v1.11 TEXT SIZE SOLU
|
|
// v1.16 TRYING AGAIN!
|
|
// IF aspect IS USED IN "$MA_OTHEROPTS" (OTHER GRAPH OPTS) THEN THIS HELPS TO CALCULATE TEXT SIZE
|
|
// IF NO ASPECT, BUT xsize AND ysize USED THEN FIND RATIO MANUALLY
|
|
// STATA ALWAYS TRIES TO PRODUCE A GRAPH WITH ASPECT ABOUT 0.77 - TRY TO FIND "NATURAL ASPECT"
|
|
|
|
local aspect = .
|
|
|
|
if strpos(`"$MA_OTHEROPTS"',"aspect") > 0{
|
|
local aspectTXT = substr( `"$MA_OTHEROPTS"', (strpos(`"$MA_OTHEROPTS"',"aspect")), (length(`"$MA_OTHEROPTS"')) )
|
|
local aspectTXT = substr( "`aspectTXT'", 1, ( strpos("`aspectTXT'",")")) )
|
|
local aspect = real( substr( "`aspectTXT'", ( strpos("`aspectTXT'","(") +1 ), ///
|
|
( strpos("`aspectTXT'",")") - strpos("`aspectTXT'","(") -1 ) ))
|
|
}
|
|
|
|
if strpos(`"$MA_OTHEROPTS"',"xsize") > 0 ///
|
|
& strpos(`"$MA_OTHEROPTS"',"ysize") > 0 ///
|
|
& strpos(`"$MA_OTHEROPTS"',"aspect") == 0{
|
|
|
|
local xsizeTXT = substr( `"$MA_OTHEROPTS"', (strpos(`"$MA_OTHEROPTS"',"xsize")), (length(`"$MA_OTHEROPTS"')) )
|
|
|
|
// Ian White's bug fix!
|
|
local xsizeTXT = substr( `"`xsizeTXT'"', 1, ( strpos(`"`xsizeTXT'"',")")) )
|
|
local xsize = real( substr( `"`xsizeTXT'"', ( strpos(`"`xsizeTXT'"',"(") +1 ), ///
|
|
( strpos(`"`xsizeTXT'"',")") - strpos(`"`xsizeTXT'"',"(") -1 ) ))
|
|
local ysizeTXT = substr( `"$MA_OTHEROPTS"', (strpos(`"$MA_OTHEROPTS"',"ysize")), (length(`"$MA_OTHEROPTS"')) )
|
|
local ysizeTXT = substr( `"`ysizeTXT'"', 1, ( strpos(`"`ysizeTXT'"',")")) )
|
|
local ysize = real( substr( `"`ysizeTXT'"', ( strpos(`"`ysizeTXT'"',"(") +1 ), ///
|
|
( strpos(`"`ysizeTXT'"',")") - strpos(`"`ysizeTXT'"',"(") -1 ) ))
|
|
|
|
local aspect = `ysize'/`xsize'
|
|
}
|
|
local approx_chars = ($LEFT_WD + $RIGHT_WD)/($MA_AS_TEXT/100)
|
|
qui count if `use' != 9
|
|
local height = r(N)
|
|
local natu_aspect = 1.3*`height'/`approx_chars'
|
|
|
|
|
|
if `aspect' == .{
|
|
// sort out relative to text, but not to ridiculous degree
|
|
local new_asp = 0.5*`natu_aspect' + 0.5*1
|
|
global MA_OTHEROPTS `"$MA_OTHEROPTS aspect(`new_asp')"'
|
|
local aspectRat = max( `new_asp'/`natu_aspect' , `natu_aspect'/`new_asp' )
|
|
}
|
|
if `aspect' != .{
|
|
local aspectRat = max( `aspect'/`natu_aspect' , `natu_aspect'/`aspect' )
|
|
}
|
|
local adj = 1.25
|
|
if `natu_aspect' > 0.7{
|
|
local adj = 1/(`natu_aspect'^1.3+0.2)
|
|
}
|
|
|
|
local textSize = `adj' * $MA_TEXT_SCA / (`approx_chars' * sqrt(`aspectRat') )
|
|
local textSize2 = `adj' * $MA_TEXT_SCA / (`approx_chars' * sqrt(`aspectRat') )
|
|
|
|
forvalues i = 1/`lcolsN'{
|
|
local lcolCommands`i' "(scatter `id' `left`i'' if `use' != 4, msymbol(none) mlabel(`leftLB`i'') mlabcolor(black) mlabpos(3) mlabsize(`textSize')) "
|
|
}
|
|
forvalues i = 1/`rcolsN'{
|
|
local rcolCommands`i' "(scatter `id' `right`i'' if `use' != 4, msymbol(none) mlabel(`rightLB`i'') mlabcolor(black) mlabpos(3) mlabsize(`textSize')) "
|
|
}
|
|
if "$MA_rfdist" != ""{
|
|
if "`stats'" == ""{
|
|
local predIntCmd "(scatter `id' `right1' if `use' == 4, msymbol(none) mlabel(`RFdistText') mlabcolor(black) mlabpos(3) mlabsize(`textSize')) "
|
|
}
|
|
if "$MA_nohet" == ""{
|
|
local predIntCmd2 "(scatter `id' `left1' if `use' == 4, msymbol(none) mlabel(`RFdistLabel') mlabcolor(black) mlabpos(3) mlabsize(`textSize')) "
|
|
}
|
|
}
|
|
if "$MA_nohet" == "" & "$MA_rjhby" != ""{
|
|
local hetGroupCmd "(scatter `id' `left1' if `use' == 4, msymbol(none) mlabel(`hetGroupLabel') mlabcolor(black) mlabpos(3) mlabsize(`textSize')) "
|
|
}
|
|
|
|
// OTHER BITS AND BOBS
|
|
|
|
local dispBox "none"
|
|
if "`nobox'" == ""{
|
|
local dispBox "square "
|
|
}
|
|
|
|
local boxsize = $MA_FBSC/150
|
|
|
|
if "$MA_FAVOURS" != ""{
|
|
local pos = strpos("$MA_FAVOURS", "#")
|
|
local leftfav = substr("$MA_FAVOURS",1,(`pos'-1))
|
|
local rightfav = substr("$MA_FAVOURS",(`pos'+1),(length("$MA_FAVOURS")-`pos'+1) )
|
|
}
|
|
if `h0' != . & "$MA_nulloff" == ""{
|
|
local leftfp = `DXmin' + (`h0'-`DXmin')/2
|
|
local rightfp = `h0' + (`DXmax'-`h0')/2
|
|
}
|
|
else{
|
|
local leftfp = `DXmin'
|
|
local rightfp = `DXmax'
|
|
}
|
|
|
|
|
|
// GRAPH APPEARANCE OPTIONS- ADDED v1.15
|
|
|
|
/*
|
|
if `"$MA_OPT"' != "" & strpos(`"$MA_OPT"',"m") == 0{(
|
|
global MA_OPT = `"$MA_OPT m()"'
|
|
}
|
|
*/
|
|
|
|
if `"$MA_BOXOPT"' != "" & strpos(`"$MA_BOXOPT"',"msymbol") == 0{ // make defaults if unspecified
|
|
global MA_BOXOPT = `"$MA_BOXOPT msymbol(square)"'
|
|
}
|
|
if `"$MA_BOXOPT"' != "" & strpos(`"$MA_BOXOPT"',"mcolor") == 0{ // make defaults if unspecified
|
|
global MA_BOXOPT = `"$MA_BOXOPT mcolor("180 180 180")"'
|
|
}
|
|
if `"$MA_BOXOPT"' == ""{
|
|
local boxopt "msymbol(`dispBox') msize(`boxsize') mcolor("180 180 180")"
|
|
}
|
|
else{
|
|
if strpos(`"$MA_BOXOPT"',"mla") != 0{
|
|
di as error "Option mlabel() not allowed in boxopt()"
|
|
exit
|
|
}
|
|
if strpos(`"$MA_BOXOPT"',"msi") != 0{
|
|
di as error "Option msize() not allowed in boxopt()"
|
|
exit
|
|
}
|
|
local boxopt `"$MA_BOXOPT msize(`boxsize')"'
|
|
}
|
|
if "$MA_classic" != ""{
|
|
local boxopt "mcolor(black) msymbol(square) msize(`boxsize')"
|
|
}
|
|
if "`box'" != ""{
|
|
local boxopt "msymbol(none)"
|
|
}
|
|
|
|
|
|
|
|
if `"$MA_DIAMOPT"' == ""{
|
|
local diamopt "lcolor("0 0 100")"
|
|
}
|
|
else{
|
|
if strpos(`"$MA_DIAMOPT"',"hor") != 0 | strpos(`"$MA_DIAMOPT"',"vert") != 0{
|
|
di as error "Options horizontal/vertical not allowed in diamopt()"
|
|
exit
|
|
}
|
|
if strpos(`"$MA_DIAMOPT"',"con") != 0{
|
|
di as error "Option connect() not allowed in diamopt()"
|
|
exit
|
|
}
|
|
if strpos(`"$MA_DIAMOPT"',"lp") != 0{
|
|
di as error "Option lpattern() not allowed in diamopt()"
|
|
exit
|
|
}
|
|
local diamopt `"$MA_DIAMOPT"'
|
|
}
|
|
|
|
|
|
|
|
if `"$MA_POINTOPT"' != "" & strpos(`"$MA_POINTOPT"',"msymbol") == 0{(
|
|
global MA_POINTOPT = `"$MA_POINTOPT msymbol(diamond)"'
|
|
}
|
|
if `"$MA_POINTOPT"' != "" & strpos(`"$MA_POINTOPT"',"msize") == 0{(
|
|
global MA_POINTOPT = `"$MA_POINTOPT msize(vsmall)"'
|
|
}
|
|
if `"$MA_POINTOPT"' != "" & strpos(`"$MA_POINTOPT"',"mcolor") == 0{(
|
|
global MA_POINTOPT = `"$MA_POINTOPT mcolor(black)"'
|
|
}
|
|
if `"$MA_POINTOPT"' == ""{
|
|
local pointopt "msymbol(diamond) msize(vsmall) mcolor("0 0 0")"
|
|
}
|
|
else{
|
|
local pointopt `"$MA_POINTOPT"'
|
|
}
|
|
if "$MA_classic" != "" & "`box'" == ""{
|
|
local pointopt "msymbol(none)"
|
|
}
|
|
|
|
|
|
|
|
if `"$MA_CIOPT"' != "" & strpos(`"$MA_CIOPT"',"lcolor") == 0{(
|
|
global MA_CIOPT = `"$MA_CIOPT lcolor(black)"'
|
|
}
|
|
if `"$MA_CIOPT"' == ""{
|
|
local ciopt "lcolor("0 0 0")"
|
|
}
|
|
else{
|
|
if strpos(`"$MA_CIOPT"',"hor") != 0 | strpos(`"$MA_CIOPT"',"vert") != 0{
|
|
di as error "Options horizontal/vertical not allowed in ciopt()"
|
|
exit
|
|
}
|
|
if strpos(`"$MA_CIOPT"',"con") != 0{
|
|
di as error "Option connect() not allowed in ciopt()"
|
|
exit
|
|
}
|
|
if strpos(`"$MA_CIOPT"',"lp") != 0{
|
|
di as error "Option lpattern() not allowed in ciopt()"
|
|
exit
|
|
}
|
|
local ciopt `"$MA_CIOPT"'
|
|
}
|
|
|
|
|
|
// END GRAPH OPTS
|
|
|
|
|
|
|
|
if "$MA_method1" == "D+L"{
|
|
tempvar noteposx noteposy notelab
|
|
qui{
|
|
summ `id'
|
|
gen `noteposy' = r(min) -1.5 in 1
|
|
summ `left1'
|
|
gen `noteposx' = r(mean) in 1
|
|
gen `notelab' = "NOTE: Weights are from random effects analysis" in 1
|
|
local notecmd "(scatter `noteposy' `noteposx', msymbol(none) mlabel(`notelab') mlabcolor(black) mlabpos(3) mlabsize(`textSize')) "
|
|
}
|
|
if "$MA_nowarning" != ""{
|
|
local notecmd
|
|
}
|
|
}
|
|
|
|
|
|
if "`overall'" != ""{
|
|
local overallCommand ""
|
|
qui drop if `use' == 5
|
|
qui summ `id'
|
|
local DYmin = r(min)
|
|
cap replace `noteposy' = r(min) -.5 in 1
|
|
}
|
|
|
|
// quick bodge to get overall- can't find log version!
|
|
tempvar tempOv ovLine ovMin ovMax h0Line
|
|
qui gen `tempOv' = `effect' if `use' == 5
|
|
sort `tempOv'
|
|
qui summ `id'
|
|
local DYmin = r(min)-2
|
|
local DYmax = r(max)+1
|
|
|
|
qui gen `ovLine' = `tempOv' in 1
|
|
qui gen `ovMin' = r(min)-2 in 1
|
|
qui gen `ovMax' = $borderline in 1
|
|
qui gen `h0Line' = `h0' in 1
|
|
|
|
if `"$MA_OLINEOPT"' == ""{
|
|
local overallCommand " (pcspike `ovMin' `ovLine' `ovMax' `ovLine', lwidth(thin) lcolor(maroon) lpattern(shortdash)) "
|
|
}
|
|
else{
|
|
local overallCommand `" (pcspike `ovMin' `ovLine' `ovMax' `ovLine', $MA_OLINEOPT) "'
|
|
}
|
|
if `ovLine' > `DXmax' | `ovLine' < `DXmin' | "`overall'" != ""{ // ditch if not on graph
|
|
local overallCommand ""
|
|
}
|
|
|
|
local nullCommand " (pcspike `ovMin' `h0Line' `ovMax' `h0Line', lwidth(thin) lcolor(black) ) "
|
|
|
|
// gap if "favours" used
|
|
if "`leftfav'" != "" | "`rightfav'" != ""{
|
|
local gap = "labgap(5)"
|
|
}
|
|
|
|
// if summary only must not have weights
|
|
local awweight "[aw= `weight']"
|
|
if "$MA_summaryonly" != ""{
|
|
local awweight ""
|
|
}
|
|
qui summ `weight'
|
|
if r(N) == 0{
|
|
local awweight ""
|
|
}
|
|
|
|
// rfdist off scale arrows only used when appropriate
|
|
qui{
|
|
tempvar rfarrow
|
|
gen `rfarrow' = 0
|
|
if "$MA_rfdist" != ""{
|
|
if "$MA_method1" == "D+L"{
|
|
replace `rfarrow' = 1 if `use' == 3 | `use' == 5
|
|
}
|
|
if "$MA_method2" == "D+L"{
|
|
replace `rfarrow' = 1 if `use' == 17 | `use' == 19
|
|
}
|
|
}
|
|
} // end qui
|
|
|
|
|
|
// final addition- if aspect() given but not xsize() ysize(), put these in to get rid of gaps
|
|
// need to fiddle to allow space for bottom title
|
|
// should this just replace the aspect option?
|
|
// suppose good to keep- most people hopefully using xsize and ysize and can always change themselves if using aspect
|
|
|
|
if strpos(`"$MA_OTHEROPTS"',"xsize") == 0 & strpos(`"$MA_OTHEROPTS"',"ysize") == 0 ///
|
|
& strpos(`"$MA_OTHEROPTS"',"aspect") > 0 {
|
|
|
|
local aspct = substr(`"$MA_OTHEROPTS"', (strpos(`"$MA_OTHEROPTS"',"aspect(")+7 ) , length(`"$MA_OTHEROPTS"') )
|
|
local aspct = substr(`"`aspct'"', 1, (strpos(`"`aspct'"',")")-1) )
|
|
if `aspct' > 1{
|
|
local xx = (11.5+(2-2*1/`aspct'))/`aspct'
|
|
local yy = 12
|
|
}
|
|
if `aspct' <= 1{
|
|
local yy = 12*`aspct'
|
|
local xx = 11.5-(2-2*`aspct')
|
|
}
|
|
global MA_OTHEROPTS = `"$MA_OTHEROPTS"' + " xsize(`xx') ysize(`yy')"
|
|
|
|
}
|
|
|
|
// switch off null if wanted
|
|
if "$MA_nulloff" != ""{
|
|
local nullCommand ""
|
|
}
|
|
|
|
***************************
|
|
*** GRAPH ***
|
|
***************************
|
|
|
|
#delimit ;
|
|
|
|
twoway
|
|
/* NOTE FOR RF, OVERALL AND NULL LINES FIRST */
|
|
`notecmd' `overallCommand' `nullCommand' `predIntCmd' `predIntCmd2' `hetGroupCmd'
|
|
/* PLOT BOXES AND PUT ALL THE GRAPH OPTIONS IN THERE */
|
|
(scatter `id' `effect' `awweight' if `use' == 1,
|
|
`boxopt'
|
|
yscale(range(`DYmin' `DYmax') noline )
|
|
ylabel(none) ytitle("")
|
|
xscale(range(`AXmin' `AXmax'))
|
|
xlabel(`lblcmd', labsize(`textSize2') )
|
|
yline($borderline, lwidth(thin) lcolor(gs12))
|
|
/* THIS BIT DOES favours. NOTE SPACES TO SUPPRESS IF THIS IS NOT USED */
|
|
xmlabel(`leftfp' "`leftfav' " `rightfp' "`rightfav' ", noticks labels labsize(`textSize')
|
|
`gap' /* PUT LABELS UNDER xticks? Yes as labels now extended */ )
|
|
xtitle("") legend(off) xtick("`xtick'") )
|
|
/* END OF FIRST SCATTER */
|
|
/* HERE ARE THE CONFIDENCE INTERVALS */
|
|
(pcspike `id' `lci' `id' `uci' if `use' == 1, `ciopt')
|
|
/* ADD ARROWS IF OFFSCALE USING offLeftX offLeftX2 offRightX offRightX2 offYlo offYhi */
|
|
(pcspike `id' `offLeftX' `offYlo' `offLeftX2' if `use' == 1, `ciopt')
|
|
(pcspike `id' `offLeftX' `offYhi' `offLeftX2' if `use' == 1, `ciopt')
|
|
(pcspike `id' `offRightX' `offYlo' `offRightX2' if `use' == 1, `ciopt')
|
|
(pcspike `id' `offRightX' `offYhi' `offRightX2' if `use' == 1, `ciopt')
|
|
/* DIAMONDS FOR SUMMARY ESTIMATES -START FROM 9 O'CLOCK */
|
|
(pcspike `DIAMleftY1' `DIAMleftX' `DIAMtopY' `DIAMtopX' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19, `diamopt')
|
|
(pcspike `DIAMtopY' `DIAMtopX' `DIAMrightY1' `DIAMrightX' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19, `diamopt')
|
|
(pcspike `DIAMrightY2' `DIAMrightX' `DIAMbottomY' `DIAMbottomX' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19, `diamopt')
|
|
(pcspike `DIAMbottomY' `DIAMbottomX' `DIAMleftY2' `DIAMleftX' if `use' == 3 | `use' == 5 | `use' == 17 | `use' == 19, `diamopt')
|
|
/* EXTENDED CI FOR RANDOM EFFECTS, SHOW DISTRIBUTION AS RECOMMENDED BY JULIAN HIGGINS
|
|
DOTTED LINES FOR INESTIMABLE DISTRIBUTION */
|
|
(pcspike `DIAMleftY1' `DIAMleftX' `DIAMleftY1' `tauLCI' if (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19) & `tau2' < ., `diamopt')
|
|
(pcspike `DIAMrightY1' `DIAMrightX' `DIAMrightY1' `tauUCI' if (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19) & `tau2' < ., `diamopt')
|
|
(pcspike `DIAMleftY1' `DIAMleftX' `DIAMleftY1' `tauLCI' if (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19) & `tau2' ==.b, `diamopt' lpattern(shortdash))
|
|
(pcspike `DIAMrightY1' `DIAMrightX' `DIAMrightY1' `tauUCI' if (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19) & `tau2' ==.b, `diamopt' lpattern(shortdash))
|
|
/* DIAMOND EXTENSION FOR RF DIST ALSO HAS ARROWS... */
|
|
(pcspike `id' `offLeftX' `offYlo' `offLeftX2' if (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19) & `rfarrow' == 1, `diamopt')
|
|
(pcspike `id' `offLeftX' `offYhi' `offLeftX2' if (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19) & `rfarrow' == 1, `diamopt')
|
|
(pcspike `id' `offRightX' `offYlo' `offRightX2' if (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19) & `rfarrow' == 1, `diamopt')
|
|
(pcspike `id' `offRightX' `offYhi' `offRightX2' if (`use' == 3 | `use' == 5 | `use' == 17 | `use' == 19) & `rfarrow' == 1, `diamopt')
|
|
/* COLUMN VARIBLES */
|
|
`lcolCommands1' `lcolCommands2' `lcolCommands3' `lcolCommands4' `lcolCommands5' `lcolCommands6'
|
|
`lcolCommands7' `lcolCommands8' `lcolCommands9' `lcolCommands10' `lcolCommands11' `lcolCommands12'
|
|
`rcolCommands1' `rcolCommands2' `rcolCommands3' `rcolCommands4' `rcolCommands5' `rcolCommands6'
|
|
`rcolCommands7' `rcolCommands8' `rcolCommands9' `rcolCommands10' `rcolCommands11' `rcolCommands12'
|
|
(scatter `id' `right1' if `use' != 4 & `use' != 0,
|
|
msymbol(none) mlabel(`rightLB1') mlabcolor("0 0 0") mlabpos(3) mlabsize(`textSize'))
|
|
(scatter `id' `right2' if `use' != 4 & `use' != 0,
|
|
msymbol(none) mlabel(`rightLB2') mlabcolor("0 0 0") mlabpos(3) mlabsize(`textSize'))
|
|
/* (scatter `id' `right2', mlabel(`use')) JUNK, TO SEE WHAT'S WHERE */
|
|
/* LAST OF ALL PLOT EFFECT MARKERS TO CLARIFY AND OVERALL EFFECT LINE */
|
|
(scatter `id' `effect' if `use' == 1, `pointopt' )
|
|
, $MA_OTHEROPTS /* RMH added */ plotregion(margin(zero));
|
|
|
|
#delimit cr
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
program define getWidth
|
|
version 9.0
|
|
|
|
// ROSS HARRIS, 13TH JULY 2006
|
|
// TEXT SIZES VARY DEPENDING ON CHARACTER
|
|
// THIS PROGRAM GENERATES APPROXIMATE DISPLAY WIDTH OF A STRING
|
|
// FIRST ARG IS STRING TO MEASURE, SECOND THE NEW VARIABLE
|
|
|
|
// PREVIOUS CODE DROPPED COMPLETELY AND REPLACED WITH SUGGESTION
|
|
// FROM Jeff Pitblado
|
|
|
|
qui{
|
|
|
|
gen `2' = 0
|
|
count
|
|
local N = r(N)
|
|
forvalues i = 1/`N'{
|
|
local this = `1'[`i']
|
|
local width: _length "`this'"
|
|
replace `2' = `width' +1 in `i'
|
|
}
|
|
|
|
} // end qui
|
|
|
|
end
|
|
|
|
|
|
|
|
exit
|
|
|
|
// METAN UPDATE
|
|
// ROSS HARRIS, DEC 2006
|
|
// MAIN UPDATE IS GRAPHICS IN THE _dispgby PROGRAM
|
|
// ADDITIONAL OPTIONS ARE lcols AND rcols
|
|
// THESE AFFECT DISPLAY ONLY AND ALLOW USER TO SPECIFY
|
|
// VARIABLES AS A FORM OF TABLE. THIS EXTENDS THE label(namevar yearvar)
|
|
// SYNTAX, ALLOWING AS MANY LEFT COLUMNS AS REQUIRED (WELL, LIMIT IS 10)
|
|
// IF rcols IS OMMITTED DEFAULT IS THE STUDY EFFECT (95% CI) AND WEIGHT
|
|
// AS BEFORE- THESE ARE ALWAYS IN UNLESS OMITTED USING OPTIONS
|
|
// ANYTHING ADDED TO rcols COMES AFTER THIS.
|
|
|
|
// v1.4 WAS GETTING THERE
|
|
// v1.5 SORT OUT EXTRA LINE AT THE TOP AND ALLOW "DOUBLE LINES"
|
|
// FOR FIXED AND RANDOM EFFECTS
|
|
|
|
// SOMETHING TO ADD- RETURN ES_2?
|
|
// v1.7 - TRY TO SORT OUT LABELLING
|
|
// CHANGED LABELS TO 7.3g -WORKS NICELY
|
|
// "FAVOURS" NOW WORKS- USES xmlabel
|
|
// v1.8 ADDED IN COUNTS OPTION, SORTED OUT TEXTSIZE, PROPER DEFINITION AND SPLIT OF VAR LABELS
|
|
|
|
// v1.9 DELETE UNECESSARY OPTIONS
|
|
// OH, AND ADD effect OPTION
|
|
// v1.10 FINAL TIDYING, USED Jeff Pitblado's SUGGESTION FOR getWidth
|
|
|
|
// v1.11 USE label() OPTIONS IF NO lcols rcols, WORK ON AUTO FIT TEXT
|
|
// v1.12 FURTHER WORK...
|
|
|
|
// v1.14 DONE ON 12TH OCTOBER, FINALLY DISCOVERED WHAT IS CAUSING PROBLEM
|
|
// WITH "NON-MATCHING CLOSE BRACE" AT END OF FILE- NO v7 STYLE IF STATEMENTS!
|
|
// EVERYTHING GOES ON A SEPARATE LINE NOW. PHEW.
|
|
|
|
// v1.15 NOW ADDING IN OPTIONS TO CONTROL BOXES, CI LINES, OVERALL
|
|
// TITLES WEREN'T SPREADING ACROSS SINCE OPTION TO CONTROL OVERALL TEXT- FIXED AGAIN
|
|
|
|
// v1.16 LAST ATTEMPT TO GET TEXT SIZE RIGHT! WORK OUT WHAT ASPECT SHOULD BE AND USE
|
|
// IF ASPECT DEFINED THEN DECREASE TEXT SIZE BY RATIO TO IDEAL ASPECT
|
|
|
|
// TEXT SCALING WORKING BETTER NOW
|
|
// LAST THING TO TRY TO SORT IS LOOK FOR LEFT OF DIAMOND AND MOVE HET STATS
|
|
// COULD PUT UNDERNEATH IF NOT MUCH SPACE? THIS WOULD BE GOOD v1.17
|
|
// STILL DEBATING WHETHER TO PUT favours BIT BELOW xticks...
|
|
|
|
// V19 LOTS OF COMMENTS FROM JONATHAN AND BITS TO DO. SUMMARY:
|
|
// aspect Y
|
|
// note if random weights Y
|
|
// update to v8 Y
|
|
// graph in mono Y
|
|
// extend overall text into plot Y
|
|
// labels Y
|
|
// help file not v8 yet
|
|
|
|
// v1.21 EVERY PROGRAM NOW CONVERTED TO v9.0, NO "CODE FOLLOWS BRACES!"
|
|
|
|
// WHAT ELSE DID PATRICK DO TO UPDATE TO v8?
|
|
|
|
// NO "#delimit ;" - I QUITE LIKE THIS THOUGH!
|
|
// GLOBALS ARE DECLARED WITHOUT = SIGN - EXCEPT WHEN USING STRING FUNCTION ETC. IT DOESN'T LIKE THIS!
|
|
// - WILL THIS EVER CAUSE PROBLEMS?
|
|
// - CAN'T BE BOTHERED TO CHANGE ALL THE NUMERIC ONES
|
|
// USE TOKENIZE INSTEAD OF PARSE - DONE
|
|
// USE di as err NOT in red, EXIT - DONE, PROPER RETURN CODES STILL NEEDED, MAYBE SOMEDAY!
|
|
// DECENT HELP FILE - USED, JUST ADD IN NEW BITS
|
|
|
|
// v1.22 ENCODE STUFF FOR metanby NOW LABORIOUSLY RECODED SO THAT GROUPS ARE IN ORIGINAL SORT ORDER
|
|
// THIS IS USEFUL IF YOU DON'T WANT STUFF IN ALPHA-NUMERIC ORDER, OR TO PUT "1..." "2..." ETC.
|
|
|
|
// counts OPTION DOES NOT WORK WITH MEAN DIFFERENCES- AND LOOKS LIKE IT NEVER DID- PUT IN
|
|
// DO OWN LINES FOR OVERALL ETC. EXTENDS TOO FAR
|
|
// LABELS NEVER RUN TO FOUR LINES- SORT OUT- QUICK SOLU- DO FIVE TIMES AND DROP ONE!
|
|
|
|
// v1.23 USES pcspike FOR OVERALL AND NULL LINES TO PREVENT OVER-EXTENDING
|
|
// NOW HAS OPTION FOR USER DEFINED "SECOND" ANALYSIS
|
|
|
|
// v1.24 ALLOW USER TO COMPLETELY DEFINE ANALYSIS WITH WEIGHTS
|
|
|
|
// v2.34 problem with nosubgroup nooverall sorted out (this combination failed)
|
|
|
|
********************
|
|
** May 2007 fixes **
|
|
********************
|
|
|
|
// "nostandard" had disappeared from help file- back in
|
|
// I sq. in return list
|
|
// sorted out the extra top line that appears in column labels
|
|
// fixed when using aspect ratio using xsize and ysize so inner bit matches graph area- i.e., get rid of spaces for long/wide graphs
|
|
// variable display format preserved for lcols and rcols
|
|
// abbreviated varlist now allowed
|
|
// between groups het. only available with fixed
|
|
// warnings if any heterogeneity with fixed (for between group het if any sub group has het, overall est if any het)
|
|
// nulloff option to get rid of line
|
|
|