*! version 1.0.0 09aug2007 program stpowplot version 10.0 gettoken cmd 0 : 0, parse(" ,") local len = length(`"`cmd'"') if `"`cmd'"' == "," | `"`cmd'"' == "" { di as err "logrank subcommand must be specified" exit 198 } else if `"`cmd'"' == substr("logrank",1,`len') & `len'>=3 { local cmd logrank local plottest Log-rank test } else if `"`cmd'"' == substr("exponential",1,`len') & `len'>=3 { di as err "exponential is not yet available with stpowplot" exit 198 local cmd exponential local plottest Exponential test } else if `"`cmd'"' == "cox" { local cmd cox local plottest Cox PH model di as err "cox is not yet available with stpowplot" exit 198 } else { di as err "unknown stpower subcommand `cmd'" exit 198 } // get plot#opts() syntax [anything] [, * ] local 0 , `options' tokenize `"`options'"' local i = 1 while `"``i''"' != "" { if substr(`"``i''"',1,4) == "plot" { if substr(`"``i''"',1,5) == "ploto" { syntax [, PLOTOpts(string) * ] } else { local k = substr(`"``i''"',5,1) cap confirm number `k' if _rc { di as err `"option ``i'' is incorrectly specified"' exit 198 } syntax [, PLOT`k'opts(string) * ] } local 0 , `options' } local ++i } local 0 `anything', `options' syntax [anything] , Yaxis(string) Xaxis(string) /// [ OVER(string) LEGend(string asis) BY(string) /// Alpha(string) Power(string) Beta(string) /// n(string) HRATio(string) p1(string) NRATio(string) /// BYOPts(string) OUTfile(string) * ] // type of computation if `"`n'"' != "" { if `"`power'"' != "" { local compute "effect size" } else { local compute power } } else { local compute "sample size" } di as txt `"Estimating `compute' ..."' gettoken comma rest : rest, parse(", ") // get twoway opts _get_gropts , graphopts(`options') gettwoway getallowed(addplot) // only twoway options are allowed; macro options must contain // -stpower- options only local options `"`s(graphopts)'"' /*stpower options only*/ local twopts `"`s(twowayopts)'"' local addplot `"`s(addplot)'"' // parse extended numlists in options local numopts alpha power beta n hratio p1 nratio foreach opt of local numopts { if `"``opt''"' != "" { ChkExtNumlist ``opt'', optname(`opt') local nextopt `s(nextopt)' if `"`nextopt'"' == "" { /* ext. numlist not specified */ local nextopt `opt'(``opt'') } local options `options' `nextopt' } } // parse extended numlists in arguments gettoken arg1 anything : anything, match(parent) if `"`arg1'"' != "" { ChkExtNumlist `arg1' if `"`s(nextopt)'"' != "" { local arg1 `s(nextopt)' } else { local arg1 (`arg1') } gettoken arg2 anything: anything, match(parent) if `"`arg2'"' != "" { ChkExtNumlist `arg2' if `"`s(nextopt)'"' != "" { local arg2 `s(nextopt)' } else { local arg2 (`arg2') } } } // check xaxis() and yaxis() columns local nwords: word count `yaxis' if `nwords' > 1 { di as err "yaxis(): only one column name may be specified" exit 198 } ChkXYcols, `yaxis' local ylab `s(lab)' local nwords: word count `xaxis' if `nwords' > 1 { di as err "xaxis(): only one column name may be specified" exit 198 } ChkXYcols, `xaxis' local xlab `s(lab)' tempfile holdtabvals local cols alpha power beta n n1 n2 e hr loghr s1 s2 p1 nratio w stpower `cmd' `arg1' `arg2', `options' table saving(`holdtabvals') /// columns(`cols') nooutput if r(onesided) == 1 { local sides one sided } else { local sides two sided } local method = r(method) // if any dataset is open qui preserve qui use `holdtabvals', clear LabelVars // get plotting range qui summ `xaxis', meanonly if r(min) == r(max) { if `"`xaxis'"' != "hr" { local xrange 0 `r=(max)' } else { local xrange `=(r(max)>1)' `=r(max)' } } else { local xrange `=r(min)' `=r(max)' } qui summ `yaxis', meanonly if r(min) == r(max) { if `"`yaxis'"' != "hr" { local yrange 0 `r=(max)' } else { local yrange `=(r(max)>1)' `=r(max)' } } else { local yrange `=r(min)' `=r(max)' } // obtain study parameters to be reported in the note local exclude loghr p1 n e n1 n2 beta if `"`xaxis'"' == "beta" | `"`yaxis'"' == "beta" { local exclude `exclude' power } else if `"`yaxis'"' == "loghr" { local exclude `exclude' hr } else if `"`xaxis'"' == "p1" { local exclude `exclude' nratio } GetNote, exclude(`by' `over' `xaxis' `yaxis' `exclude') level(`sides') local keepvars `s(varlist)' local note note(`"Other study parameters: `s(note)'"') // get titles and subtitles gettoken first rest: xlab local first = lower(`"`first'"') gettoken rest: rest, parse(",") local title title(`"`ylab' vs `first' `rest'"') local subti subtitle(`"`plottest', `method' method"') local singlepnt = 0 // check if yaxis() and xaxis() do not vary tempvar ymin ymax xmin xmax if `"`by'"' != "" | `"`over'"' != "" { tempvar byover qui egen `byover' = group(`by' `over') qui by `byover', sort: egen double `ymin' = min(`yaxis') qui by `byover', sort: egen double `ymax' = max(`yaxis') qui by `byover', sort: egen double `xmin' = min(`yaxis') qui by `byover', sort: egen double `xmax' = max(`yaxis') } else { qui egen double `ymin' = min(`yaxis') qui egen double `ymax' = max(`yaxis') qui egen double `xmin' = min(`yaxis') qui egen double `xmax' = max(`yaxis') } cap assert `ymin'==`ymax' & `xmin'==`xmax' local singlepnt = _rc cap isid `yaxis' `byover' if `"`over'"' != "" { if `"`plotopts'"' != "" { di as err "plotopts() and over() may not be combined" exit 198 } tempvar group qui egen `group' = group(`over') qui tab `group' cap assert r(r) <= 10 if _rc { // !! di as err "too many categories in over();" di as err "use combination of by() and over()" exit 198 } } local yvar `yaxis' local xvar `xaxis' local yplotopts ytitle(`"`ylab'"') ysc(range(`yrange')) ylab(#10, grid) local xplotopts xtitle(`"`xlab'"') xsc(range(`xrange')) xlab(#10, grid) if c(N) == 1 | !`singlepnt' { // scatter plot if only one data point or values do not vary local plottype scatter } else { local plottype line } if `"`over'"' != "" { // overlaid plots qui levelsof `group', local(overcat) tokenize `overcat' local i = 1 while `"``i''"' != "" { GetGroupLabel `over' if `group'==``i'' local lgnd `lgnd' label(`i' `"`s(label)'"') label define overlab ``i'' `"`s(label)'"', add local plotyx `plotyx' `sep' /// (`plottype' `yvar' `xvar' /// if `group' == ``i'', sort `plot`i'opts') local sep "||" local ++i } label values `group' overlab } else { sort `xvar' `yvar' local plotyx `plottype' `yvar' `xvar', `plotopts' } if `"`by'"' != "" { // separate plots tempvar bygroup qui egen `bygroup' = group(`by') qui levelsof `bygroup', local(bycat) tokenize `bycat' local i = 1 while `"``i''"' != "" { GetGroupLabel `by' if `bygroup'==``i'' label define bylab ``i'' `"`s(label)'"', add local ++i } label values `bygroup' bylab ParseByOpts , `byopts' local bylgnd `"`s(bylgnd)'"' local byttl `"`s(byttl)'"' local byopts `"`s(byopts)'"' if `"`byttl'"' == "" { local byttl `"`title'"' } local byplotopts by(`bygroup', /// `byttl' `subti' `note' `bylgnd' `byopts') } else { if `"`byopts'"' != "" { di as err "byopts() requires specifying by()" exit 198 } local twopts `title' `subti' `note' `twopts' } /* produce graphs */ local legend legend(`lgnd' `legend') twoway `plotyx' || `addplot' || , /// `byplotopts' `yplotopts' `xplotopts' `legend' `twopts' if `"`outfile'"' != "" { _prefix_saving `outfile' local filename `"`s(filename)'"' local replace `"`s(replace)'"' label variable alpha "Alpha (`sides')" if `"`over'"' != "" { rename `group' over local groupvars over } if `"`by'"' != "" { rename `bygroup' by local groupvars `groupvars' by } order `yvar' `xvar' `groupvars' `by' `over' `keepvars' keep `xvar' `yvar' `by' `over' `groupvars' `keepvars' qui compress local plottest = lower(`"`plottest'"') local datalabel Estimated `compute' for the `plottest', local datalabel `datalabel' `method' method label data `"`datalabel'"' save `filename', `replace' } qui restore end program ChkXYcols, sclass version 10.0 cap syntax [, Alpha Power Beta n n1 n2 e HR LOGHR s1 s2 p1 NRATio w ] if _rc == 198 { di as err "invalid column name in yaxis() or xaxis()" exit 198 } else if _rc != 0 { exit _rc } if `"`alpha'"' != "" { sreturn local lab Significance level } else if `"`power'"' != "" { sreturn local lab Power } else if `"`beta'"' != "" { sreturn local lab Probability of a type II error } else if `"`n'"' != "" { sreturn local lab Sample size } else if `"`n1'"' != "" { sreturn local lab Control-group sample size } else if `"`n2'"' != "" { sreturn local lab Experimental-group sample size } else if `"`e'"' != "" { sreturn local lab Number of events } else if `"`hr'"' != "" { sreturn local lab Hazard ratio } else if `"`loghr'"' != "" { sreturn local lab Log hazard ratio local opt loghr } else if `"`s1'"' != "" { sreturn local lab Survival of the control group } else if `"`s2'"' != "" { sreturn local lab Survival of the experimental group } else if `"`p1'"' != "" { sreturn local lab Prop. of subjects (control group) } else if `"`nratio'"' != "" { sreturn local lab Ratio of sample sizes, N2/N1 } else if `"`w'"' != "" { sreturn local lab Proportion of withdrawals } end program ChkExtNumlist, sclass version 10 syntax [anything] [, optname(string) ] gettoken first rest: anything local k = length(`"`first'"') if `"`first'"' == substr("range",1,`k') { gettoken num1 rest: rest gettoken num2 rest: rest cap numlist `"`num1' `num2'"', min(2) max(2) sort if _rc { di as err `"extended numlist: range must contain two numeric values"' exit 198 } tokenize `"`r(numlist)'"' local min = `1' local max = `2' if `"`rest'"' != "" { gettoken first np: rest local k = length(`"`first'"') if `"`first'"' == substr("npoints",1,`k') & `k'>1 { } else { di as err "extended numlist incorrectly specified" exit 198 } cap confirm number `np' if _rc { di as err "extended numlist: number of points" /// " must be integer greater than 1" exit 198 } cap assert `np'>1 if _rc { di as err "extended numlist: number of points" /// " must be integer greater than 1" exit 198 } } else { // default is 20 points local np = 20 } // build numlist local step = (`max'-`min')/(`np'-1) if `"`optname'"' == "n" { local step = int(`step') } if `step'< 1e-4 { di as err "computed step size is too small (< 1e-4);" di as err "reduce number of points or increase range" exit 198 } sreturn local nextopt `optname'(`min'(`step')`max') } else { cap numlist `"`anything'"' if _rc { di as err "extended numlist incorrectly specified" exit 198 } sreturn local nextopt } end program define GetGroupLabel, sclass version 10.0 syntax varlist [if] foreach var of local varlist { sum `var' `if', mean local ll `"`: var label `var'' = `=string(round(r(min),0.01))'"' local lab `"`lab'`sep'`ll'"' local sep "; " } sreturn local label `"`lab'"' end program LabelVars version 10.0 syntax [varlist] foreach var of local varlist { if `"`var'"' == "hr" { label variable `var' "HR" } else if `"`var'"' == "loghr" { label variable `var' "ln(HR)" } else if `"`var'"' == "nratio" { label variable `var' "N2/N1" } else { label variable `var' `"`=proper("`var'")'"' } } end program GetNote, sclass version 10.0 syntax [varlist] [, EXCLUDE(string) level(string) ] // must specify full names in by(), over(), ... local varlist: list varlist - exclude foreach var of local varlist { if `"`var'"' == "alpha" { local dilevel " (`level')" } else { local dilevel } sum `var' `if', mean if (r(min)==r(max) & r(min)!=0) { local ll `"`: var label `var'' = `=string(round(r(min),0.01))'"' local lab `"`lab'`sep'`ll'`dilevel'"' local sep "; " local tokeep `tokeep' `var' } } sreturn local note `"`lab'"' sreturn local varlist `tokeep' end program define ParseByOpts, sclass version 10 syntax [, LEGend(passthru) TItle(passthru) MISSing total * ] if "`total'" != "" { display as error /// "total option not allowed inside byopts()" exit 191 } if "`missing'" != "" { display as error /// "missing option not allowed inside byopts()" exit 191 } sreturn local bylgnd `"`legend'"' sreturn local byttl `"`title'"' sreturn local byopts `"`options'"' end