%macro circagg( revdate=%str(3/13/2003 3:10PM), filetype=, /* Specify specific recognized filetypes such as sf12000x, sf32000x, stf901x2, stf903x2 */ setsin=_last_, /* SAS dataset(s) containing data to aggregate */ setin=, /* alias for setsin */ setout=aggout, /* name of aggregated dataset */ radii=, /* List of radii for which to create summaries. Must be in ascending order, e.g. " 1 5 10" */ radius=, /* Alisas for radii */ x0=, /* x coordinate (longitude) of circle center in degrees (west assumed unless a "+" is coded) */ y0=, /* 7 coordinate (latitude) of circle center in degrees */ long=, /* alias for x0 */ lat=, /* alias for y0 */ sitename=, /* Optional: describes the point represented by (x0,y0) */ aggvars=, /* variables to be aggregated. Defaults to all numeric */ means=, /* variables for which to calculate weighted averages */ meanwts=, /* weight variables to use with means list */ states=, /* optional list of state fips codes indicating states to search for data. Variable state containing 2-digit (character) fips codes must be on input data set(s) */ sumlev=, /* geographic summary level to use when doing aggregation. Only specify if _setin has more than one level and you want to filter */ sumlevV=SumLev, /* Name of the Variable on &setsin that contains the geo summary level code */ genrept=1, /* flag indicating whether you want to generate a report with resulting dataset. Only works with certain filetypes. */ filter=, /* value can be the name of a user written macro or it can be a where clause without the word where. E.g. filter=select, will cause macro to invoke the select macro. filter=%str(county = '29019') will cause a where statement to be generated with this filter applied. You MUST CODE AT LEAST 1 BLANK for the program to recognize a where filter. */ xvar=intptlon, yvar=intptlat, /* names of the variables on input sets contain the long and lat values, resp. */ debug=0); %*---Check for and assign aliases----------; %if &radius ne %str() %then %let radii=&radius; %if &long ne %str() %then %let x0=&long; %if &lat ne %str() %then %let y0=⪫ %if &setin ne %str() %then %let setsin=&setin; %local lon1; %if &debug %then %put Parms: Radii=&radii x0=&x0 y0=&y0; %let lon1=%substr(&x0,1,1); %if &debug %then %put lon1= &lon1; %if %superq(lon1) ne %nrbquote(-) and %superq(lon1) ne %nrbquote(+) %then %let x0=%str(-)&x0; %if %superq(sitename) eq %str() %then %let sitename=%str(%() &x0 , &y0 %str(%)); %local nradii _r r1 r2 r3 r4 r5 r6 r7 r8 r9 r10; %let nradii=1; %do %until (&_r = ); %let _r=%scan(&radii,&nradii); %let r&nradii=&_r; %if &debug %then %put Radius &nradii = &_r %str( = ) &&r&nradii; %if &_r ne %str() %then %let nradii=%eval(&nradii+1); %end; %let nradii=%eval(&nradii-1); %local maxrad; %let maxrad=&&r&nradii; data _aggin; retain sitename "&sitename" radius ; retain _x0 &x0 _y0 &y0; retain xlong0r ylat0r sinylat0 cosylat0; array _radius(&nradii) _temporary_ (&radii); rename _x0=Longitude _y0=Latitude; set &setsin; %if %superq(filter) ne %str() %then %do; %*-- if just a single word we assume its the name of a macro. Otherwise its a where clause --; %if %scan(%superq(filter),2) ne %str() or (%length(%superq(filter)) gt 8) %then %do; where also %unquote(&filter); %end; %else %&filter ; %end; retain _D2R .0174532925; *--- This is ATAN(1)/45: converts to radians; drop _d2r; *--convert coords from degrees to radians--; *---this code should only have to execute once.---; if xlong0r=. then do; xlong0r=abs(_x0) * _d2r; ylat0r=_y0 * _d2r; sinylat0=sin(ylat0r); cosylat0=cos(ylat0r); end; %if %nrbquote(&states) ne %str() %then %do; if state ne ' ' then if index("&states",state); %end; %if &sumlev ne %str() %then %do; if &sumlevV = "&sumlev"; %end; xlongr=abs(&xvar) * _d2r; ylatr=&yvar * _d2r; *--This distance algorithm coded by jgb from a formula found in an old Schaums Outline book back in the 70s. Seems to work OK.--; distance=3949.99*arcos(sinylat0 * sin(ylatr) + cosylat0 * cos(ylatr) * cos(xlong0r- xlongr)); if distance le &maxrad; *---In this set of nested if-else statements we find the first (smallest) radius distance falls within--; if distance le &r1 then radius=&r1; %if &nradii gt 1 %then %do i=2 %to &nradii; else if distance le &&r&i then radius=&&r&i; %end; output; format distance 7.2; run; proc sort data=_aggin; by radius distance; run; %local setoutP; %let setoutP=&setout; %*---Now invoke the cumagg macro to generate cumulative sums by radius for final aggout dataset---; %cumagg(setin=_aggin , setout=&setoutP , aggby=radius, idvars=sitename latitude longitude, agglvl=1 , vars=LandSQMI TotPop--AvgHValue, facvar= , dropvars=_lvl_ _nag_, grand=0 , naggvars=404, nmeans=207 , nmwts=207 , means= PctSample PctUrban PctInUAs PctInUCs PctRural PctOnFarms PopPerSQM PctAge0_4 PctAge5_9 PctAge10_14 PctAge15_17 PctAge18_19 PctAge20_24 PctAge25_34 PctAge35_44 PctAge45_54 PctAge55_59 PctAge60_64 PctAge65_74 PctAge75_84 PctOver85 PctUnder18 PctOver18 PctAge18_64 PctOver21 PctOver62 PctOver65 PctWhite1 PctBlack1 PctIndian1 PctAsian1 PctHawnPI1 PctOther1 PctMultRace PctHispPop PctWhite1NH PctMinority PctHHPop PctHouseholder PctSpouse PctChild PctOther_relative PctNonRelative PctFamilies PctMarriedCouples PctCouplesWithKids PctSingleParents PctSingleMothers PctOtherFamilies PctNonFamHHs PctLivingAlone PctOver15 PctNeverMarried PctMarried PctSeparated PctWidowed PctDivorced PctOver5 PctEnglishOnly PctEnglishLimited PctNoEnglish PctForeignBorn PctNaturalized PctNonCitizen PctEnteredLast10Yrs PctFBEurope PctFBAsia PctFBLatinAmerica PctFBMexico PctFBOther PctSameHouse PctSameCounty PctSameState PctWorkInCounty PctWorkersInaPlace PctWorkInPlace PctDriveAlone PctCarpool PctPublicTrans PctCycleWalk PctWorkAtHome AvgCommute PctOver3 PctEnrolledK12 PctInPvtSchools PctInCollege PctOver25 PctLessThan9th PctSomeHighSchool PctHighSchool PctNoCollege PctSomeCollege PctBachelors PctMasters PctProfPHD PctGradProf PctOver18 PctArmedForces PctCivilian PctVeteran PctDisabled PctDisabled65 PctWorkDisability PctOver16 PctCivLabForce PctUnemployed PctCivLabForceFem PctUnemployedFem PctNotInLF PctBothWork PctOneWorks PctEmployedCLF PctManufacturing PctRetailTrade PctEducation PctHealthSA PctOtherIndustry PctUnemployedCLF PctManProfOccs PctServiceOccs PctSalesOffOccs PctFarmFishOccs PctConsOccs PctTransOccs PctHHInc0 PctHHInc10 PctHHInc15 PctHHInc25 PctHHInc35 PctHHInc50 PctHHInc75 PctHHInc100 PctHHInc150 PctHHInc200 MedianHHInc AvgHHInc PctHHIncLT200 AvgHHIncLT200 AvgHHIncGE200 PctWages PctSocSec PctSSI PctPubAssist PctRetirement MedianFamInc AvgFamInc PCI AvgMaleEarnings AvgFemEarnings PctPovUniverse PctPoor PctVeryPoor PctUnder185Poor PctNearlyPoor MeanPovRatio PctPoorInFam PctPoorFamilies PctPoorNonFamHHs PctFemale PctGQPop PctInInstitutions PctGrandPrntsCaring PctOccHUSample PctVacHUSample PctUrbanHUs PctRuralHUs PctOccupied PctOwnerOcc PctRenterOcc PctVacant PctCrowded PctPlumbing PctNoPhone PctNoCars AvgHHSize PctMovedIn5 MedianYearIn PctUnits1 PctUnits2 PctUnits5 PctUnits20up PctMobileHomes PctBoatRV PctAgeUnit5 PctAgeUnit50 PctBuiltBefore1940 AvgAgeUnit PctSpecRenter PctCashRenter PctRentUnder300 PctRenter300 PctRent600 PctRenterOver1000 MedianGrossRent AvgGrossRent PctNoCashRent PctSpecOwner PctHvalUnder50 PctHval50 PctHval100 PctHval150 PctHval200 PctHval300 PctHval500 PctHvalOverMillion MedianHValue AvgHValue ,meanwts= TotPop100 TotPop TotPop TotPop TotPop TotPop LandSQMI TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop TotPop Totpop HHpop HHpop HHpop HHpop HHpop TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs TotPop Over15 Over15 Over15 Over15 Over15 TotPop Over5 Over5 Over5 TotPop TotPop TotPop TotPop ForeignBorn ForeignBorn ForeignBorn ForeignBorn ForeignBorn Over5 Over5 Over5 Worker16 Worker16 WorkersInaPlace Worker16 Worker16 Worker16 Worker16 Worker16 Commuters TotPop Over3 EnrolledK12 Over3 TotPop Over25 Over25 Over25 Over25 Over25 Over25 Over25 Over25 Over25 TotPop Over18 Over18 Over18 DisabledUniv DisabledUniv65 DisabledUniv16 TotPop Over16 CivLabForce CivLabForce CivLabForceFem Over16 MarriedCouples MarriedCouples CivLabForce EmployedCLF EmployedCLF EmployedCLF EmployedCLF EmployedCLF CivLabForce EmployedCLF EmployedCLF EmployedCLF EmployedCLF EmployedCLF EmployedCLF TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs TotHHs HHIncLT200 HHInc200 TotalIncome TotalIncome TotalIncome TotalIncome TotalIncome Families Families TotPop NMalesEarning NFemalesEarning TotPop PovUniverse PovUniverse PovUniverse PovUniverse PovUniverse InFamPovUniv Families NonFamHHs TotPop TotPop TotPop TotPop OccHUs100 VacHUs100 TotHUs TotHUs TotHUs Occupied Occupied TotHUs Occupied Occupied Occupied Occupied Occupied Occupied Occupied TotHUs TotHUs TotHUs TotHUs TotHUs TotHUs TotHUs TotHUs TotHUs TotHUs RenterOcc SpecRenter CashRenter CashRenter CashRenter CashRenter CashRenter CashRenter SpecRenter OwnerOcc SpecOwner SpecOwner SpecOwner SpecOwner SpecOwner SpecOwner SpecOwner SpecOwner SpecOwner SpecOwner ,debug=1) run; %mend circagg;