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