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.

2508 lines
80 KiB
Plaintext

7 months ago
*! 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 metan7 , rclass
version 7.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) SAVING(passthru) noBOX
XLAbel(passthru) XTick(passthru) FORCE BOXSCA(real 1.0) BOXSHA(integer 4)
TEXTS(real 1.0) T1title(string) T2title(string) LEGEND(string)
B1title(string) B2title(string) noWT noSTATS COUNTS WGT(varlist numeric max=1)
GROUP1(string) GROUP2(string) EFFECT(string) ] ;
#delimit cr
global MA_FBSH=`boxsha'
global MA_FBSC=`boxsca'
global MA_ESLA="`effect'"
if "`legend'"!="" { global S_TX="`legend'" }
else { global S_TX "Study" }
*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'" }
if (`texts'>2 | `texts'<0.1 ) {local texts=1}
global MA_FTSI=`texts'
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'
#delimit ;
global S_1 "."; global S_2 "."; global S_3 "."; global S_4 ".";
global S_5 "."; global S_6 "."; global S_7 "."; global S_8 ".";
global S_9 "."; global S_10 ".";global S_11 ".";global S_12 ".";
#delimit cr
*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'"!="" {
parse "`label'", parse("=,")
while "`1'"!="" {
cap confirm var `3'
if _rc!=0 {
di in re "Variable `3' not defined"
exit _rc
}
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') }
}
}
else { 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 in re "Option invalid with user-defined weights"
exit _rc
}
confirm numeric variable `wgt'
local wgt "wgt(`wgt')"
}
} /* End of quietly loop */
parse "`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
}
}
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 in re "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 in re "Specify fixed or random effect/s model"
exit _rc
}
}
cap assert "`cc'"==""
if _rc!=0 {
di in re "Continuity correction not valid with unless individual counts specified"
exit _rc
}
local callalg "iv_init"
local sumstat "ES"
} /*end of 2-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 in re "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 in re "Non integer cell counts found"
exit _rc
}
}
cap assert ( (`1'>=0) & (`2'>=0) & (`3'>=0) & (`4'>=0) )
if _rc!=0 {
di in re "Non-positive cell counts found"
exit _rc
}
if "`cc'"!="" {
*Ensure Continuity correction is valid
if "`peto'"!="" {
di in re "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 in re "Invalid continuity correction: specify a constant number eg metan ... , cc(0.166667)"
exit
}
cap assert (`cc'>=0) & (`cc'<1)
if _rc!=0 {
di in re "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 in re "Invalid specifications for combining trials"
exit 198
}
*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 in re "Chi-squared option invalid for `method' `sumstat'"
exit
}
if ("`sumstat'"!="OR" | "`method'"=="D+L" | "`method'"=="Peto" ) & "`breslow'"!="" {
di in re "Breslow-Day heterogeneity option not available for `method' `sumstat'"
exit
}
if ("`sumstat'"!="OR" & "`sumstat'"!="RR") & "`log'"!="" {
di in re "Log option not appropriate for `sumstat'"
exit
}
if "`keep'"=="" {
cap drop _SS
qui gen _SS =`1'+`2'+`3'+`4'
}
} /* end of binary variable setup */
}
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 in re "Wrong number of variables specified"
exit _rc
}
if "`integer'"=="" {
cap assert ((int(`1')==`1') & (int(`4')==`4'))
if _rc!=0 {
di in re "Non integer sample sizes found"
exit _rc
}
}
cap assert (`1'>0 & `4'>0)
if _rc!=0 {
di in re "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 in re "Invalid specifications for combining trials"
exit 198
}
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" }
if "`counts'"!="" {
di in bl "Data option counts not available with continuous data"
local counts
}
if "`cc'"!="" {
di in re "Continuity correction not available with continuous data"
exit
}
local callalg "MD"
if "`keep'"=="" {
cap drop _SS
qui gen _SS =`1'+`4'
}
} /*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')"
}
`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'") /*
*/ `groupla' `nextcall' `sstat'
if $S_8<0 {
di in re "Insufficient data to perform this meta-analysis"
}
/*Saved results: to keep compatible with v5 have retained $S_. macros.
Now assign also to r() macros
The macro names and descriptions in the prev version are
Name v7.0 v5.0
pooled ES r(ES) $S_1*
se(ES) - not if RR or OR r(seES) $S_2
se(logES) - only if RR/OR, non-logged
r(selogES) $S_2
lower CI of pooled ES r(ci_low) $S_3
upper CI of pooled ES r(ci_upp) $S_4
Z-value for ES r(z) $S_5
p(Z) r(p_z) $S_6
chi2 heterogeneity r(het) $S_7
df (#studies-1) r(df) $S_8
p(chi2 heterogeneity) r(p_het) $S_9
Chi2 for ES (OR only) r(chi2) $S_10
p(chi2) (OR only) r(p_chi2) $S_11
Estimated tau^2(D&L only) r(tau2) $S_12
Effect measure (RR,SMD..) r(measure) -
*unless log option used..
Overall event rate [binary data; group 1)
r(tger) -
Overall event rate [binary data; group 2)
r(cger) -
*/
*return log or eform as appropriate for OR/RR
return scalar ES=$S_1
if ("`sumstat'"=="OR" | "`sumstat'"=="RR") & ("`log'"=="") { return scalar selogES=$S_2 }
else if ("`sumstat'"=="ES" & "`eform'"!="") { return scalar selogES=$S_2 }
else { return scalar seES=$S_2 }
return scalar ci_low=$S_3
return scalar ci_upp=$S_4
return scalar z=$S_5
return scalar p_z=$S_6
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 7.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) noOVERALL
noWT noSTATS LOG BRESLOW COUNTS WGT(varlist numeric max=1) noGROUPLA ] ;
#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
parse "`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 str20 `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
}
}
*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) */
}
}
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" {
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) */
}
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'") `overall' `wt' /*
*/ `stats' `counts' `log' `groupla' `udwind' `cornfield'
end
program define Peto
version 7.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) noOVERALL noWT noSTATS LOG COUNTS ] ;
#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
parse "`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 str20 `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'="."}
*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)
gen `weight' =100*`v'/`V'
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'") `overall' `wt' `stats' `counts' `log'
end
program define RR
version 7.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) noOVERALL noWT noSTATS LOG COUNTS
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
parse "`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 str20 `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'
*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)
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" {
cap gen `weight'=.
iv `lnrr' `v', method(`method') `randomi' `exp'
replace `weight'=100/( (`v'+$S_12)*($MA_W) )
}
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'") `overall' `wt' /*
*/ `stats' `counts' `log' `udwind'
end
program define RD
version 7.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) noOVERALL noWT noSTATS COUNTS WGT(varlist numeric max=1) ] ;
#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
parse "`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 str20 `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 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)
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" {
iv `rd' `v', method(`method') `randomi'
replace `weight'=100/( (`v'+$S_12)*($MA_W) )
}
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'") `overall' `wt' `stats' `counts' `udwind'
end
program define MD
version 7.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) noOVERALL noWT noSTATS COUNTS WGT(string) ] ;
#delimit cr
qui {
tempvar n1 x1 sd1 n2 x2 sd2 use n s md v se ill iul weight id qhet rawdata
parse "`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 str40 `rawdata'= string(`n1') + " " + string(`x1') +" (" + string(`sd1') + /*
*/ ") ; " + string(`n2') + " " + string(`x2') +" (" + string(`sd2') +") "
replace `rawdata'= trim(`rawdata')
}
else {gen str1 `rawdata'="."}
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) )
}
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'") `overall' `wt' `stats' `udwind'
end
program define iv_init
version 7.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) noOVERALL noWT noSTATS EFORM WGT(string) ] ;
#delimit cr
qui {
tempvar es se use v ill iul weight id rawdata
parse "`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'"!="" {
gen `weight' = `wgt' if `use'==1
udw `es' `v', wgt(`weight') `exp'
replace `weight'=100*`wgt'/($MA_W)
local udwind "wgt(`wgt')"
}
else {
iv `es' `v', method(`method') `exp' randomi
*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'") `overall' `wt' `stats' `eform' /*
*/ `var3' `udwind'
end
program define iv
version 7.0
#delimit ;
syntax varlist(min=2 max=2 default=none numeric) [if] [in] [,
METHOD(string) RANDOMI EXP ] ;
#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
parse "`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') )
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)
end
program define udw
* user defined weights to combine trials
version 7.0
#delimit ;
syntax varlist(min=2 max=2 default=none numeric) [if] [in] [,
METHOD(string) EXP WGT(varlist numeric max=1) ] ;
#delimit cr
tempvar stat v w e_w varcomp qhet
tempname W E_W OV W2 Vnum V QHET
parse "`varlist'", parse(" ")
gen `stat'=`1'
gen `v' =`2'
gen `w' =`wgt' if `stat'!=.
sum `w',meanonly
scalar `W'=r(sum)
if `W'==0 {
di in re "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)
end
program define _disptab
version 7.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) noOVERALL noWT noSTATS COUNTS LOG EFORM noGROUPLA SORTBY(string)
WGT(string) VAR3 CORNFIELD ] ;
#delimit cr
tempvar effect se lci uci weight use label tlabel rawdata id
parse "`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 str40 `rawdata' = `8'
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" {
#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')";
gen _WT=`weight';label var _WT "`method' weight";
#delimit cr
}
preserve
if "`overall'"=="" {
**If overall figure requested, add an extra line to contain overall stats
qui {
local nobs1=_N+1
set obs `nobs1'
replace `effect'= ($S_1) in `nobs1'
replace `lci'=($S_3) in `nobs1'
replace `uci'=($S_4) in `nobs1'
replace `weight'=100 in `nobs1'
replace `use'=5 in `nobs1'
replace `label' = "Overall" in `nobs1'
if "`counts'"!="" { replace `rawdata'="$MA_ODC" in `nobs1' }
replace `label' = "Overall" in `nobs1'
}
}
local usetot=$S_8+1
count if `use'==2
local alltot=r(N)+`usetot'
gen `id'=_n
sort `use' `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 {
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 ( (`use'[`i']==1) | (`use'[`i']==5) ) {
if (`use'[`i'])==1 {
*trial results
di in gr `tlabel'[`i'] _cont
}
else {
*overall
di in gr _dup(21) "-" "+" _dup(11) "-" "`insert'" _dup(20) "-" _n /*
*/ "`method' pooled `log'`sumstat'" _cont
}
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
}
di in gr _dup(21) "-" "+" _dup(51) "-"
if "`overall'"=="" {
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. */
if "`graph'"=="" & `usetot'>0 {
_dispgby `effect' `lci' `uci' `weight' `use' `label' `rawdata', `log' /*
*/ `xlabel' `xtick' `force' sumstat(`sumstat') `saving' `box' t1("`t1'") /*
*/ t2("`t2'") b1("`b1'") b2("`b2'") `overall' `wt' `stats' `counts' `eform' /*
*/ `groupla' `cornfield'
}
restore
end
program define metanby
version 7.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) 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) noWT noSTATS COUNTS noBOX noGROUPLA ] ;
#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 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 "`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" }
*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
sort `by' `sortby' `id'
*Keep only neccesary data (have to put preserve here in order to keep _ES etc)
preserve
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 `tsig'=.
gen `psig'=.
*Convert "by" variable to numeric if its a string variable
cap confirm numeric var `by'
if _rc>0 {
encode `by', gen(`by2')
drop `by'
rename `by2' `by'
}
*Create new "by" variable to take on codes 1,2,3..
gen `newby'=(`by'>`by'[_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'
*Put cell counts in subtotal row
if ("`counts'"!="" & "`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'
}
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 `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' }
}
*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)
sort `newby' `use' `sortby' `id'
by `newby': gen `expand'=1 + 2*(_n==1) + (_n==1 & "`subgroup'"=="")
replace `expand'=1 if `use'==5
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 */
* 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' {
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 {
`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'
}
}
*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')
}
}
}
*Label attatched (if any) to byvar
local lbl: value label `by'
sum `by' if `newby'==`j'
local byvlu=r(mean)
if "`lbl'"=="" { local lab "`by'==`byvlu'" }
else { local lab: label `lbl' `byvlu' }
replace `label' = "`lab'" if ( `use'==0 & `newby'==`j')
replace `label' = "Subtotal" if ( `use'==3 & `newby'==`j')
local j=`j'+1
}
} /*End of quietly loop*/
*Put table up (if requested)
sort `newby' `use' `sortby' `id'
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) & "`subgroup'"=="") | (`use'[`i']==5) {
*Subgroup effect size or overall effect size
if (`use'[`i'])==3 {
di in gr " Sub-total" _col(22) "|"
}
if (`use'[`i'])==5 {
if $IND!=$OVE {
local insert "[$OVE% Conf. Interval]"
}
di in gr "Overall" _col(22) "|" _col(34) "`insert'"
}
if "`ww'"=="." { local ww }
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'])==5 {
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
}
*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" }
di
local i=1
while `i'<= _N {
if ("`subgroup'"=="" & (`use'[`i'])==0) | ( (`use'[`i'])==5) {
di in gr _n `tlabel'[`i'] _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 "`method'"=="D+L" {
di in ye " " %7.4f `tau2'[`i'] _cont
}
if (`use'[`i']==5) & ("`subgroup'"=="") {
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
*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) {
di _n in gr `tlabel'[`i'] _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 table display */
if "`overall'"=="" {
*need to return overall effect to $S_1 macros and so on...
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]
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'
}
}
else {
#delimit ;
global S_1 "."; global S_2 "."; global S_3 "."; global S_4 ".";
global S_5 "."; global S_6 "."; global S_7 "."; global S_8= `nostud';
global S_9 "."; global S_10 ".";global S_11 ".";global S_12 ".";
global S_13 ".";global S_14 ".";
#delimit cr
}
if "`graph'"=="" {
_dispgby `effect' `lci' `uci' `weight' `use' `label' `rawdata' `wtdisp', /*
*/ `log' `xlabel' `xtick' `force' sumstat(`sumstat') `saving' `box' t1("`t1'") /*
*/ t2("`t2'") b1("`b1'") b2("`b2'") `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
by `by': gen `tempsum'=sum(`weight')
by `by': replace `tempsum'=`tempsum'[_N]
gen _WT=`weight'*100/`tempsum'
local sg "(subgroup) "
}
cap label var _WT "`method' `sg'% weight"
}
}
end
program define _dispgby
version 7.0
#delimit ;
syntax varlist(min=6 max=8 default=none ) [if] [in] [,
LOG XLAbel(string) XTICK(string) FORCE SAVING(string) noBOX SUMSTAT(string)
T1(string) T2(string) B1(string) B2(string) noOVERALL noWT noSTATS COUNTS EFORM
noGROUPLA CORNFIELD ];
#delimit cr
tempvar effect lci uci weight wtdisp use label tlabel id yrange xrange Ghsqrwt rawdata
parse "`varlist'", parse(" ")
qui {
gen `effect'=`1'
gen `lci' =`2'
gen `uci' =`3'
gen `weight'=`4'
gen byte `use'=`5'
*Use is now coded:
*0: blank line, except for text containing "by"
*1: trial
*2: excluded trial
*3. subgroup effect (in which case `label' or `6' is to contain the name of the subgroup)
*4. blank line
*5. overall effect
*9. missed/not considered
*As before effect sizes are held elsewhere
gen str10 `label'=""
replace `label'=`6'
count if (`use'==1 | `use'==2)
local ntrials=r(N)
count if (`use'>=0 & `use'<=5)
local ymax=r(N)
gen `id'=`ymax'-_n+1 if `use'<9
gen str40 `rawdata' = `7'
compress `rawdata'
if "`8'"!="" {
gen `wtdisp'=`8'
}
else {
gen `wtdisp'=`weight'
}
format `wtdisp' %5.1f
sum `lci'
local Gxlo=r(min) /* minimum of CIs*/
sum `uci'
local Gxhi=r(max) /* maximum of CIs*/
local h0=0
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 `Gxlo'<1e-8 {local Gxlo=1e-8}
if `Gxhi'>1e8 {local Gxhi=1e8}
}
if "`cornfield'"!="" {
replace `lci'=`log'(1e-9) if ( (`lci'==. | `lci'==0) & (`effect'!=. & `use'==1) )
replace `uci'=`log'(1e9) if ( (`uci'==.) & (`effect'!=. & `use'==1) )
}
local flag1=0
if "`xtick'"!="" {
* capture inappropriate tick
cap assert ("`xlog'"=="" ) | /*
*/ ( ( min(`xtick' ,`Gxhi')>1e-8 ) & (max(`xtick' ,`Gxlo')<1e8) )
if _rc!=0 {
local flag1=10
local xtick "`h0'"
}
}
else {
local xtick "`h0'"
}
if "`xlabel'"!="" {
* capture inappropriate label
cap {
assert ("`xlog'"=="" ) | /*
*/ ( ( min(`xlabel',`Gxhi')>1e-8 ) & (max(`xlabel',`Gxlo')<1e8) )
}
if _rc!=0 {
local flag1=10
local xlabel
}
else {
if "`force'"!="" {
parse "`xlabel'", parse(",")
if "`3'"!="" {
local Gxlo=`h0'
local Gxhi=`h0'
}
}
}
}
if "`xlabel'"=="" | (`flag1'>1) {
local Gmodxhi=max( abs(`xlog'(`Gxlo')),abs(`xlog'(`Gxhi')))
if `Gmodxhi'==. {local Gmodxhi=2}
local Gxlo=`xexp'(-`Gmodxhi')
local Gxhi=`xexp'( `Gmodxhi')
local xlabel "`Gxlo',`h0',`Gxhi'"
}
local Gxlo=`xlog'(min(`xlabel',`xtick',`Gxlo'))
local Gxhi=`xlog'(max(`xlabel',`xtick',`Gxhi'))
local Gxlo1=`Gxlo'-0.1*`Gxhi'
local Gxrange=(`Gxhi'-`Gxlo')
local Gyhi=`id'[1]
local Gxh20=`Gxhi'+`Gxrange'*0.2
local Gxh40=`Gxhi'+`Gxrange'*0.4
local Gxh60=`Gxhi'+`Gxrange'*0.6
local Gxh80=`Gxhi'+`Gxrange'*0.8
local Gxh100=`Gxhi'+`Gxrange'*1.0
gen `xrange'=`xexp'(`Gxlo') in 1
*If user wants no counts (c), stats (s) or weights (w) , use entire window for trial plots
if ("`stats'"!="" & "`wt'"!="" & "`counts'"=="" ) {
local Txhi=`Gxhi'
}
*If user wants s&w (default) or c&w use Gxh60 (60% of graph range) for figures
if (("`stats'"=="" & "`wt'"=="" & "`counts'"=="" ) | ("`stats'"!="" & "`wt'"=="" & "`counts'"!="" )) {
local Txhi=`Gxh60'
}
*If user wants s or c alone use Gxh40 (40% of range)
if (("`stats'"=="" & "`wt'"!="" & "`counts'"=="" ) | ("`stats'"!="" & "`wt'"!="" & "`counts'"!="" )) {
local Txhi=`Gxh40'
}
*If user wants w alone use Gxh20
if ("`stats'"!="" & "`wt'"=="" & "`counts'"=="" ) {
local Txhi=`Gxh20'
}
*If user wants s&c use Gxh80
if ("`stats'"=="" & "`wt'"!="" & "`counts'"!="" ) {
local Txhi=`Gxh80'
}
*If user wants all 3 use Gxh100
if ("`stats'"=="" & "`wt'"=="" & "`counts'"!="" ) {
local Txhi=`Gxh100'
}
replace `xrange'=`xexp'(`Txhi') in 2
gen `yrange'=0 in 1
replace `yrange'=`Gyhi'+2 in 2
cap label drop tmpyl
cap label drop tmpxl
* Study legend now removed
label define tmpyl 0 " "
label define tmpxl `h0' " "
label values `yrange' tmpyl
label values `xrange' tmpxl
*Label x-axis and top right *if stats requested
if "`sumstat'"=="OR" {local sscale "`log' Odds ratio"}
else if "`sumstat'"=="RR" {local sscale "`log' Risk ratio"}
else if "`sumstat'"=="RD" {local sscale "Risk difference"}
else if "`sumstat'"=="WMD" {local sscale "Mean difference"}
else if "`sumstat'"=="SMD" {local sscale "Standardised mean difference"}
else if ("`sumstat'"=="ES" & "$MA_ESLA"!="") { local sscale "$MA_ESLA" }
else if "`sumstat'"=="ES" {local sscale "Effect size"}
if "`t1'"=="." {local t1 }
else {
local t1=substr("`t1'",2,.)
local t1 "t1(`t1')"
}
if "`t2'"=="." {local t2 }
else {
local t2=substr("`t2'",2,.)
local t2 "t2(`t2')"
}
if "`b2'"=="." { local b2 "`sscale'"}
else {
*Revise position of b2 title: graph command doesn't put it in the right place
local b2=substr("`b2'",2,.)
}
if "`saving'"!="" {local saving "saving(`saving')" }
else { local saving }
gph open, `saving'
if "`b1'"=="." {
graph `yrange' `xrange', s(i) xli(`h0') `Glog' xlabel(`h0') /*
*/ noaxis yla(0) gap(10) `t1' `t2' b2(" ")
}
else {
graph `yrange' `xrange', s(i) xli(`h0') `Glog' xlabel(`h0') /*
*/ noaxis yla(0) gap(10) `t1' `t2' b1(" ") b2(" ")
}
local r5=r(ay)
local r6=r(by)
local r7=r(ax)
local r8=r(bx)
local Aytexs=($MA_FTSI)*max(200, min(700, (600-20*(`ymax'-15)) ) )
local Axtexs=($MA_FTSI)*max(130, min(360,(0.6*`Aytexs')) )
gph font `Aytexs' `Axtexs'
gph pen 1
local Axh0 =`r7'*(`xlog'(`h0'))+`r8'
local Axlo =`r7'*(`Gxlo') +`r8'
local Axloe =`r7'*(`Gxlo') +`r8' -1500
local Axhi =`r7'*(`Gxhi') +`r8'
local Axhie =`r7'*(`Gxhi') +`r8' + 1500*( ("`wt'"=="") | ("`stats'"=="") | ("`counts'"!="") )
local Axh20 =`r7'*(`Gxh20') +`r8'
local Axh40 =`r7'*(`Gxh40') +`r8'
local Axh60 =`r7'*(`Gxh60') +`r8'
local Axh80 =`r7'*(`Gxh80') +`r8'
local Axh100=`r7'*(`Gxh100')+`r8'
*add x-axis line and label manually
gph line `r6' `Axloe' `r6' `Axhie'
local yb=`r6'+1000
gph line `r6' `Axh0' `yb' `Axh0'
local yb=`r6'+2400+max(0,(1000-100*`ymax'))
gph text `yb' `Axh0' 0 0 `b2'
if "`b1'"!="." {
local yb=`r6'+3000+max(0,(1200-100*`ymax'))
local b1=substr("`b1'",2,.)
if substr("`b1'",1,3)=="*I:" {
*"Favours ..." labels
local flab= substr("`b1'",4,.)
tokenize "`flab'" , parse(*)
if "`1'"!="" {
local xt=`Axh0'-1000
gph text `yb' `xt' 0 1 `1'
}
if "`3'"!="" {
local xt=`Axh0'+1000
gph text `yb' `xt' 0 -1 `3'
}
}
else {
gph text `yb' `Axh0' 0 0 `b1'
}
}
*add xtick & xlabel manually
tokenize "`xlabel'", parse(,)
while "`1'"!="" {
local x=`1'
if (`x'>10e8) { local x="10e8" }
if ((`x'<=-10e8) & (`h0'==0)) { local x="-10e8" }
local Ax=`r7'*(`xlog'(`x')) +`r8'
local Ayh=`r6'
local Ayl=`r6'+400
local Ayt=`r6'+1700
gph line `Ayh' `Ax' `Ayl' `Ax'
if ((`x'<10e-6) & (`h0'==1)) { local x="0.00000" }
if ((`x'<10e4) & (`x'>-10e4)) { local x=substr("`x'",1,7) }
gph text `Ayt' `Ax' 0 0 `x'
mac shift 2
}
tokenize "`xtick'", parse(,)
while "`1'"!="" {
local Ax=`r7'*(`xlog'(`1')) + `r8'
local Ayh=`r6'
local Ayl=`r6'+400
local Ayt=`r6'+1000
gph line `Ayh' `Ax' `Ayl' `Ax'
mac shift 2
}
*Add legend
local Ayhi =(`Gyhi'+2)*`r5'+`r6'
local Axtexh=50+max(0,min(2400,`ymax'*60-700))
local Ayhead=`r5'*(`ymax'+1) + `r6'
gph text `Ayhead' `Axtexh' 0 -1 $S_TX
/*Order of text: stats, counts, weights (where selected)*/
*New positionings reduce gaps between stats/weight/counts
if ("`stats'"=="") {
*Align stats first at Axhi. Use prev line if `sscale' too long (>12chrs)
* local lenssc=length("`sscale'")
* if `lenssc'<13 {
* gph text `Ayhead' `Axhi' 0 -1 `sscale' ($IND% CI)
* }
* else {
local Ayhead2=`r5'*(`ymax'+1.65) + `r6'
gph text `Ayhead2' `Axhi' 0 -1 `sscale'
gph text `Ayhead' `Axhi' 0 -1 ($IND% CI)
* }
}
if ("`counts'"!="") {
*Align counts 2nd if both stats & weight
if ("`stats'"=="") {
local Ax2hi1=`Axh20'+(`Axh60'-`Axh20')*(max(0.4, min(1,2-0.07*`ymax') ) )
local Ax2hi2=`Axh20'+(`Axh80'-`Axh20')*(max(0.4, min(1,2-0.07*`ymax') ) )
*local Ax2hi1=`Axh60'
*local Ax2hi2=`Axh80'
}
else {
local Ax2hi1=`Axhi'+(`Axh20'-`Axhi')*(max(0.4, min(1,2-0.07*`ymax') ) )
local Ax2hi2=`Axhi'+(`Axh40'-`Axhi')*(max(0.4, min(1,2-0.07*`ymax') ) )
*local Ax2hi1=`Axh20'
*local Ax2hi2=`Axh40'
}
local yt=`Ayhead'-max(200, min(1000,1600-40*`ymax'))
gph text `yt' `Ax2hi1' 0 0 No. of events
* gph font 500 270
gph text `Ayhead' `Ax2hi1' 0 1 $MA_G1L
gph text `Ayhead' `Ax2hi2' 0 1 $MA_G2L
}
if ("`wt'"=="") {
if ("`stats'"=="" & "`counts'"!="") {
*local Ax3hi=`Axh100'
local Ax3hi=`Axh20'+(`Axh100'-`Axh20')*(max(0.4, min(1,2-0.07*`ymax') ) )
}
else if ("`stats'"!="" & "`counts'"=="") {
local Ax3hi=`Axh20'
}
else {
*local Ax3hi=`Axh60'
local Ax3hi=`Axh20'+(`Axh60'-`Axh20')*(max(0.4, min(1,2-0.07*`ymax') ) )
}
gph text `Ayhead' `Ax3hi' 0 1 % Weight
}
gen `Ghsqrwt'=0.5*sqrt(`weight')/2
local flag=0
while `flag'<1 {
cap assert `Ghsqrwt'<0.5 if (`use'==1)
if _rc!=0 { replace `Ghsqrwt'=0.9*`Ghsqrwt' }
else { local flag=10}
}
replace `Ghsqrwt'=($MA_FBSC)*`Ghsqrwt'
local flag2=0
local flag3=0
local i=1
gph pen 2
while `i'<=`ymax' {
local Aytcen= `r5'*(`id'[`i']-0.2)+`r6' /* text label centre */
local Aygcen= `r5'*(`id'[`i'])+`r6' /* graphics label centre */
*label to put on left hand
local tx = `label'[`i']
local Axtexs=`Axtexh'+400
*use=0 => blank line except for "by" legend
if (`use'[`i']==0) {
gph pen 3
gph text `Aytcen' `Axtexh' 0 -1 `tx'
}
*use=1 => individual trial
if `use'[`i']==1 {
gph pen 2
gph text `Aytcen' `Axtexs' 0 -1 `tx'
if `lci'[`i']==. | `uci'[`i']==. { local flag2=10 }
else {
* Define lower/upper points on x-line, and centre on y-axis
local Axlpt= `r7'*(`xlog'( `lci'[`i'] ))+`r8'
local Axupt= `r7'*(`xlog'( `uci'[`i'] ))+`r8'
if (`Axupt' < `Axlo') | (`Axlpt' > `Axhi') {
* If CI is totally off scale draw (triangular) arrow
local Ayco1=`r5'*(`id'[`i']-0.2)+`r6'
local Ayco2=`r5'*(`id'[`i']+0.2)+`r6'
if `Axupt'<=`Axlo' {
local Axlpt =`Axlo'
local Axco1=`r7'*(`Gxlo')+`r8'
local Axco2=`r7'*(`Gxlo')+`r8'+450
}
if `Axlpt'>=`Axhi' {
local Axupt =`Axhi'
local Axco1=`r7'*(`Gxhi')+`r8'
local Axco2=`r7'*(`Gxhi')+`r8'-450
}
gph line `Aygcen' `Axco1' `Ayco2' `Axco2'
gph line `Ayco2' `Axco2' `Ayco1' `Axco2'
gph line `Ayco1' `Axco2' `Aygcen' `Axco1'
}
else {
local Axcen =`r7'*`xlog'(`effect'[`i'])+`r8'
* Define box size
local Ahboxl =abs(`r5'*( `Ghsqrwt'[`i'] ))
local Ay1cord=`Aygcen'+`Ahboxl'
local Ax1cord=`Axcen' -`Ahboxl'
local Ay2cord=`Aygcen'-`Ahboxl'
local Ax2cord=`Axcen' +`Ahboxl'
if (`Axlpt' < `Axlo') | (`Axupt' > `Axhi') {
* CI is on but not totaly on scale: draw arrow at end of CI
local Ayco1=`r5'*(`id'[`i']-0.1)+`r6'
local Ayco2=`r5'*(`id'[`i']+0.1)+`r6'
if `Axlpt' < `Axlo' {
local Axlpt =`Axlo'
local Axco1=`r7'*(`Gxlo')+`r8'
local Axco2=`r7'*(`Gxlo')+`r8'+350
gph line `Aygcen' `Axco1' `Ayco1' `Axco2'
gph line `Aygcen' `Axco1' `Ayco2' `Axco2'
}
if `Axupt' > `Axhi' {
local Axupt =`Axhi'
local Axco1=`r7'*(`Gxhi')+`r8'
local Axco2=`r7'*(`Gxhi')+`r8'-350
gph line `Aygcen' `Axco1' `Ayco1' `Axco2'
gph line `Aygcen' `Axco1' `Ayco2' `Axco2'
}
}
*draw line for CI
gph line `Aygcen' `Axlpt' `Aygcen' `Axupt'
*either draw box for ES/weight...
if "`box'"=="" {
if (`Ax1cord' >=`Axlo') & (`Ax2cord'<=`Axhi') {
gph box `Ay1cord' `Ax1cord' `Ay2cord' `Ax2cord' $MA_FBSH
}
else {local flag2=10}
}
*...or simply plot ES (as circle) instead of box
if "`box'"!="" {
if (`Ax1cord' >=`Axlo') & (`Ax2cord'<=`Axhi') {
local ptsize=250*$MA_FBSC
gph point `Aygcen' `Axcen' `ptsize' 1
}
else {local flag2=10}
}
}
}
}
*use=2 => Excluded trial
if (`use'[`i']==2) {
gph text `Aytcen' `Axtexs' 0 -1 `tx'
}
*use=4 => blank line: no text or graphic necessary (above displays nothing)
*use=3 => subgroup effect size (display by default), or...
*use=5 => overall effect size (display by default)
if ( ((`use'[`i']==3) & ("`subgrp'"=="")) | /*
*/ ((`use'[`i']==5) & ("`overall'"=="")) ) {
if (`use'[`i']==3) { gph pen 3 }
if (`use'[`i']==5) { gph pen 5 }
gph text `Aytcen' `Axtexh' 0 -1 `tx'
local Aycol=`r5'*((`id'[`i'])-0.2)+`r6'
local Aycoh= `r5'*((`id'[`i'])+0.2)+`r6'
*the following 4 are necc in case diamond is chopped off
local Aycenl1=`Aygcen'
local Aycenl2=`Aygcen'
local Aycenh1=`Aygcen'
local Aycenh2=`Aygcen'
local Axcol=`r7'*(`xlog'(`lci'[`i']))+`r8'
local Axcen=`r7'*(`xlog'(`effect'[`i']))+`r8'
local Axcoh=`r7'*(`xlog'(`uci'[`i']))+`r8'
if (`Axcen'<`Axlo') | (`Axcen'>`Axhi') {
*diamond is off the scale!
local flag3=10
}
else {
* phi is angle between diamond slope and y=id in right angle triangle; use this
* fact to get y where diamond is chopped off at
if `Axcol'<`Axlo' {
local flag3=10
local tanphi=(0.2*`r5')/(`Axcen'-`Axcol')
local Aydiff=(`Axlo'-`Axcol')*`tanphi'
local Aycenl1=`Aygcen'-`Aydiff'
local Aycenl2=`Aygcen'+`Aydiff'
local Axcol=`Axlo'
gph line `Aycenl1' `Axcol' `Aycenl2' `Axcol'
}
if `Axcoh'>`Axhi' {
local flag3=10
local tanphi=(0.2*`r5')/(`Axcoh'-`Axcen')
local Aydiff=(`Axcoh'-`Axhi')*`tanphi'
local Aycenh1=`Aygcen'-`Aydiff'
local Aycenh2=`Aygcen'+`Aydiff'
local Axcoh=`Axhi'
gph line `Aycenh1' `Axcoh' `Aycenh2' `Axcoh'
}
gph line `Aycoh' `Axcen' `Aycenh2' `Axcoh'
gph line `Aycenh1' `Axcoh' `Aycol' `Axcen'
gph line `Aycol' `Axcen' `Aycenl1' `Axcol'
gph line `Aycenl2' `Axcol' `Aycoh' `Axcen'
*Overall line (if specified)
if ((`use'[`i'])==5 & "`line'"=="" ) {
gph pen 5
local Adashl=`r5'*(`Gyhi'-1)/100
local Ayhi =`r5'*`Gyhi'+`r6'
local j =`r5'+`r6'
while `j'>`Ayhi' {
local Aycol=`j'
local Aycoh=`j'+`Adashl'
gph line `Aycol' `Axcen' `Aycoh' `Axcen'
local j=`j'+2*`Adashl'
}
}
}
}
*use=9 => excluded, ignore (will have been sorted to bottom of data)
*Diamonds or boxes&lines are now drawn - put text on the end
if ( `use'[`i']==1 | `use'[`i']==3 | `use'[`i']==5 ) {
*put text at end of graph (if requested)
if "`stats'"=="" {
*effect sizes
local e1=`effect'[`i']
local e2=`lci'[`i']
local e3=`uci'[`i']
*Make allowance for alignment where es<0
local sp1
if (`e1'>0) {local sp1 " "}
local sp2
if (`e2'>0) {local sp2 " "}
local sp3
if (`e3'>0) {local sp3 " "}
if (`e1'<1e-8) & "`Glog'"!="" {local e1 "<10^-8"}
else if (`e1'>1e8) & (`e1'!=.) & "`Glog'"!="" {
local e1 ">10^8"
}
else { local e1: displ %4.2f `e1' }
if (`e2'<1e-8) & ("`Glog'"!="" | "`cornfield'"!="") {
local e2 "<10^-8"
}
else if (`e2'>1e8) & (`e2'!=.) & "`Glog'"!="" {local e2 ">10^8"}
else { local e2: displ %4.2f `e2' }
if (`e3'<1e-8) & "`Glog'"!="" {local e3 "<10^-8"}
else if (`e3'>1e8) & (`e3'!=.) & ("`Glog'"!="" | "`cornfield'"!="") {
local e3 ">10^8"
}
else { local e3: displ %4.2f `e3' }
local esize "`sp1'`e1' (`sp2'`e2',`sp3'`e3')"
gph text `Aytcen' `Axhi' 0 -1 `esize'
}
if "`wt'"=="" {
local weit: displ %4.1f `wtdisp'[`i']
if `weit'!=. { gph text `Aytcen' `Ax3hi' 0 1 `weit' }
}
if "`counts'"!="" {
local nm: displ `rawdata'[`i']
if "`nm'"!="." {
parse "`nm'" , parse(";")
local nm1 "`1'"
local nm2 "`3'"
gph text `Aytcen' `Ax2hi1' 0 1 `nm1'
gph text `Aytcen' `Ax2hi2' 0 1 `nm2'
}
}
}
if `use'[`i']==2 & "`stats'"=="" {
gph text `Aytcen' `Axhi' 0 -1 (Excluded)
if "`counts'"!="" {
local nm: displ `rawdata'[`i']
if "`nm'"!="." {
parse "`nm'" , parse(";")
local nm1 "`1'"
local nm2 "`3'"
gph text `Aytcen' `Ax2hi1' 0 1 `nm1'
gph text `Aytcen' `Ax2hi2' 0 1 `nm2'
}
}
}
local i=`i'+1
}
gph close
} /* end of qui section*/
#delimit ;
if `flag1'>1 { di in bl _n "Note: invalid xlabel() or xtick(): graph has been rescaled"};
if `flag2'>1 { di in bl _n "Warning: Some trials cannot be
represented graphically (may contain" _n "inestimable effects). Consider using different xlabel()"};
if `flag3'>1 { di in bl _n "Warning: Overall (or subgroup) effect size not fully
represented graphically." _n "Consider using xlabel()"};
#delimit cr
end
exit
Revision history
*Log option added: can display Log(ORs,RRs) on table & graph.
*graph appears when only 1 trial.
*nomenclature for _ES changed when OR or RR selected
*std err of estimate /log est in saved results is renamed and labelled so is clearer
*can handle 2 variables (ES, seES), exponentiated with new eform option
*Max label length for table is now 20chrs
*Breslow Day test for OR heterogeneity added
*Can display n/N for trials, with and without weights/stats.
*Groups can be labelled when using the counts option with group1() and group2()
*User-defined weight option:
* - can't use with fixed or random option
* - metan ... , wgt(wt) == metan ... , fixedi if wt=1/v ie IV weighting
* - however will differ if RE:
* - no tau2 involved in weights ie variance est differs: wgt=1/(vi+t) but SIGMA{1/wgt}=/= SIGMA{wi^2 * var(thetai) }/[SIGMA(wi)]^2
* - pooled ES=SIGMA{wgt*es}/SIGMA{wgt} =/= FE weighted, so heterogeneity not equal
*Can plot the ES alone without the box (nobox)
*Option to change "Study" label to something else
*Display a bit nicer (table formatted 3 rather than up to 7 dec places)
*Removed "Study -" from top; by default is replaced with "Study". Annoying "tick" next to it removed
*Added I^2 (Higgins & Thompson 2003)
*xtick, b2title options added can add "Favours ..." below graph with prefix and asterisk in b1(*I: .... * ....)
*Nointeger: allows sample size to be non-integer if requested.
*Adding continuity correction: currently allows user-defined const (or via nointeger opt)
*r(sumstat) now displays with S/WMD (did forget to was long standing bug)
*by() option added!!!
*r(tger) and r(cger) corrected from prev by() versions; overall ERs were not reported (were from the last by subg)
*bug with by() removed: wasn't keeping _ES etc
*allows CI syntax (3 variables: theta lower_limit upper_limit), BUT:
* - does not follow "meta" syntax, ie does not assume log transform needed
* - default is to assume symmetry and calculate se=0.5*(upper-lower)/z, but allows asymmetry
* - bug with udw and missing data fixed 1Mar04
*minor bugs fixed: trial labelling with by() on table, extended line to right of graph with
*options nostats nowt counts all specified, sortby w/o by() option, junk text if by() subgroup
*contained no informative trials, erroneous lack of overall summary on graph in some situations.