Hope this would help anybody trying to create centroids using %ANNOMAC and %CENTROID macros. Below is the final correct approach. It would not have been difficult for anybody who has better understanding of how to define macros than me.
data south_korea; set mapsgfk.south_korea; run;
%MACRO ANNOMAC(P1);
/*********************************************************************/
/* */
/* MACRO: ANNOMAC */
/* */
/* USAGE: %ANNOMAC(NOMSG) */
/* */
/* */
/* If ANNOMAC is called without the NOMSG parameter, */
/* a message is displayed on the log that the ANNOTATE */
/* macros are available, and that help is available by */
/* calling the %HELPANO macro. If the NOMSG parameter is */
/* specified, no messages are displayed. */
/* */
/* */
/* DESCRIPTION: */
/* This macro compiles and makes available all of the */
/* ANNOTATE macros documented in the SAS/GRAPH Users Guide. */
/* */
/* NOTES: */
/* Use of %ANNOMAC causes all of the ANNOTATE macros to be */
/* compiled. If this is undesirable, you should select the */
/* macros you want to use and place them in a separate member */
/* in your AUTOCALL library. */
/* */
/*********************************************************************/
%IF %UPCASE(&P1)=HELP %THEN %DO;
%PUT %NRSTR( USAGE: %ANNOMAC(NOMSG););
%PUT %NRSTR( );
%PUT %NRSTR(This macro causes all of the ANNOTATE macros documented);
%PUT %NRSTR(in the SAS/GRAPH USERS GUIDE, Version 6 Edition,);
%PUT %NRSTR(to be made available. Each of the macros can then be);
%PUT %NRSTR(used by calling them as documented in the USERS GUIDE.);
%PUT %NRSTR( );
%PUT %NRSTR(If %ANNOMAC is called without any parameters,);
%PUT %NRSTR(a message is displayed on the log that the ANNOTATE);
%PUT %NRSTR(macros are available, and that help is available by);
%PUT %NRSTR(calling the %HELPANO macro. If the NOMSG parameter is);
%PUT %NRSTR(specified, no messages are displayed.);
%PUT %NRSTR( );
%END;
%if &p1= %then %do;
%PUT %NRSTR( );
%PUT %NRSTR(*** ANNOTATE macros are now available ***) ;
%PUT %NRSTR( );
%PUT %NRSTR( For further information on ANNOTATE macros, enter,) ;
%PUT %NRSTR( %HELPANO(macroname), (for specific macros));
%PUT %NRSTR( %HELPANO(ALL), (for information on all macros));
%PUT %NRSTR( or %HELPANO (for a list of macro names));
%PUT %NRSTR( );
%end;
%MEND ANNOMAC;
%macro centroid( in, out, ids, segonly= );
%local lastid pos hasseg tempds;
%let lastid=&ids;
%let pos=%index(&ids,%str( ));
%do %while(&pos > 0);
%let lastid=%substr(&lastid, &pos, %length(&lastid)-&pos+1);
%let pos=%index(&lastid,%str( ));
%end;
data _null_;
segment=.;
set &in(obs=1);
if segment ne . then call symput("hasseg", "true");
run;
data;
set ∈
%if %length(&hasseg) > 0 and %length(&segonly) > 0 %then %do;
where segment = &segonly;
%end;
run;
%let tempds=&SYSLAST;
proc summary data=&tempds;
by &ids;
var x y;
output out=&out min=_xmin _ymin max=_xmax _ymax n=_npoints;
run;
data &out;
set &out;
_xbar = (_xmin+_xmax)*0.5;
_ybar = (_ymin+_ymax)*0.5;
keep &ids _xbar _ybar _npoints;
run;
data &tempds;
retain _newring 1 _found _seglast _xfirst _yfirst _xlast _ylast _yc _xc;
merge &out(in=_want) &tempds;
by &ids;
if _newring then do;
if _want then do;
_xc = _xbar;
_yc = _ybar;
end;
_xfirst = x;
_yfirst = y;
_xlast = .;
_ylast = .;
_seglast= .;
if first.&lastid then _found = 0;
end;
if x = . | y = . then _newring = 1;
else _newring = 0;
_xlast = lag(x);
_ylast = lag(y);
%if %length(&hasseg) > 0 %then %do;
_seglast = lag(segment);
%end;
if ^first.&lastid & _xlast ne . & _ylast ne . then do;
%if %length(&hasseg) > 0 %then %do;
if _seglast = segment then do;
if _newring then do;
x = _xfirst;
y = _yfirst;
end;
link calc;
end;
else if _seglast ne . then do;
_xkeep = x;
_ykeep = y;
x = _xfirst;
y = _yfirst;
segment = _seglast;
link calc;
_xfirst = _xkeep;
_yfirst = _ykeep;
end;
%end;
%else %do;
link calc;
%end;
end;
if last.&lastid then do;
_xlast = x;
_ylast = y;
x = _xfirst;
y = _yfirst;
_newring = 1;
link calc;
if _found = 0 then output;
end;
return;
calc:
/* Swap coordinates */
if _ylast > y then do;
_x1 = _xlast;
_xlast1 = x;
_y1 = _ylast;
_ylast1 = y;
end;
else do;
_x1 = x;
_xlast1 = _xlast;
_y1 = y;
_ylast1 = _ylast;
end;
if _yc >= _ylast1 & _yc < _y1 then do;
_xc = _xlast1 + (_yc - _ylast1)/(_y1 - _ylast1) * (_x1 - _xlast1);
_found = 1;
output;
end;
return;
keep _xc _yc &ids;
run;
proc sort data=&tempds;
by &ids _xc;
run;
data &out;
retain _xc1 . _dist1 _dist _xckeep 0;
set &tempds;
by &ids;
if _xc1 = . then
_xc1 = _xc;
else do;
_dist1 = abs(_xc-_xc1);
if _dist1 > _dist then do;
_xckeep = (_xc+_xc1)/2;
_dist = _dist1;
end;
_xc1 = .;
end;
if last.&lastid then do;
if first.&lastid then x = _xc;
else x = _xckeep;
y = _yc;
output;
_dist= 0;
_xc1 = .;
end;
keep x y &ids;
run;
%mend;
/*********************************************************************/
/* */
/* MACRO: MAPLABEL */
/* */
/* DESCRIPTION: */
/* This macro is used to create an annotate data set for use with */
/* PROC GMAP output. The resulting data set can be used with ANNO=*/
/* The user can use the default font/size information, or choose */
/* their own. */
/* */
/* USAGE: %HOTSPOTS(<map-ds>, <attribute-ds>, <output-ds>,<var>, */
/* <ids>, FONT=, COLOR=, SIZE=, HSYS=); */
/* */
/* PARAMETERS: */
/* <map-ds> Input Map data set */
/* <attr-ds> Attribute data set that contains var for label */
/* <out-ds> Resulting output data set for use in ANNO= in GMAP */
/* <var> Variable for label on <attr-ds>. Can be text or num */
/* <ids> Space-separated list of IDs that the map and attr */
/* data sets are sorted on. */
/* FONT= Font for the label. Default is SWISS. */
/* COLOR= Color of the label. Devault is BLACK. */
/* SIZE= Size of the label. Default is 1 <unit> */
/* HSYS= UNIT system for SIZE=. Default is 3 (PERCENT) */
/* SEGONLY= Only process the segment specified of each polygon */
/* set (map area). Useful to not have centroid placed */
/* in non-polygon area */
/* */
/* NOTES: */
/* */
/*********************************************************************/
%macro maplabel(mapds,attrds,outds,textvar,ids,
font=swiss,color=black,size=2,hsys=3,segonly=);
%local tempds;
data;
set &attrds;
run;
%let tempds=&SYSLAST;
proc sort data=&tempds;
by &ids;
run;
data &outds;
length position xsys ysys when position hsys $1 text $40;
retain function 'label'
xsys ysys '2'
hsys "&hsys"
when 'a'
position '5'
style "&font"
color "&color"
size &size;
merge &outds(in=want) &tempds(keep=&textvar &ids);
by &ids;
if vtype(&textvar) = 'C' then
text=&textvar;
else
text=left(input(&textvar,BEST.));
if want then output;
run;
proc sort data=&outds nodupkey;by &ids; run;
%mend;
%centroid(south_korea,centroids,ID,segonly=1);
... View more