Search code examples
saslegendproc

SAS graph/ map legend formatting


I have searched all over looking for map legend formatting but can't find the answer to my problem. Does SAS have a feature to display legend as a group as indicated below? enter image description here

Thank you


Solution

  • The LEGEND statement does not have options that allow you to draw the 'desired' legend you have shown (named grouped range categories).

    Desired: Image of desired legend - grouped range categories Doable: A SAS Legend

    You would have to use some data preprocessing and annotate data to draw the desired legend.

    Consider this sample code that uses gmap to draw a choro map of simulated walked paths across a grid. The legend of the map is of the 'doable' nature. A choro map legend for a numeric response variable will list a value range next to each ranges boxed color. A custom format is used in a PUT function call to map a numeric response variable to it's realized categorical value. The categorical variable is type string and choro map legend will list only the value.

    Sample choro map of paths walked

    %let H_MAX = 88;
    %let V_MAX = 50;
    %let C_MAX = 4250;
    %let P_MAX = 1250;
    %let H_CYCLE = 1.5;
    %let H_JITTER = 5;
    %let V_JITTER = 8;
    %let PI = CONSTANT('PI');
    %let PI2 = (2 * &PI);
    %let PI2K = (2 * &PI * &H_CYCLE);
    %let PIK = (&PI * &H_CYCLE);
    
    data grid;
      do v = 0 to &V_MAX-1;
      do h = 0 to &H_MAX-1;
        id + 1;
        * data for clockwise edges of a unit square;
        segment = 1;
        x = h  ; y = v  ; output;
        x = h  ; y = v+1; output;
        x = h+1; y = v+1; output;
        x = h+1; y = v  ; output;
      end;
      end;
      stop;
    run;
    
    data paths (keep=id pid stepid ix p x y v h type weight);
      type = 'S'; weight = 1;
      do _n_ = 1 to &P_MAX;
        pid + 1;
        do ix = 0 to &H_MAX-1;
          p = ix + &H_JITTER * ranuni(123) - &H_JITTER / 2;
          x = p * &PI2 * &H_CYCLE / &H_MAX;
          y = &V_MAX / 2 + &V_MAX / 2.5 * sin ( x );
          y = y + &V_JITTER * ranuni(123) - &V_JITTER / 2;
    
          v = floor ( y ) ;
          h = floor ( p ) ;
    
          id = v * &H_MAX + h + 1;
    
          stepid + 1;
          output;
        end;
      end;
    
      type = 'C'; weight = 1;
      do k = 1 to floor ( &H_CYCLE / 0.5 );
        pid + 1;
        x = &PI * ( k - 0.5 );
        p = x / &PI2 / &H_CYCLE * &H_MAX ;
    
        if mod(k,2) then do;
          y = 1 / 3 * &V_MAX; 
        end;
        else do;
          y = 2 / 3 * &V_MAX; 
        end;
    
        do _n_ = 1 to &C_MAX;
          theta = &pi2 * ranuni(123) ;
          theta = _n_ * &pi2 / &C_MAX ;
    
          dx = &V_MAX / 6 * cos(theta) * ranuni(123);
          dy = &V_MAX / 6 * sin(theta) * ranuni(123);
    
          v = floor ( y + dy + ranuni(123) * &V_JITTER - &V_JITTER / 2) ;
          h = floor ( p + dx + ranuni(123) * &H_JITTER - &H_JITTER / 2) ;
    
          id = v * &H_MAX + h + 1;
    
          stepid + 1;
    
          output;
        end;
      end;
    
      type = 'L'; weight = 250;
      do k = 1 to floor ( &H_CYCLE / 0.5 );
        pid + 1;
        x = &PI * ( k - 0.5 );
        p = x / &PI2 / &H_CYCLE * &H_MAX ;
    
        if mod(k,2) then do;
          y = 1 / 3 * &V_MAX; 
          dy = 1;
          steps = &V_MAX * 5 / 6 - y;
        end;
        else do;
          y = 2 / 3 * &V_MAX; 
          dy = -1;
          steps = y - &V_MAX * 1 / 6;
        end;
    
        do _n_ = 0 to steps;
          y + dy;
    
          v = floor ( y ) ;
          h = floor ( p ) ;
    
          id = v * &H_MAX + h + 1;
    
          stepid + 1;
    
          output;
        end;
      end;
    
      * every id draws the grid;
      type = '*'; weight=1;
      pid + 1;
      do id = 1 to &H_MAX * &V_MAX;
        output;
      end;
      format pid stepid id 6.;
    run;
    
    proc freq noprint data=paths;
      table id / out=stepsfreq (keep=id count);
      weight weight;
    run;
    
    proc format;
      value step_count_category
         1 = 'None'
         2 -  5 = 'Fewest'
         6 - 15 = 'Fewer'
        16 - 25 = 'Few'
        26 - 35 = 'Lowest'
        36 - 45 = 'Low'
        46 - 60 = 'Moderate Low'
        61 - 75 = 'Moderate High'
        76 - 125 = 'High'
       126 - 175 = 'Higher'
       176 - high = 'Highest'
      ;
      value step_count_category_color
         1       = 'White'
         2 -   5 = 'cx00C200'
         6 -  15 = 'cx5BF700'
        16 -  25 = 'cx8CF700'
        26 -  35 = 'cxBAF700'
        36 -  45 = 'cxE0F500'
        46 -  60 = 'cxF7DF00'
        61 -  75 = 'cxFCB100'
        76 - 125 = 'cxFC8200'
       126 - 175 = 'cxFA4F00'
       176 -high = 'cxCC0000'
      ;
    run;
    
    proc format cntlout=stepsfmt lib=work;
      select step_count_category;
    run;
    
    data steps;
      set stepsfreq;
      count_category = put(count,step_count_category.);
    run;
    
    proc sql noprint;
      select quote(trim(cats(label)))
      into :order_list
        separated by ' '
      from stepsfmt
      order by input(strip(start),best12.) descending 
      ;
    
      select put(input(strip(start),best12.),step_count_category_color.)
      into :color_list
        separated by ' '
      from stepsfmt
      order by put(input(strip(start),best12.),step_count_category.)
      ;
    quit;
    
    %put NOTE: &=order_list;
    %put NOTE: &=color_list;
    
    goptions reset=all;
    
    legend1 label=("Steps")
      position = (left middle)
      across = 1
      cframe = cxf7f7f7
      order = (&order_list)
    ;
    
    ods _all_ close;
    ods listing;
    options gstyle;
    
    goptions colors = (&color_list) ;
    
    proc gmap map=grid data=steps(keep=id count_category);
      id id;
      choro count_category /
        legend = legend1 
        coutline = gray
      ;
    run;
    quit;