/**********************************************************************/


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;  


/**********************************************************************/


   /* The PAIRWISE Macro */

   /* 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:      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                */                                                                    
   /*                                                             */                                                                    
   /*  REQUIREMENTS: Sort INDS by CLASS.                          */                                                                    
   /*                Have DRAWLAB macro (shown later in the       */                                                                    
   /*                example) available for labels.               */                                                                    
   /*                                                             */                                                                    
                                                                                                                                     
%macro pairwise(inds,line,symbol,text,                                                                                            
                var1,var2,var3,var4,var5,                                                                                        
                class,order);                                                                                                       
                                                                                                                                     
                                                                                                                                     
   /* The following PROC MEANS step calculates both 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 coordinate values (values     */                                                               
   /*    between 0 and 100) in a later DATA step; factors are     */                                                               
   /*    stored in variables named 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       */                                                               
   /*    repeatedly 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 the 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;                                                                                                                             
                                                                                                                                     
   /* 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 immediately preceding DATA step.             */                                                                  
data _null_;                                                                                                                         
                                                                                                                                     
   /* Make sure variables containing the Y axis coordinates and   */                                                              
   /* line color loop index persist across DATA step iterations.  */                                                                  
retain y1 y2 y3 y4 y5 lincol;                                                                                                      
                                                                                                                                     
   /* 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 */                                                                  
   /* values.                                                     */                                                                  
   /*                                                             */                                                                  
   /* 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 value 95.                                        */                                                                  
%do i=1 %to 5;                                                                                                                     
   x&i=(&&var&i-min&i)*display&i+10;                                                                                              
%end;                                                                                                                            
                                                                                                                                     
      /* Everything in the following DO group, 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 values were chosen to provide evenly spaced        */                                                                  
      /* horizontal axis lines in the output using 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 linecolor, 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. The code for DRAWLAB */                                                                  
      /* appears later.                                           */                                                                  
   rc=gset('texheight',2.5);                                                                                                      
   %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 color. The number   */                                                                  
      /* refers to the nth color in the default colors list of    */                                                                  
      /* the device driver you are using.                         */                                                                  
      /*                                                          */                                                                  
      /* Later, the line color changes based on a change in the   */                                                                  
      /* CLASS variable value.                                    */                                                                  
      /*                                                          */                                                                  
      /* For black and white plots, change the line type instead. */                                                                  
   lincol=1;                                                                                                                       
   rc=gset('lincolor',lincol);                                                                                                    
   rc=gset('lintype',1);                                                                                                          
                                                                                                                                     
      /* 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 SAS/GRAPH Software Reference for a table   */                                                                  
      /* with all of the symbols you can use and the values to    */                                                                  
      /* specify for MARTYPE.                                     */                                                                  
      /*                                                          */                                                                  
      /* The size of the symbol is specified in DSGI coordinate   */                                                                  
      /* units.                                                   */                                                                  
   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 color (or alternatively, line type in    */                                                                  
      /* black and white) if it does change.                      */                                                                  
   if lag(&class) ne &class then do;                                                                                                  
      lincol+1;                                                                                                                    
      rc=gset('lincolor',lincol);                                                                                                   
   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;                                                                                                                      
                                                                                                                                     

/**********************************************************************/


   /* The DRAWLAB Macro */

   /* DRAWLAB:  Places text labels with minimum and maximum       */                                                                 
   /*           values at each end of each Y axis.                */                                                                 
   /*              ARGUMENT    VALUE                              */                                                                 
   /*              --------    -----                              */                                                                 
   /*              Y:          Y coordinate (position of axis)    */                                                                 
   /*              B:          minimum value                      */                                                                 
   /*              T:          maximum value                      */                                                                 
   /*                                                             */                                                                 
   /*  REQUIREMENTS: Used 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;                                                                                                                       
                

/**********************************************************************/


   /* The MVPLOT Macro */ 

   /* 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.  */                                                                 
   /*                                                             */                                                                 
   /*              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 colors for lines         */                                                                 
   /*                          connecting each 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. This was formerly a part of the   */                                                                 
   /* macro %PAIRWISE, but for efficiency was removed from there  */                                                                 
   /* and inserted here.                                          */                                                                 
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 coordinate values (values    */                                                                    
   /*     between 0 and 100) in a later DATA step; factors are    */                                                                    
   /*     stored in variables named 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       */                                                                    
   /*    repeatedly 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 the plot data set.                                   */                                                                    
   /*                                                             */                                                                    
   /* This was formerly a part of the macro %PAIRWISE, but for    */                                                                    
   /* efficiency was removed from there and inserted here.        */                                                                    
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;                                                                                                                               
                                                                                                                                     
     /* The following three invocations of PAIRWISE provide three */                                                               
     /* plots containing every possible combination of variable   */                                                               
     /* pairs plotted on adjacent axes.                           */                                                               
  %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;                                                                                                                                           
                      

/**********************************************************************/


   /* Modifying the Example */

   /* Replacement code                                            */
retain y1 y2 y3 y4 y5 lintyp;                                                                                                        
      /* more program lines */                                                                                                               
   lintyp=1;                                                                                                                         
   rc=gset('lincolor',1);                                                                                                           
   rc=gset('lintype',lintyp);                                                                                                       
      /* more program lines */                                                                                                               
    lintyp+1;                                                                                                                        
    rc=gset('lintype',lintyp);                                                                                                      
                     
   /* Produce a legend describing line types on plot.             */                                                                         
rc=gset('texheight',2);                                                                                                             
rc=gset('texalign','left','half');                                                                                                 
rc=gset('lintype',1);                                                                                                               
rc=gdraw('line',.,10,20,10,10);                                                                                                 
rc=gdraw('text',23,10,'Compact');                                                                                                 
rc=gset('lintype',2);                                                                                                               
rc=gdraw('line',.,40,50,10,10);                                                                                                 
rc=gdraw('text',53,10,'Sports');                                                                                                  
rc=gset('lintype',3);                                                                                                               
rc=gdraw('line',.,70,80,10,10);                                                                                                 
rc=gdraw('text',83,10,'Midsize');                                                                                                 
rc=gset('lintype',4);                                                                                                               
rc=gdraw('line',.,10,20,5,5);                                                                                                   
rc=gdraw('text',23,5,'Fullsize');                                                                                                 
rc=gset('lintype',5);                                                                                                               
rc=gdraw('line',.,40,50,5,5);                                                                                                   
rc=gdraw('text',53,5,'Luxury');                                                                                                   
rc=gset('lintype',6);                                                                                                               
rc=gdraw('line',.,70,80,5,5);                                                                                                   
rc=gdraw('text',83,5,'Minivans');                                                                                                 
rc=gset('texalign','left','base');                                                                                                 
                                                 

/**********************************************************************/