#delimit ; program define polyspline, rclass; version 16.0; /* Create a basis for a polynomial or other unrestrictd spline in an X-variable, with corresponding parameters equal to values of the spline at user-specified reference points, or differences between those values. This program is an easy-to-use front end for the bspline package. *! Author: Roger Newson *! Date: 17 July 2022 */ syntax varname [if] [in] , Generate(passthru) [ Refpts(numlist sort min=2) Power(numlist integer min=1 max=1) OMit(passthru) BAse(passthru) INClude(passthru) Type(passthru) LABfmt(passthru) LABPrefix(passthru) ]; /* refpts() is the list of reference points. power() is the power (or degree) of the spline. Other options are passed to flexcurv. */ * Check package dependencies *; _whichlist bspline frencurv flexcurv, package(bspline); if trim("`r(incomplete)'")=="bspline" {; disp as error "Package bspline must be installed for polyspline to work." _n as error "To install bspline from SSC, type:" _n as input "ssc install bspline"; error 498; }; * Count reference points and set power if necessary *; local refpts: list uniq refpts; local nrefpt: word count `refpts'; if `nrefpt'==0 {; local nrefpt=2; }; else if `nrefpt'==1 {; disp _n as error "refpts() invalid"; error 122; }; if "`power'"=="" {; local power=`nrefpt'-1; }; if `power'>`nrefpt'-1 {; local power=`nrefpt'-1; }; if `power'<1 {; disp _n as error "power() must be an integer >= 1"; error 498; }; * Generate splines *; qui flexcurv `if' `in', xvar(`varlist') refpts(`refpts') power(`power') krule(interpolate) `include' `omit' `base' `generate' `type' `labfmt' `labprefix'; local nspline=r(nspline); return add; disp as text "`nspline' reference splines generated of degree: " as result `power'; end; prog def _whichlist, rclass; version 16.0; /* Input a list of which input items and optionally a package list and output lists of present and absent items and complete and incomplete packages. */ syntax anything(name=itemlist) [ , Packagelist(namelist) NOIsily ]; * packagelist() specifies a list of packages for the items to belong to. noisily specifies that whichlist will have the output generated by which for each item in the item list. *; local Nitem: word count `itemlist'; * Extend packagelist if required *; if "`packagelist'"!="" {; local Npackage: word count `packagelist'; if `Npackage' < `Nitem' {; local lastpackage: word `Npackage' of `packagelist'; forv i1=`=`Npackage'+1'(1)`Nitem' {; local packagelist "`packagelist' `lastpackage'"; }; }; }; * Create present, absent, complete, and incomplete lists *; if "`packagelist'"=="" {; * Create present and absent lists only *; forv i1=1(1)`Nitem' {; local itemcur: word `i1' of `itemlist'; cap `noisily' which `itemcur'; if _rc local absent `"`absent' `itemcur'"'; else local present `"`present' `itemcur'"'; }; }; else {; * Create present, absent, complete, and incomplete lists *; forv i1=1(1)`Nitem' {; local itemcur: word `i1' of `itemlist'; local packagecur: word `i1' of `packagelist'; cap `noisily' which `itemcur'; if _rc {; local absent `"`absent' `itemcur'"'; local incomplete "`incomplete' `packagecur'"; }; else {; local present `"`present' `itemcur'"'; local complete "`complete' `packagecur'"; }; }; local incomplete: list uniq incomplete; local incomplete: list sort incomplete; local complete: list uniq complete; local complete: list complete - incomplete; local complete: list sort complete; }; local present: list uniq present; local present: list sort present; local absent: list uniq absent; local absent: list sort absent; * List results *; if `"`present'"'!="" {; disp as text "Present items:"; disp as result `"`present'"'; }; if `"`absent'"'!="" {; disp as text "Absent items:"; disp as result `"`absent'"'; }; if "`complete'"!="" {; disp as text "Complete packages:"; disp as result `"`complete'"'; }; if "`incomplete'"!="" {; disp as text "Incomplete packages:"; disp as result `"`incomplete'"'; }; * Return results *; foreach R in incomplete complete absent present {; return local `R' `"``R''"'; }; end;