*! Program to: *! 1) Generate spatial weights using point coordinates or key variables *! 2) Import spatial weights from ArcGIS, GeoDa and from dta and text files // Although this is not memory-efficient, it may be useful for some researchers. *! 3) Export spatial weights to .txt, .dat, .gwt, and Mata files // Exported .txt file can be used with sspack and spautoreg and exported .dat file can be used in R and Matlab *! *! What -spwmatrix- can actually do depends on memory availability since sparse matrix operations are not yet allowed in Mata. *! *! Author: P. Wilner Jeanty *! Version 2.8: February 2013 -----> Information on the dimension of the generated spatial weights matrix added to the report *! Version 2.6: October 3, 2012 ---> Modified so that eigenvalue variable can be saved to a file when either xtw() or noisland is specified. *! Version 2.5: September 4, 2012 -> Option noisland added to remove observations with no neighbors *! Version 2.4: July 3, 2012 ------> Option external added to save the weights matrix to Mata memory and option noreport also added to suppress report when necessary *! Version 2.3: April 28, 2012 ----> Option xtw() added to generate spatial weights for a balanced panel dataset *! Version 2.2: December 2011 -----> Option xport() added to export spatial weights to dat, txt, and gwt format with one option, replacing option export *! Version 2.1: November 2011 -----> Option dthres(), dmins(), snn(), and gamma() added when socio-econ spatial weights requested to cap the number of neighbors *! Version 2.0.0: October 2011 ----> Option swm() added: Weights matrix generated by ArcGIS or stored as a dta file or a text file can now be imported *! Version 1.0.7: May 2011 --------> Change default value for beta from 100 to 1. *! Version 1.0.6: January 2011 ----> Bugs when econ spatial weights requested fixed *! Version 1.0.5: February 2010 ---> Mata code compiled to a separate Mata file and option connect added *! Version 1.0.4: August 2009 -----> Social network and socio-economic weights added *! Version 1.0.3: July 2009 ------> Three syntaxes allowed and option to export weights to gwt files added *! Version 1.0.2: June 2009 -------> Econ weights and option eignvar() added *! version 1.0.1: December 2008 ---> Option to export weights to .dat file added *! Version 1.0.0: August 21, 2008 -> Born date program define spwmatrix version 12 * First perform some housekeeping in case the program started running but did not finish for some reasons capture mata: mata drop spwmatrix* spwmatrix*() capture scalar drop spwmatrix_spa spwmatrix_forst spwmatrix_rowst spwmatrix_RC capture macro drop SP_* * Now begin serious stuff global spwmatrix_soc=0 gettoken afaire 0:0 if "`afaire'"=="import" spwmatrix_gal `0' else if "`afaire'"=="gecon" spwmatrix_n1 `0' else if "`afaire'"=="socio" spwmatrix_socio `0' else { di as err "`afaire' is not a valid subcommand" exit 199 } local using "`s(using)'" local wname "`s(wname)'" local knn "`s(knn)'" local wtype "`s(wtype)'" local alpha "`s(alpha)'" local eignval "`s(eignval)'" local dband "`s(dband)'" local mataf "`s(mataf)'" local rowstand "`s(rowstand)'" local eignvar "`s(eignvar)'" local connect "`s(connect)'" local dta "`s(dta)'" local text "`s(text)'" local swm "`s(swm)'" local xtw "`s(xtw)'" local external "`s(external)'" local report "`s(report)'" local island "`s(island)'" if "`using'"=="" { DisplayReport, wname(`wname') knn(`knn') wtype(`wtype') alpha(`alpha') eignval(`eignval') dband(`dband') /// `mataf' `rowstand' eignvar(`eignvar') `connect' xtw(`xtw') `external' `report' } else { DisplayReport using `using', wname(`wname') knn(`knn') wtype(`wtype') alpha(`alpha') eignval(`eignval') /// dband(`dband') `mataf' `rowstand' eignvar(`eignvar') `connect' `dta' `text' swm(`swm') xtw(`xtw') /// `external' `report' } if scalar(spwmatrix_donow)==0 { if "`external'"!="" { capture mata: rmexternal("`wname'") mata: *crexternal("`wname'")=spwmatrixE_W } if "`eignvar'"!="" { if "`xtw'"!="" | "`island'"!="" { capture erase "`c(pwd)'`c(dirsep)'`eignvar'.dta" preserve clear mata: spwmatrix_eignget() qui save "`c(pwd)'`c(dirsep)'`eignvar'" restore } } } * Cleaning up after everything went smoothly well capture scalar drop spwmatrix_spa capture scalar drop spwmatrix_forst capture scalar drop spwmatrix_rowst capture scalar drop spwmatrix_donow capture sreturn clear capture erase "`c(pwd)'`c(dirsep)'spwmatrix_saveig.out" capture mata: mata drop island xtw spwmatrix* spwmatrix_*() capture mata: mata set matastrict off macro drop SP_* end program define spwmatrix_gal version 12 syntax using/, WName(str) [EIGNVal(name) Mataf eignvar(str) ROWstand replace favor(str) /// dta text swm(str) CONnect xport(str) xtw(numlist max=1 >0) /// EXTernal noREPort noISland] if "`favor'"!="" & !inlist("`favor'", "space", "speed") { di as err "Option favor(`favor') not allowed" exit 198 } if "`dta'" !="" & "`text'"!="" & "`swm'"!="" { di as err "Options {bf:dta}, {bf:text}, and {bf:swm} may not be combined" exit 198 } if "`eignvar'"!="" & "`xtw'"=="" Confnewvar `eignvar' `replace' if "`xtw'"!="" CHKint `xtw' CheckFile, wname(`wname') nametype(`xport') `mataf' eignval(`eignval') `replace' preserve drop _all if "`dta'`text'`swm'"=="" qui insheet using `using', delim(" ") else if "`dta'"!="" qui use `using', clear else if "`text'"!="" qui insheet using `using', clear else if "`swm'"!="" { qui insheet using `"`using'"', names clear confirm numeric var `swm' capture drop oid_ field1 sort `swm' } unab xvars: _all SpaceSpd, favor(`favor') capture erase spwmatrix_tempf mata: spwmatrix_CalcSPweightM("`xvars'") restore if "`xtw'`island'"=="" { if "`eignvar'"!="" & scalar(spwmatrix_rowst)==0 { if "`eignval'"!="" & "`mataf'"!="" mata: spwmatrix_getfile() else { mata: spwmatrix_getfile() capture erase spwmatrix_tempf } } } if "$SP_fformat"=="txt" SP_fixit using "$outname", id(`swm') // where an id variable is required that variable will be used RetOption "`using'" "`wname'" "`knn'" "`wtype'" "`alpha'" "`eignval'" "`dband'" "`mataf'" "`rowstand'" /// "`eignvar'" "`connect'" "`dta'" "`text'" "`swm'" "`xtw'" "`external'" "`report'" // Quotes here are crucial to determine position of arguments end program define spwmatrix_n1 version 12 syntax varlist(numeric min=2 max=2) [if] [in], WName(str) /// [WType(str) alpha(str) DBand(numlist min=2 max=2 sort) cart /// r(str) knn(str) ECONVar(varlist numeric min=1 max=1) beta(str) /// EIGNVal(name) eignvar(str) Mataf ROWstand replace favor(str) /// CONnect xport(str) xtw(numlist max=1 >0) EXTernal noREPort noISland] marksample touse CheckFile, wname(`wname') nametype(`xport') `mataf' eignval(`eignval') `replace' if "`eignvar'"!="" & "`xtw'"=="" Confnewvar `eignvar' `replace' local xvars `varlist' if "`r'"!="" & "`cart'"!="" { di as err " Options {bf:cart} and {bf:r()} may not be combined" exit 198 } if "`favor'"!="" & !inlist("`favor'", "space", "speed") { di as err " Option favor(`favor') not allowed" exit 198 } * Checking the coordinates gettoken lat1 long1: xvars if "`cart'"=="" { quietly count if abs(`lat1')>90 if `r(N)'>0 { di as err "Spherical latitudes must be in [-90,90]" exit 198 } quiet count if abs(`long1')>180 if `r(N)'>0 { di as err "Spherical longitudes must be in [-180,180]" exit 198 } if "`r'"=="" local rad= 6371.009 /* Calculcated as rad=(2*a+b)/3 with a=6,356.752 km (Polar radius) b=6,378.137 km (Equatorial radius) */ else local rad=`r' } else if `lat1'<0 | `long1'<0 { di di as err " Cartesian or projected coordinates must be positive" exit 198 } if "`wtype'"!="" & !inlist(`"`wtype'"', "bin", "inv", "econ", "invecon", "socnet", "socecon") { di di as err " One of bin, inv, econ, invecon, socnet, and socecon is required with option {bf:wtype()}" exit 198 } if `"`wtype'"'=="bin" & `"`dband'"'=="" { di di as err "Option {bf:dband()} required when binary distance-based weights matrix requested" e 198 // N.B. Although not recommended, distance cut-off is not required for inverse distance weights matrix } if "`knn'"!="" & ("`wtype'"!="" | "`dband'"!="") { di di as err " Option {bf:knn(#)} may not be combined with either {bf:wtype()} or {bf:dband()}" exit 198 } if "`knn'`wtype'"=="" { di di as err " You must specify either {bf:knn(#)} or {bf:wtype()} option" exit 198 } if "`knn'"!="" CHKint `knn' if "`xtw'"!="" CHKint `xtw' if ("`alpha'"!="" & "`wtype'"!="inv") { di di as err "Option {bf:alpha()} can only be specified when inverse distance matrix requested" exit 198 } if inlist("`wtype'", "econ", "invecon") & "`econvar'"=="" { di di as err "You must specify at least option {bf:econvar()} required when requesting economic or inverse economic distance spatial weights" exit 198 } if inlist("`wtype'", "econ", "invecon")==0 & ("`econvar'"!="" | "`beta'"!="") { di di as err "Option {bf:econvar()} or {bf:beta()} may not be specified when option {bf:wtype(econ|invecon)} is not specified" exit 198 } if "`wtype'"=="inv" { if "`alpha'"=="" local alpha=1 // alpha(1) is the default when wtype(inv) is specified mata: spwmatrix_Alfa=`alpha' } if "`wtype'"=="econ" | "`wtype'"=="invecon" { if "`dband'"!="" { di as err " Option {bf:dband()} may not be combined with {bf:wtype(econ|invecon)}" exit 198 } markout `touse' `econvar' confirm numeric var `econvar' if "`beta'"!="" CHKint `beta' if "`beta'"=="" local beta=1 // beta=1 is the default when wtype(econ|invecon) is specified mata: spwmatrix_beta=`beta' } if "`dband'"!="" { gettoken cut1 cut2: dband global cut1 `cut1' global cut2 `cut2' mata: spwmatrix_clow=`cut1'; spwmatrix_chigh=`cut2' } mata: spwmatrix_soc=$spwmatrix_soc SpaceSpd, favor(`favor') mata: spwmatrix_CalcSPweightM("`xvars'", "`touse'") if "$SP_fformat"=="txt" SP_fixit using "$outname" RetOption "`using'" "`wname'" "`knn'" "`wtype'" "`alpha'" "`eignval'" "`dband'" /// "`mataf'" "`rowstand'" "`eignvar'" "`connect'" "`dta'" "`text'" "`swm'" /// "`xtw'" "`external'" "`report'" "`island'" end program define spwmatrix_socio version 12 syntax varlist(numeric min=1 max=1) [if] [in], WName(str) WType(str) /// [idvar(varname numeric) EIGNVal(name) eignvar(name) Mataf /// ROWstand replace favor(str) CONnect DTHres(numlist max=1 >0) /// Gamma(numlist max=1 >0) snn(numlist max=1 >0) dmins(str) xport(str) /// xtw(numlist max=1 >0) EXTernal noREPort noISland] marksample touse if "`wtype'"!="" & !inlist(`"`wtype'"', "socnet", "socecon") { di di as err " One of socnet and socecon is required with option {bf:wtype()}" exit 198 } if "`wtype'"=="socnet" & "`idvar'"=="" { di di as err " Option {bf:idvar()} required when requesting social networks spatial weights" exit 198 } if "`wtype'"=="socecon" & "`idvar'"!="" { di di as err " Option {bf:idvar()} may not be specified when requesting socioeconomics spatial weights" exit 198 } if ("`dthres'"!="" | "`snn'"!="" | "`dmins'"!="" | "`gamma'"!="") & "`wtype'"!="socecon" { di "{err}Options {bf:dthres()}, {bf:dmins()}, {bf:gamma()}, and {bf:snn()} may be specified " _c di "only when socio-economic spatial weights are requested" exit 198 } if "`snn'"!="" CHKint `snn' // Need to note in the help file that snn() can be combined with wtype() while knn() cannot. local socops=("`dthres'"!="") + ("`snn'"!="") + ("`dmins'"!="") if `socops'>1 { di as err "Only one of {bf:dthres()}, {bf:dmins()} and {bf:snn()} is allowed" exit 198 // The purpose of dmins is to help in specifying dthres() } if "`gamma'"!="" & "`dthres'"=="" { di as err "Option {bf:gamma()} must be combined with {bf:dthres()} only" exit 198 } local ksoc=0 local dsoc=0 if "`dthres'"!="" { local dsoc=`dthres' if "`gamma'"=="" local gamma=1 // gamma(1) is the default when wtype(socecon) is specified else { capture confirm integer number `gamma' if _rc { di as err "Value supplied for {bf:gamma()} must be an integer" exit 198 } } mata: spwmatrix_gamma=`gamma' } if "`snn'"!="" local ksoc=`snn' mata: spwmatrix_d=`dsoc'; spwmatrix_snn=`ksoc' if "`favor'"!="" & !inlist("`favor'", "space", "speed") { di as err " Option favor(`favor') not allowed" exit 198 } if "`idvar'"!="" markout `touse' `idvar' CheckFile, wname(`wname') nametype(`xport') `mataf' eignval(`eignval') `replace' if "`eignvar'"!="" & "`xtw'"=="" Confnewvar `eignvar' `replace' global spwmatrix_soc=1 mata: spwmatrix_soc=$spwmatrix_soc SpaceSpd, favor(`favor') mata: spwmatrix_CalcSPweightM("`varlist'", "`touse'") if "$SP_fformat"=="txt" SP_fixit using "$outname", id(`idvar') RetOption "`using'" "`wname'" "`knn'" "`wtype'" "`alpha'" "`eignval'" "`dband'" /// "`mataf'" "`rowstand'" "`eignvar'" "`connect'" "`dta'" "`text'" "`swm'" /// "`xtw'" "`external'" "`report'" "`island'" end program define DisplayReport version 12 syntax [using/], wname(str) [knn(str) wtype(str) alpha(str) eignval(name) /// dband(numlist min=2 max=2 >=0 sort) mataf rowstand eignvar(name) /// connect dta text swm(str) xtw(str) external noREPort] local spwmatrix_N=scalar(spwmatrix_RC) if scalar(spwmatrix_donow) exit local impfile GAL if "`dta'" != "" local impfile DTA if "`text'"!="" local impfile TEXT if "`swm'"!="" local impfile SWM if `"`using'"'!="" local titl `impfile' file `using' imported successfully as a (`spwmatrix_N' x `spwmatrix_N') SPW matrix and the following action(s) taken: else { if "`knn'"!="" local matype Nearest neighbor (knn = `knn') else if "`wtype'"!="" { if "`wtype'"=="bin" local matype Binary distance else if "`wtype'"=="inv" local matype Inverse distance (alpha = `alpha') else if "`wtype'"=="econ" local matype Economic distance else if "`wtype'"=="invecon" local matype Inverse economic distance else if "`wtype'"=="socnet" local matype Social network else if "`wtype'"=="socecon" local matype Socio-economic } local titl `matype' spatial weights matrix (`spwmatrix_N' x `spwmatrix_N') calculated successfully and the following action(s) taken: } mata: st_local("spisland", strofreal(island)); st_local("spxtw", strofreal(xtw)) if "`report'"=="" { di di as txt `"{bf:`titl'}"' local foreign1 "" local foreign2 "" if "`eignval'"!="" & scalar(spwmatrix_rowst)==0 { local foreign1 and its eigenvalues if "`mataf'"=="" local foreign2 as txt " and " in ye "`eignval'" else if "`mataf'"!="" local foreign2 as txt " and " in ye "`c(pwd)'`c(dirsep)'`eignval'" if scalar(spwmatrix_forst)!=0 & "`mataf'"=="" local foreign3 as txt " and " in ye "`c(pwd)'`c(dirsep)'`eignval'_n" } if scalar(spwmatrix_forst)==0 { if "`mataf'"=="" { if ("`using'"!="") local ROW="SWMDist No " else local ROW="SWMDist Yes " if "`rowstand'"!="" local ROW="`ROW'Yes" else local ROW="`ROW'No" matrix rownames `wname'=`ROW' if "`dband'"!="" { local int1=int($cut1) local int2=$cut1-`int1' local int2=string(`int2') local col "`int1' `int2'" local int=int($cut2) local int2=$cut2-`int1' local int2=string(`int2') local col "`col' `int1' `int2'" matrix colnames `wname'=`col' } di di as txt " - Spatial weights matrix `foreign1' created as Stata object(s): " in ye "`wname'" `foreign2' as txt "." } else { di di " - Spatial weights matrix `foreign1' saved to Mata file(s): " in ye "`c(pwd)'`c(dirsep)'`wname'" `foreign2' as txt "." } } if scalar(spwmatrix_forst)!=0 { if "`mataf'"=="" { di di as txt " - Spatial weights matrix `foreign1' saved to Mata file(s): " in ye "`c(pwd)'`c(dirsep)'`wname'_n" `foreign3' as txt "," di as txt " since dimensions exceed {help matsize} limit of your Stata flavor." } if "`mataf'"!="" { di di " - Spatial weights matrix `foreign1' saved to Mata file(s): " in ye "`c(pwd)'`c(dirsep)'`wname'" `foreign2' as txt "." } } if "`rowstand'"!="" & scalar(spwmatrix_rowst)==0 { di di as txt " - Spatial weights matrix has been row-standardized." } if "$SP_Fname"!="" { di di as txt " - Spatial weights matrix saved to .$SP_fformat file, " in ye "`c(pwd)'`c(dirsep)'$outname" as txt ", $SP_use" } if "`eignvar'"!="" & scalar(spwmatrix_rowst)==0 { di if (`spxtw' + `spisland')>=1 { di as txt " - Eigenvalue variable saved the .dta file " in ye "`c(pwd)'`c(dirsep)'`eignvar'" as txt "." } else di as txt " - Eigenvalues placed into the variable " in ye "`eignvar'" as txt "." } if "`external'"!="" { di di as txt " - Spatial weights matrix stored as a Mata object residing in Mata memory." } } if "`connect'"!="" { mata: spwmatrix_Connect() di di as txt "{bf:Connectivity Information for the Spatial Weights Matrix}" di as txt " - Sparseness: " as res %5.3f scalar(spwmatrix_spa) as txt "%" di as txt " - Neighbors: " di as txt " Min : " as res "`min'" di as txt " Mean : " as res "`mean'" di as txt " Median: " as res "`med'" di as txt " Max : " as res "`max'" } end program define RetOption, sclass version 12 args using wname knn wtype alpha eignval dband mataf rowstand eignvar connect dta text swm xtw external report island if "`using'" != "" sreturn local using "`using'" if "`wname'" != "" sreturn local wname "`wname'" if "`knn'" != "" sreturn local knn "`knn'" if "`wtype'" != "" sreturn local wtype "`wtype'" if "`alpha'" !="" sreturn local alpha "`alpha'" if "`eignval'" != "" sreturn local eignval "`eignval'" if "`dband'" != "" sreturn local dband "`dband'" if "`mataf'" != "" sreturn local mataf "`mataf'" if "`rowstand'" != "" sreturn local rowstand "`rowstand'" if "`eignvar'" != "" sreturn local eignvar "`eignvar'" if "`connect'" != "" sreturn local connect "`connect'" if "`dta'" != "" sreturn local dta "`dta'" if "`text'" != "" sreturn local text "`text'" if "`swm'" != "" sreturn local swm "`swm'" if "`xtw'" != "" sreturn local xtw "`xtw'" if "`external'" != "" sreturn local external "`external'" if "`report'" != "" sreturn local report "`report'" if "`island'"!="" sreturn local island "`island'" end program CheckFile version 12 syntax, wname(str) [nametype(str) mataf eignval(name) replace] if "`nametype'"!="" { tokenize "`nametype'", parse(",") args fname sepopt ftype if "`sepopt'"!="," { di "{err}Comma required when {bf:xport()} is specified" exit } local fformat `ftype' if !inlist("`fformat'", "dat", "txt", "gwt") { di as err "Option {bf:xport()} takes one of {bf:dat}, {bf:txt}, and {bf:gwt} as sub-option" exit 198 } if "`fformat'"=="dat" { global outname `fname'.dat global SP_use "for use in {bf:Matlab} and {bf:R}." } if "`fformat'"=="txt" { global outname `fname'.txt global SP_use "for use with other {bf:Stata} packages." } if "`fformat'"=="gwt" { global outname `fname'.gwt global SP_use "for use in GeoDa or other software packages." } Confnewfile $outname `replace' mata: spwmatrix_forout="`fformat'" global SP_fformat `fformat' global SP_Fname `fname' } if "`mataf'"!="" { Confnewfile `wname' `replace' if "`eignval'"!="" Confnewfile `eignval' `replace' } end prog define Confnewfile version 12 args filename replace local conf_file confirm new file global spwmatrix_repf=0 cap `conf_file' `filename' if _rc { if "`replace'"!="" { erase `filename' global spwmatrix_repf=1 } else { di `conf_file' `filename' } } else { if "`replace'"!="" { di di "(Note: file `filename' not found)" di } } end prog define Confnewvar version 12 args varname replace cap confirm new var `varname' if _rc & "`replace'"!="" drop `varname' else if _rc & "`replace'"=="" confirm new var `varname' end prog define SpaceSpd version 12 syntax, [favor(str)] if "`favor'"=="" & c(matafavor)=="space" mata: mata set matafavor speed if "`favor'"=="speed" & c(matafavor)=="space" mata: mata set matafavor speed if "`favor'"=="space" & c(matafavor)=="speed" mata: mata set matafavor space end prog define SP_fixit version 12 syntax using/, [id(varname numeric)] tempfile sav_id preserve qui { if "`id'"!="" gen idv=`id' // This assumes `id' takes on values ranging from 1 to _N else gen idv=_n keep idv save `sav_id' insheet using `using', clear merge using `sav_id' local n=_N+1 set obs `n' gen nid=. replace nid=0 if _n==_N replace nid=idv if nid!=0 // Assuming `id' takes on values from 1 to _N sort nid order nid drop idv _merge local N=_N-1 replace nid=`N' if nid==0 outsheet using `using', delim(" ") nonames replace } restore end prog define CHKint version 12 args chkint if "`chkint'"!="" { capture confirm integer number `chkint' if _rc { di as err "Value supplied for option {bf:`chkint'()} must be an integer" exit 198 } } end