*
; *This SAS program moves the borders of Canada provinces and of Hawaii to the borders of States of USA. That one map (North America) is for use in SAS/GRAPH procedure GMAP. Note: for draft/presentation graphics only. Try this example, and you can see what this means; options nosource; %macro trans (data,result,plotds,x,y,x_range,y_range, x_move ,y_move, angle, deg); /*developed by Arnold Schick, University of Marburg/Germany December 9, 1994, modified: January 4, 1995 note: on plot dataset PLOTDS there are dummy-corner-points which are the X-,Y-Range from the input dataset and from the new transformated data */ options nosource nostimer nosymbolgen nonotes; %if &data = %then %do; %put ; %put macro-note: This macro is to call: ; %put ; %put macro-note: trans(data,result,plotds,x,y,x_r,y_r,x_m,y_m,angle,deg); %put ; %put macro-note: and it scales X-,Y-Values from input dataset DATA into; %put macro-note: wanted ranges of 0 to X and 0 to Y with possibility of moving; %put macro-note: in X-,Y-Directions and rotation about origin in X=0, Y=0. ; %put macro-note: The new values are written into dataset RESULT, ; %put macro-note: dataset PLOTDS has data for plotting (proc GPLOT with; %put macro-note: plot option SKIPMISS) for showing the effect.; %put macro-note: All transformations are from scope {x|0,1} and {y|1,0}.; %put ; %goto fin; %end; /*set default values*/ data _NULL_; k=symget('x_range')/1.0; if k=. then k=1; call symput('x_range',k); k=symget('y_range')/1.0; if k=. then k=1; call symput('y_range',k); k=symget('x_move')/1.0; if k=. then k=0; call symput('x_move',k); k=symget('y_move')/1.0; if k=. then k=0; call symput('y_move',k); k=symget('angle')/1.0; if k=. then k=0; call symput('angle',k); if k ^= 0 then k=1; call symput('k',k); run; /*set default variablenames*/ %if &data = . %then %do; %let data = _LAST_ ; %put macro-note: default input dataset is the _LAST_; %end; %if &result = or &result = . %then %do; %let result = _NEW_ ; %put macro-note: default result dataset is _NEW_; %end; %if &plotds = or &plotds = . %then %do; %let plotds = _PLOTDS_ ; %put macro-note: default plotting data set is _PLOTDS_; %end; %if &x = or &x = . %then %let x = x; %if &y = or &y = . %then %let y = y; %if °= or ° = . or °=degrees or °=DEGREES or °=GRAD or °=grad %then %let deg = deg; proc means data=&data noprint min max; var &x &y ; output out=_minmax_ min=x_min y_min max=x_max y_max ; run; data _NULL_; set _minmax_; call symput('x_min',x_min); call symput('x_max',x_max); call symput('y_min',y_min); call symput('y_max',y_max); run; options notes; data &result; set &data; length default=8; &x = ((&x - &x_min)/(&x_max - &x_min))*&x_range + &x_move; &y = ((&y - &y_min)/(&y_max - &y_min))*&y_range + &y_move; run; options nonotes; %if &k ^= 0 %then %do; data &result; set &result; keep &x &y; angle=∠ if upcase("°") ^= upcase("DEG") then angle=angle*45/atan(1); r = sqrt(&x**2 + &y**2); if r ^= 0 then phi = arcos(&x/r); else phi=0; if &y < 0 then phi = 360 - phi * 45/atan(1); else phi = phi * 45/atan(1); phi + angle; phi = phi * atan(1)/45; &x = r*cos(phi); &y = r*sin(phi); run; %end; data &plotds; set &result; run; data _scope_ ; if &x_min = 0 then xd=0.01/(&x_max-&x_min); else xd=0; if &x_max = 0 then xr=0.01/(&x_max-&x_min); else xr=0; if &y_min = 0 then yd=0.01/(&y_max-&y_min); else yd=0; if &y_max = 0 then yr=0.01/(&y_max-&y_min); else yr=0; keep &x &y ; &x =.; &y =.; output; &x = &x_min - xd; &y = &y_min - yd; output; &x = &x_max + xr; &y = &y_min - yd; output; &x = &x_max + xr; &y = &y_max + yr; output; &x = &x_min - xd; &y = &y_max + yr; output; &x = &x_min - xd; &y = &y_min - yd; output; &x =.; &y =.; output; run; proc append base=&plotds data= _scope_ force; run; proc append base=&plotds data= &data force; run; proc means data=_scope_ noprint min max; var &x &y ; output out=_minmax_ min=x_min y_min max=x_max y_max ; run; data _NULL_; set _minmax_; call symput('x_min',x_min); call symput('x_max',x_max); call symput('y_min',y_min); call symput('y_max',y_max); run; data _scope_; set _scope_; keep &x &y; &x = ((&x - &x_min)/(&x_max - &x_min))*&x_range + &x_move; &y = ((&y - &y_min)/(&y_max - &y_min))*&y_range + &y_move; angle=∠ if angle ^=0 then do; if upcase("°") ^= upcase("DEG") then angle=angle*45/atan(1); r = sqrt(&x**2 + &y**2); if r ^= 0 then phi = arcos(&x/r); else phi=0; if &y < 0 then phi = 360 - phi * 45/atan(1); else phi = phi * 45/atan(1); phi + angle; phi = phi * atan(1)/45; &x = r*cos(phi); &y = r*sin(phi); end; run; proc append base=&plotds data= _scope_ force; run; %fin : ; options source stimer notes; %mend trans; options source; data one; set maps.canada2; x=x-0.0115 + 0.017*x; y=y+0.447 - 0.015*x - abs(sin(x/14)); run; data two alaska hawaii; set maps.us; if x > 0 or state=2 then y=y+sin(x/41); if state=2 then output alaska; else if state=15 then output hawaii; else output two; run; *trans(data ,result,plotds,x,y,x_range, y_range, x_move ,y_move ,angle,deg); %trans(alaska,eins, ,x,y,0.287, 0.287 , -0.8025, 0.022 ,-44.11); %trans(hawaii,zwei, ,x,y,0.075, 0.075 , -0.9 ,-0.25); data three; set one two eins zwei; run; goptions device=win rotate=landscape border lfactor=2; *goptions targetdevice=hpljs3a4 rotate=landscape border lfactor=2; pattern v=e c=black r=123; * USABLE IN SAS 6.10 OR ABOVE (i.e. 6.12) ONLY; * OTHERS: CONVERT STATE AND PROVINCE TO THE SAME DATATYPE; proc gmap data=three map =three all; id state province; choro state / nolegend discrete ; run; quit; *;