*! version 1.0.1 26jun2003 Jean Marie Linhart and Jeffrey S. Pitblado *! version 1.0.2 2dec2003 addition Jens Lauritsen of showing group labels *! version 1.0.3 18dec2003 Jean Marie Linhart added many options *! version 1.0.4 02jan2004 Jean Marie Linhart small improvements *! version 1.0.5 18mar2004 Jean Marie Linhart fix for stsplit data *! version 1.0.6 26apr2004 Jean Marie Linhart fix mult rec and respect tmax tmin program define stsatrisk, sort version 8 st_is 2 analysis syntax [if] [in] [, /// CATRisk(passthru) /// per(real 1.0) /// tmax(real 0.0) /// label space adj tmin(real 0.0) /// label space adj SEParate /// noLabel /// SHOWEvents /// TABLEGend /// Table legend CLabel(passthru) /// TABLABel(string ) /// table label LLength(int 16) /// label length LSpace(real 1.0) /// label space adj VSpace(real 1.0) /// vertical space adj STrata(varlist) /// Hazard Gwood NA CNA /// NOT allowed XMTIck(passthru) /// NOT allowed YMTIck(passthru) /// NOT allowed TLABel(passthru) /// NOT allowed XTIck(passthru) /// NOT allowed * /// -graph- options ] if `tmax' != 0 { local tma tmax(`tmax') } if `tmin' != 0 { local tmi tmin(`tmin') } local showev `showevents' local tabl `tablegend' if `"`separate'"' != "" { di as err "option separate is not allowed with stsatrisk" exit 198 } if `"`xmtick'"' != "" { di as err "option xmtick() is not allowed with stsatrisk" exit 198 } if `"`ymtick'"' != "" { di as err "option ymtick() is not allowed with stsatrisk" exit 198 } if `"`tlabel'"' != "" { di as err "option tlabel() is not allowed, use catrisk()" exit 198 } if `"`xtick'"' != "" { di as err "option xtick() is not allowed, use catrisk()" exit 198 } if `"`hazard'`na'`cna'"'!="" { di as err "hazard, na, cna may not be specified with stsatrisk" exit 198 } local gropts `"`options'"' _get_gropts , graphopts(`gropts') grbyable local by `s(varlist)' if "`strata'"!="" & "`by'"!="" { di as err "strata may not be specified with by in stsatrisk" exit 198 } else if "`strata'"!="" { local by `"`strata'"' } if `"`by'"' != "" & `"`gwood'"' != "" { di as err "gwood may not be specified with by or strata in stsatrisk" exit 198 } /* go grab out the custom labels into a useable macro */ CLABEL `clabel' marksample touse qui replace `touse' = 0 if !_st CATRISK if `touse', `catrisk' `tma' `tmi' local catrisk `s(catrisk)' local txtopts `s(txtopts)' /* start defining our space. * First, get the range of the time variable. */ summarize _t if `touse', mean local rmin : word 1 of `catrisk' local wc : word count `catrisk' local rmax : word `wc' of `catrisk' if r(min) < `rmin' { local rmin `r(min)' } if r(max) > `rmax' { local rmax r(max) } local ranget = `rmax'-`rmin' /* Label space definition. * Define where our x position for text is (xtx) is. * we put it outside the normal graph by a fraction of * the range. You can modify the label space with the lspace * option to give more or less label space (horizontal space) */ local xtx = (`rmin'-`ranget'/5)*`lspace' /* the starting yposition for text. The base range for * survival plots is 0 to 1, so we go down by a .1 step * from zero. If `per' was specified, we multiply by * that (since per multiplies the yrange). Then * we multiply by the user specified vspace multiplier * which gives more or less vertical space. */ local ypos = -( 0.1 )*`per' * `vspace' /* the first bit of text to add is the table label */ if `"`tablabel'"' == "" { if `"`showev'"' !="" { local tablabel "At risk (events):" } else { local tablabel "At risk:" } } if (length(`"`tablabel'"') > 20) & `lspace'==1.0 { local lspace 1.5 } local addtext `"text(`ypos' `xtx' `"`tablabel'"', `txtopts')"' /* define groups as specified by the by() option */ tempvar group quietly egen int `group' = group(`by') if `touse' summarize `group' if `touse', mean local ngroup = r(max) /* too many and my hack to get things positioned right * will break down */ local ncatr : word count `catrisk' if `ngroup'*`ncatr'>30 { di as err "Too much information! The number of -by-" _c di as err " groups times the number of at risk" _c di as err " labels must be 30 or less." exit 198 } /* Determine the number of by variables. * if there is one by variable, and it has labels we are probably going to use them to label the at risk groups if there are no custom labels specified */ local nby : word count `by' if `nby' == 1 { tempvar mybyv qui gen `mybyv' = _n if `group'==1 } /* Make a table in the legend */ if "`tabl'" != "" { local lrd `"order(- " ""' local lrd2 `" - "Events""' local lrd3 `" - "Total""' } else if `"`clabel'"'!="" { local lrd `"order("' } /* In the forval j=1/`ngroup' loop we will * first Define the At risk labels. * second Define the At risk data and event data */ forval j = 1/`ngroup' { /* each group (row) gets its own yposition, this defines it. This is a hack, I fiddled with the parameters until it looked like it was working */ local ypos = -( 0.1 + .125*(`j'))*`per'*`vspace' if (`ngroup'>1) { local lab /* one by variable, so can try to use value labels */ if `nby' == 1 { // addition by Jens lauritsen to show value // labels instead of group number /* get value label */ local lab1: value label `by' /* scratch out `mybyvar' and get in it the value for the group we are on */ qui replace `mybyv' = . qui replace `mybyv' = _n if `group'==`j' quietly summ `mybyv', meanonly local byv = `by'[r(min)] /* this is the value*/ /* take the label from this value, restrict length to llength */ capture local lab: label `lab1' `byv' /// `llength' /* if we've got a string variable, we * want to use its value for the label */ capture confirm numeric variable `by' if (_rc) { local lab `byv' } } /* If we have custom labels, they will be used * to label the groups (rows). Get * the label we are on */ local clab : word `j' of `clabel' /* if there is one replace the label with it */ if (`"`clab'"' != "") local lab "`clab'" /* now, if there STILL isn't a label or if we said nolabels put a generic label on it */ if ("`lab'" == "" | "`label'" != "" ) /// local lab "`byv'" /* if there is more than one by variable that * won't work, so label something generic */ if (`"`lab'"' == "") /// local lab "At risk `j'" } else { /* only one group */ local lab `clabel' if `"`lab'"' == "" { /* no custom label, use default */ local lab "" } } /* legend */ if "`tabl'" != "" | `"`clabel'"' != ""{ local lrd `"`lrd' `j' `"`lab'"' "' } /* this addtext labels the row */ local addtext `addtext' /// text(`ypos' `xtx' "`lab'", `txtopts') /* Now add the at risk and event data to the * table */ local ni : word count `catrisk' local ni = `ni' -1 /* count the at-risk and the events */ forval i = 1/`ni' { local k : word `i' of `catrisk' local i2 = `i'+1 local k2 : word `i2' of `catrisk' if (`k' == 0) { quietly count if _t>=`k'&`group'==`j'&`touse'& _t0<=`k' local atrisk `r(N)' } else{ quietly count if _t>=`k'&`group'==`j'&`touse'& _t0<`k' local atrisk `r(N)' } quietly count if (_d & ~missing(_d) & _t >= `k' & _t< `k2' /// &`group'==`j'&`touse' ) local events `r(N)' local k2 = (`k' + `k2')/2 /* add the at risk text */ local addtext /// `"`addtext' text(`ypos' `k' "`atrisk'", `txtopts')"' if `"`showev'"' != "" { /* add the events text */ local addtext /// `"`addtext' text(`ypos' `k2' "(`events')", `txtopts')"' } } /* the last one does not have events text, just at * risk text */ local ni = `ni' + 1 local k : word `ni' of `catrisk' quietly count if _t>=`k'&`group'==`j'&`touse' local atrisk `r(N)' local addtext /// `"`addtext' text(`ypos' `k' "`atrisk'", `txtopts')"' /* legend table, events then at risk info */ if "`tabl'" != "" { quietly count if (_d & _t >= 0 /// &`group'==`j'&`touse') local lrd2 `"`lrd2' - "`r(N)'" "' quietly count if _t>=0&`group'==`j'&`touse' local lrd3 `"`lrd3' - "`r(N)'" "' } } if "`tabl'" != "" { local lrd3 `"`lrd3' )"' local lrd `"legend(`lrd' `lrd2' `lrd3' on colfirst cols(3))"' } else if `"`clabel'"' != "" { local lrd `"legend( `lrd' ) )"' } /* Now we need to create space for this table. We are * going to make the graph smoosh to * give us space via adding an invisible xmtick and ymtick */ /* y position of the invisible ymtick. Current text position * then subtract 0.05*`per'*`vspace', since `per' and `vspace' * both adjust the vertical space. */ local marg = `ypos'-(0.05*`per'*`vspace') /* The xmtick is placed at the xtx location - 1/8 of the range * *`lspace' to make place for the table heading and labels. * The ymtick is just below the lowest of the text written above * (-0.05*`per'*`vspace' below). */ local adjust /// ymtick(`marg' , notick) /// xmtick(`=`xtx'-(`ranget'/8)*`lspace'' , notick) /// // blank if `"`strata'"' != "" { local strata strata(`strata') } sts graph if `touse', /// `adjust' /// xlabel(`catrisk') /// `addtext' /// per(`per') `tma' `tmi' `strata' `gwood' /// `lrd' `options' end program CATRISK, sclass syntax [if] [, CATRisk(string asis) tmax(real 0.0) tmin(real 0.0)] local iftouse `if' local 0 `catrisk' syntax [anything] [, * ] local txtopts `"`options'"' local 0 , catrisk(`anything') syntax [, catrisk(numlist sort) ] if "`catrisk'" == "" { summarize _t `iftouse', mean if `tmin' == 0.0 { local tmin `r(min)' } if `tmax' == 0.0 { local tmax `r(max)' } _natscale `tmin' `tmax' 5 numlist "`tmin'(`r(delta)')`tmax'", ascending sort local catrisk `r(numlist)' } sreturn clear sreturn local txtopts `txtopts' sreturn local catrisk `catrisk' end program define CLABEL local lab `0' local lab2 : subinstr local lab "clabel(" "" local lab3 : subinstr local lab2 ")" "" c_local clabel `"`lab3'"' end