/**********************************************************************/
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');
/**********************************************************************/