*
;
/***************************************************************/
/* DRAWLAB:  places text labels with minimum and maximum       */
/*           values at each end of the axis                    */
/*  ARGUMENT       VALUE                                       */
/*  --------       -----                                       */
/*     Y:          Y coordinate (position of axis)             */
/*     B:          minimum value                               */
/*     T:          maximum value                               */
/*                                                             */
/*  REQUIREMENTS: Use in PAIRWISE macro after the              */
/*                GRAPH('CLEAR') and before the GRAPH('UPDATE')*/
/*                function calls                               */
/*                                                             */
/*                Requires minimum and maximum values          */
/*                compatible with BEST5. format.               */
/***************************************************************/

%macro drawlab(y, b, t);
   rc = gdraw('text', 10, &y-3, put(&b,best5.));
   rc = gdraw('text', 95, &y-3, put(&t,best5.));
%mend drawlab;

/***************************************************************/
/* PAIRWISE: creates one page of pairwise comparison plots.    */
/*           This macro only works for data sets with at least */
/*           five continuous numeric variables to plot.        */
/*                                                             */
/*           You must supply values for the macro when you     */
/*           invoke it as described in the following table:    */
/*                                                             */
/*  ARGUMENT       VALUE                                       */
/*  --------       -----                                       */
/*  INDS:          input data set containing variables to plot */
/*  LINE:          SAS/GRAPH color for axis lines              */
/*  SYMBOL:        SAS/GRAPH color for symbols                 */
/*  TEXT:          SAS/GRAPH color for text                    */
/*  VAR1-VAR5:     names of the five variables to plot         */
/*  CLASS:         the class variable to use to determine the  */
/*                 different line colors and line types that   */
/*                 connect the data points                     */
/*  ORDER:         order to draw horizontal lines (axes) to    */
/*                 represent variables in the plot, starting   */
/*                 with the top axis (for example, 12345 or    */
/*                 53412) where different orders allow the     */
/*                 axes to represent different variables.      */
/*                                                             */
/*  REQUIRMENTS: Sort INDS by CLASS.                           */
/*               Have DRAWLAB macro (shown above) available    */
/*               for labels.                                   */
/***************************************************************/

%macro pairwise(inds, line, symbol, text,
                var1, var2, var3, var4, var5,
                class, order);

  /* The following DATA step produces plots based on the input data    */
  /* set (represented by the reference &inds) merged with the modified */
  /* statistical summary data set (_range_), created in the DATA step  */
  /* in the MVPLOT macro.                                              */

data _null_;

  /* Make sure variables containing the Y axis coordinates and line    */
  /* type loop index persist across DATA step iterations.              */

  retain y1 y2 y3 y4 y5 lintype;

  /* Merge input data set with modified stat summary data set.         */

  merge &inds _range_ end=eof;

  /* The following loop converts actual plot variable values to DSGI   */
  /* window coordinates for each variable in the current observation.  */
  /*                                                                   */
  /* &&var&i resolves to the variable names specified as parameters.   */
  /*                                                                   */
  /* min&i resolves to names of variables containing lower limit       */
  /* ranges.                                                           */
  /*                                                                   */
  /* display&i resolves to names of variables containing factors to    */
  /* convert the actual values of each plot variable to DSGI coordinate*/
  /* values between 0 and 100, plus a minimum value of 10 to maintain  */
  /* a white space border around the edge of the final plot.           */
  /*                                                                   */
  /* As a result of this calculation, the minimum value for each       */
  /* variable produces the DSGI X coordinate value 10, and the maximum */
  /* value for each variable produces the DSGI X coordinate 95.        */

  %do i=1 %to 5;
    x&i = (&&var&i - min&i) * display&i + 10;
    %end;

  /* Everything in the following DO grouop, including the embedded     */
  /* loops, executes only once at the beginning of the DATA step.      */

  if _n_=1 then do;

     /* The following loop creates five variables, Y1-Y5, each         */
     /* containing DSGI Y coordinate values of 20, 35, 50, 65, or 80,  */
     /* but in the order given in the parameter ORDER.                 */
     /*                                                                */
     /* These Y values were chosen to provide evenly spaced horizontal */
     /* axis lines in the output using the DSGI coordinate numbering   */
     /* system.                                                        */
     /*                                                                */
     /* The numeric suffix of each variable corresponds to the macro   */
     /* variables &VAR1-&VAR5. So, for example, if you specify         */
     /* ORDER=54321 at invocation, the value of Y5 is 80, and the fifth*/
     /* variable passed to the macro will be represented on the        */
     /* uppermost horizontal axis.                                     */
     /*                                                                */
     /* The loop begins with a hardcoded uppermost DSGI coordinate of  */
     /* 80, in a display scaled to a coordinate system using values    */
     /* between 0 and 100.                                             */

     pos = 80;

     %do i=1 %to 5;
       %let s&i = %substr(&order, &i, 1);
       %let s = &&s&i;
       y&s = pos;
       pos = pos - 15;
       %end;

     /* Initialize DSGI. The GRAPH('CLEAR') function creates a graphics*/
     /* catalog entry and prepares it to collect the graphics elements */
     /* that you want to display.                                      */

     rc = ginit();
     rc = graph('clear');

     /* Open the window to contain the plot at 100 percent of screen   */
     /* capacity, and activate the window.                             */

     rc = gset('window', 1, 0, 0, 100, 100);
     rc = gset('transno', 1);

     /* Set up colors for axis line, text, and plot symbols by         */
     /* associating color names with the color index numbers.          */
     rc = gset('colrep', 50, "&LINE");
     rc = gset('colrep', 51, "&TEXT");
     rc = gset('colrep', 52, "&SYMBOL");

     /* Choose font, choose text color, set alignment, and set size;   */
     /* then write a title for the plot (which includes the names of   */
     /* all the variables) centered at the top of the page. The text   */
     /* height and centering position are each in DSGI coordinate      */
     /* units.                                                         */

     rc = gset('texfont', 'swissl');
     rc = gset('texcolor', 51);
     rc = gset('texalign', 'center', 'base');
     rc = gset('texheight', 3);
     rc = gdraw('text', 50,95,
                "Comparing &VAR1,&VAR2,&VAR3,&VAR4,&VAR5");

     /* Choose font and line color, then loop to draw the Y axes for   */
     /* each variable in the order specified at invocation. The minimum*/
     /* and maximum values for each axis appear in the font specified; */
     /* in the example, they appear in the simplex font.               */

     rc = gset('texfont', 'simplex');
     rc = gset('lincolor', 50);
     %do i=1 %to 5;
       rc = gdraw('line', ., 10, 95, y&i, y&i);
       %end;

     /* Set text height, then loop calling the DRAWLAB macro to label  */
     /* each axis with the min and max values of the variable          */
     /* associated with each axis.                                     */

     %do i=1 %to 5;
       %drawlab(y&i, min&i, max&i);
       %end;

     /* Set text height, choose font, set alignment, then loop to label*/
     /* each Y axis with the correct variable name.                    */

     rc = gset('texheight', 3);
     rc = gset('texfont', 'swissl');
     rc = gset('texalign', 'left', 'base');
     %do i=1 %to 5;
       rc = gdraw('text', 0, y&i, "&&VAR&I");
       %end;

     /* Begin the plots with an initial line type. The number refers  */
     /* to the nth color in the default colors list of the device     */
     /* driver you are using.                                         */
     /*                                                               */
     /* Later, the line type changes based on a change in the CLASS   */
     /* variable value.                                               */
     /*                                                               */
     /* For color plots, change the line type instead.                */

     lintype = 1;
     rc = gset('lincolor', 1);
     rc = gset('lintype', lintype);

     /* Set the point plot symbol color, type, and size. In this      */
     /* example, the MARTYPE corresponding to the value 67 is an      */
     /* asterisk.                                                     */
     /*                                                               */
     /* See p. 719 of the SAS/GRAPH Software Reference for a table    */
     /* with all the symbols you can use and the values to specify for*/
     /* MARTYPE.                                                      */

     rc = gset('marcolor', 52);
     rc = gset('martype', 67);
     rc = gset('marsize', 4);

     /* This is the end of all of the tasks performed at the first    */
     /* DATA step iteration.                                          */

    end;

  /* Finally, draw lines connecting the points representing the values*/
  /* of each variable in the current observation on each of the axes. */
  /*                                                                  */
  /* The variables X&S1-X&S5 and Y&S1-Y&S5 resolve to the DSGI X and  */
  /* Y coordinates for each plotted data point, but in the order you  */
  /* specify in ORDER at invocation time.                             */

  rc = gdraw('line', ., x&s1, x&s2, x&s3, x&s4, x&s5,
                        y&s1, y&s2, y&s3, y&s4, y&s5);

  /* Draw the plot symbols at each plotted data point on each axis in */
  /* the specified order.                                             */

  rc = gdraw('mark', ., x&s1, x&s2, x&s3, x&s4, x&s5,
                        y&s1, y&s2, y&s3, y&s4, y&s5);

  /* Check to see if the CLASS variable value changes, and change the */
  /* line type (or, alternatively, line color) if it does change.     */

  if lag(&class) ne &class then do;
     lintype + 1;
     rc=gset('lintype', lintype);
     end;

  /* if no more data, close the GRSEG entry, close DSGI, and terminate*/
  /* the DATA step.                                                   */

  if eof then do;
    rc=graph('update');
    rc=gterm();
    end;
  run;
%mend pairwise;

/***************************************************************/
/* MVPLOT:   Creates a three page chart showing all the        */
/*           pairwise comparisons of five variables. The       */
/*           variables are ordered in successive calls of the  */
/*           PAIRWISE macro in order to get all pairings       */
/*           in order to get all pairings.                     */
/*                                                             */
/*  ARGUMENT       VALUE                                       */
/*  --------       -----                                       */
/*  INDS:          input data set containing variables to plot */
/*  LINE:          SAS/GRAPH color for axis lines              */
/*  SYMBOL:        SAS/GRAPH color for symbols                 */
/*  TEXT:          SAS/GRAPH color for text                    */
/*  VAR1-VAR5:     names of the five variables to plot         */
/*  CLASS:         class variable to use to trigger different  */
/*                 style for lines connecting two data points  */
/*                                                             */
/* REQUIREMENTS: Have DRAWLAB macro available for labels. Have */
/*               PAIRWISE macro available for plots            */
/***************************************************************/

%macro mvplot(inds, line, symbol, text,
              var1, var2, var3, var4, var5, class);

  /* Sort the input data set by the class variable to enable changing */
  /* plot line colors when the value of the class variable changes.   */
  proc sort data=&inds; by class; run;

  /* The following PROC MEANS step calculates the minimum, maximum, and  */
  /* range for each plot variable,  and the number of observations to    */
  /* use when merging with the input data set in a later DATA step. The  */
  /* result of this step is a data set with one observation.             */

  proc means data=&inds noprint;
    var &var1 &var2 &var3 &var4 &var5;
    output out= _mvmean_ n=num
           range=range1 range2 range3 range4 range5
           max=max1 max2 max3 max4 max5
           min=min1 min2 min3 min4 min5;
  run;

  /* The following DATA step                                           */
  /*                                                                   */
  /* o creates a factor for each variable plotted based on the range   */
  /*   of values it contains and used to convert actual data values to */
  /*   DSGI coordinates (values between 0 and 100) in a later DATA     */
  /*   step; factores are stored in DISPLAY1-DISPLAY5.                 */
  /*                                                                   */
  /* o transforms the factors to ensure no more than 85 percent of the */
  /*   horizontal space on the plot is used to leave a white space     */
  /*   border around the edges for aesthetic reasons.                  */
  /*                                                                   */
  /* o takes the input statistics data set (containing only one        */
  /*   observation) and copies its single observation repeated to      */
  /*   create a data set having the same number of observations as the */
  /*   data set containing the variables to plot; this step is         */
  /*   necessary so that a subsequent DATA step can merge the          */
  /*   statistics data set and plot data set.                          */

  data _range_;
    set _mvmean_;
    %do i=1 %to 5;
      display&i = 85 / range&i;
      %end;
    keep display1 display2 display3 display4 display5
         max1 max2 max3 max4 max5
         min1 min2 min3 min4 min5 num;
    do i=1 to num; output; end;
    run;

  %pairwise(&inds, &line, &symbol, &text, &var1, &var2, &var3,
            &var4, &var5, &class, 12345);

  %pairwise(&inds, &line, &symbol, &text, &var1, &var2, &var3,
            &var4, &var5, &class, 13524);

  %pairwise(&inds, &line, &symbol, &text, &var1, &var2, &var3,
            &var4, &var5, &class, 25143);

%mend mvplot;

/* get some data and invoke the macro */

data cars;
  length make $ 10 model $ 11;
  input make $ model $ class weight cuin gears price mpg;
  cards;
Chevrolet  Chevette    1  2200    98   2.89   5959  36
Honda      Civic       1  2035    91   3.03   7798  30.5
Toyota     Corolla     1  2270    97   2.70   7348  35.5
Ford       Mustang     2  2860   140   3.08   7189  23
Honda      Prelude     2  2345   112   3.08  10980  31.5
Pontiac    Fiero       2  2530   151   2.48   8949  29
Cadillac   Cimarron    3  2620   121   2.96  13128  28
Nissan     Stanza      3  2440   121   2.60  10069  34
Volkswagen Quantum     3  2640   136   3.14  13595  21.5
Buick      Century     4  2775   151   2.39  10228  27
Ford       Thunderbird 4  3190   232   2.73  11020  22.5
Pontiac    6000        4  2785   151   2.84   9729  22
Buick      Electra     5  3300   231   1.99  15588  23.5
Lincoln    TownCar     5  4060   302   2.06  20764  22
Pontiac    Parisienne  5  3630   262   2.56  11169  21.5
Dodge      Caravan     6  3005   135   2.56   9659  22
Ford       Aerostar    6  3475   140   3.17   9418  18
Volkswagen Vanagon     6  3370   129   4.11  12540  16
;
run;

%mvplot(cars, black, black, black,
        weight, cuin, gears, price, mpg, class);

*
;