*
;

*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;

*
;