*! inspired by 340.600.71 *! by Zhenghao(Vincent) Jin & Abi Muzaale *! July 5, 2022 *! version 3.01 *! fixed rounding issue for non-by table *! a space added to between median and IQR for cont vars capture program drop table1_options program define table1_options syntax [if], title(string) /// [cont(varlist)] /// [binary(varlist)] /// [multi(varlist)] /// [foot(string)] /// [by(varname)] /// [excel(string)] quietly { // sreen if if syntax is called if "`if'" != "" { local if_helper = substr("`if'", 3, .) local if_helper : di "& " "`if_helper'" } // screen if excel option got called if "`excel'" == "" { local excel_name : di "table1_option_output" } else { local excel_name : di "`excel'" } // generate an excel file putexcel set `excel_name', replace local alphabet "`c(ALPHA)'" tokenize `alphabet' if "`by'" == "" { // generate row and col indicator in excel local excel_row_c = 1 local excel_col_c = 1 //columns local col1: di "_col(40)" capture local col2: di "_col(50)" //title string noisily di "`title'" ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`title'" local excel_row_c = `excel_row_c' count `if' local total_N=r(N) di `col1' "N=`total_N'" local excel_row_c = `excel_row_c' + 1 ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "N=`total_N'" foreach v of varlist `cont' { quietly sum `v' `if', detail local row_lab_c: variable label `v' local excel_row_c = `excel_row_c' + 1 local excel_col_c = 1 ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`row_lab_c'" local D %2.0f local med_iqr_c: di /// `D' `col1' r(p50) " [" /// `D' r(p25) "," /// `D' r(p75) "]" local med_iqr_c2: di /// `D' r(p50) " [" /// `D' r(p25) "," /// `D' r(p75) "]" local row_c: di "`row_lab_c' `med_iqr_c'" local excel_col_c = `excel_col_c' + 1 ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`med_iqr_c2'" //continuous varlist noisily di "`row_c'" } foreach v of varlist `binary' { local excel_row_c = `excel_row_c' + 1 local excel_col_c = 1 ind_translator, row(`excel_row_c') col(`excel_col_c') quietly sum `v' `if', detail local row_lab_b: variable label `v' putexcel $ul_cell = "`row_lab_b'" local D %2.0f local percent: di `D' `col1' r(mean)*100 local percent2: di `D' r(mean)*100 local row_b: di "`row_lab_b' `percent'" local excel_col_c = `excel_col_c' + 1 ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`percent2'" //binary varlist noisily di "`row_b'" } foreach v of varlist `multi' { local row_var_lab: variable label `v' local row_lab_m: value label `v' // count without missing quietly count if !missing(`v') `if_helper' local total = r(N) quietly levelsof `v' `if', local(levels) // putexcel the variable name local excel_row_c = `excel_row_c' + 1 local excel_col_c = 1 ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`row_var_lab'" //multinomial varlist noisily di "`row_var_lab'" local nlevels=r(r) forvalues l=1/`nlevels' { local excel_col_c = 1 local excel_row_c = `excel_row_c' + 1 capture local levels: label `row_lab_m' `l' ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = " `levels'" local excel_col_c = `excel_col_c' + 1 quietly count if `v'==`l' `if_helper' local num=r(N) local percent_v: di `D' `col1' `num'*100/`total' local percent_v2: di `D' `num'*100/`total' ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`percent_v2'" noisily di " `levels' `percent_v'" local l=`l'+1 } } local oldvarname: di "`cont' `binary' `multi'" preserve rename (`oldvarname')(`foot') local missvar "`foot'" di "" foreach v of varlist `missvar' { local excel_row_c = `excel_row_c' + 1 local excel_col_c = 1 quietly count `if' local denom=r(N) quietly count if missing(`v') `if_helper' local vlab: variable label `v' local num=r(N) local missing=`num'*100/`denom' local missingness: di _col(25) %2.1f `missing' local missing2 : di %2.1f `missing' noisily di "`v': `missingness'% missing" ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`v': `missing2'% missing" } noisily di "`if'" local excel_row_c = `excel_row_c' + 1 local excel_col_c = 1 ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`if'" restore } else { // generate a screener to see if user inputted a by varaible in table 1 // this will not influence the table but will influence the footnote missing value section local dual_screener = 0 local var_screener `cont' `binary' `multi' foreach var in `var_screener' { if "`by'" == "`var'"{ local dual_screener = 1 } } if `dual_screener' == 1 { noisily di "Wrong Input: The stratifying variable should not be inputted as table 1 variable" } else { // generate row and col indicator in excel local excel_row_c = 1 local excel_col_c = 1 // first detect how many categories the variable has levelsof(`by') // save values to a macro local by_var_val = r(levels) /* // count how many values the variable has local val_count = 0 foreach count in `by_var_val' { val_count = `val_count' + 1 } */ // prepare a spacing factor to separate columns local col_fac = 20 // prepare a spacing parameter for actual separation // and the default should be 40 for the first column local col_sep = 40 // prepare for column heading local col_lab_m: value label `by' // display first line noisily di "`title'" // put the title line into excel ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`title'" // di second line (the column heading) local col_header_count = 0 // for second line, add excel row count for 1 local excel_row_c = `excel_row_c' + 1 foreach col_h in `by_var_val' { // calculate appropriate identation for each column header // an identation is calculated based on basic identation for second column + identation factor per column * column number of each heading local col_sep_temp = `col_sep' + `col_header_count' * `col_fac' // adjust for the excel column counts to make sure it gets inputted to correct place local excel_col_c = `excel_col_c' + 1 local col_s "_col(`col_sep_temp')" ind_translator, row(`excel_row_c') col(`excel_col_c') capture local col_level : label `col_lab_m' `col_h' noisily di `col_s' "`col_level'" _continue // output to excel cells putexcel $ul_cell = "`col_level'" // correctly counting for the header numbers local col_header_count = `col_header_count' + 1 } // use this to stop _continue noisily di "" // reset col_header_count local col_header_count = 0 // reset excel_col_c to 1 so that new lines can be inputted to first cell of each lines local excel_col_c = 1 // the third line (N=xxx) // first set the excel row count to correct numbers local excel_row_c = `excel_row_c' + 1 foreach col_h in `by_var_val' { // calculate correct identation local col_sep_temp = `col_sep' + `col_header_count' * `col_fac' local col_s "_col(`col_sep_temp')" // adjust for the excel column counts to make sure it gets inputted to correct place local excel_col_c = `excel_col_c' + 1 count if `by' == `col_h' `if_helper' local col_count = r(N) noisily di `col_s' "N=`col_count'" _continue // output to excel cells ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "N=`col_count'" local col_header_count = `col_header_count' + 1 } // use this to stop _continue noisily di "" // for counting variables foreach v of varlist `cont' { // reset header count local col_header_count = 0 // count for excel row numbers local excel_row_c = `excel_row_c' + 1 // reset excel_col_c to 1 so that new lines can be inputted to first cell of each lines local excel_col_c = 1 // label name and displaying status local row_lab_c: variable label `v' // set format local D %1.0f // print variable name noisily di "`row_lab_c'" _continue // put variable name into cell ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`row_lab_c'" // print for each column foreach col_h in `by_var_val' { // get correct separation space local col_sep_temp = `col_sep' + `col_header_count' * `col_fac' local col_s "_col(`col_sep_temp')" // count for excel columns local excel_col_c = `excel_col_c' + 1 // get median and IQR info quietly sum `v' if `by' == `col_h' `if_helper', detail // display each column local col_percent : di `D' r(p50) " [" /// `D' r(p25) "," /// `D' r(p75) "]" noisily di `col_s' "`col_percent'", _continue // output to excel for median & IQR ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`col_percent'" local col_header_count = `col_header_count' + 1 } // finish the line noisily di "" } // for binary variables foreach v of varlist `binary' { // reset header count local col_header_count = 0 // label name and displaying status local row_lab_b: variable label `v' // set format local D %1.0f // count for excel row numbers local excel_row_c = `excel_row_c' + 1 // reset excel_col_c to 1 so that new lines can be inputted to first cell of each lines local excel_col_c = 1 // put variable name into cell ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`row_lab_b'" // print variable name noisily di "`row_lab_b'" _continue // print for each column foreach col_h in `by_var_val' { // get correct separation space local col_sep_temp = `col_sep' + `col_header_count' * `col_fac' local col_s "_col(`col_sep_temp')" // count for excel columns local excel_col_c = `excel_col_c' + 1 quietly sum `v' if `by' == `col_h' `if_helper', detail local percent: di `D' `col1' r(mean)*100 noisily di `D' `col_s' `percent', _continue // output to excel for median & IQR ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`percent'" local col_header_count = `col_header_count' + 1 } noisily di "" } // for categorical variables foreach v of varlist `multi' { // set format local D %1.0f local row_var_lab: variable label `v' local row_lab_m: value label `v' // get levels of the categorical variable levelsof `v' local var_level = r(levels) // count for excel row numbers local excel_row_c = `excel_row_c' + 1 // reset excel_col_c to 1 so that new lines can be inputted to first cell of each lines local excel_col_c = 1 // put variable name into cell ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`row_lab_m'" // display variable name noisily di "`row_var_lab'" // get value range in case some variables have extreme values like 0 sum `v' `if', detail local v_min = r(min) local v_max = r(max) // loop from min to max forvalues v_val = `v_min'/`v_max' { // when loop from min to max, it is necessary to get rid off non-existing values // achieve this by count if the variable has the value or not count if `v' == `v_val' `if_helper' local v_level_count = r(N) if `v_level_count' != 0 { // reset header count local col_header_count = 0 // reset excel_col_c to 1 so that new lines can be inputted to first cell of each lines local excel_col_c = 1 // label name and displaying variable value local v_level: label `row_lab_m' `v_val' // count for excel row and output variable values local excel_row_c = `excel_row_c' + 1 ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = " `v_level'" noisily di _col(5) "`v_level'", _continue foreach col_h in `by_var_val' { // get correct separation space local col_sep_temp = `col_sep' + `col_header_count' * `col_fac' local col_s "_col(`col_sep_temp')" // count for excel colmns local excel_col_c = `excel_col_c' + 1 count if `v'==`v_val' & `by' == `col_h' & !missing(`v') `if_helper' local num=r(N) count if `by' == `col_h' & !missing(`v') `if_helper' local t_num = r(N) local v_percent = `num' * 100 / `t_num' local v_percent2 : di `D' `v_percent' noisily di `D' `col_s' `v_percent', _continue // output to excel ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`v_percent2'" local col_header_count = `col_header_count' + 1 } noisily di "" } } } // missing values local oldvarname: di "`cont' `binary' `multi'" preserve rename (`oldvarname')(`foot') local missvar "`foot'" // a line spacer noisily di "" // put the line separator into excel local excel_col_c = 1 local excel_row_c = `excel_row_c' + 1 ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "" foreach v of varlist `missvar' { noisily di "`v'", _continue // output variable name into excel local excel_row_c = `excel_row_c' + 1 local excel_col_c = 1 ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`v'" // reset col_header_count local col_header_count = 0 foreach col_h in `by_var_val' { local col_sep_temp = `col_sep' + `col_header_count' * `col_fac' local col_s "_col(`col_sep_temp')" // count for excel col local excel_col_c = `excel_col_c' + 1 count if `by' == `col_h' local denom = r(N) count if missing(`v') & `by' == `col_h' local neu = r(N) local per = `neu' / `denom' * 100 local per2 = round(`per' * 10) / 10 // output to excel ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`per2'% missing" noisily di `col_s' %2.1f `per' "% missing", _continue local col_header_count = `col_header_count' + 1 } noisily di "" } noisily di "`if'" local excel_row_c = `excel_row_c' + 1 local excel_col_c = 1 ind_translator, row(`excel_row_c') col(`excel_col_c') putexcel $ul_cell = "`if'" restore } } } end