With the viewport capability of the PROC IML graphics subroutine, you can arrange several graphs on a page. In this example, multiple graphs are generated from three variables and are displayed in a scatterplot matrix. For each variable, one contour plot is generated with each of the other variables as the dependent variable. For the graphs on the main diagonal, a box-and-whiskers plot is generated for each variable.
This example takes advantage of user-defined PROC IML modules:
computes median and quartiles.
draws box-and-whiskers plots.
generates confidence ellipses assuming bivariate normal data.
draws the confidence ellipses for each pair of variables.
produces the scatter plot matrix, where n is the number of variables.
The code for the five modules and a sample data set follow. The modules produce Output 16.1.1 and Output 16.1.2.
/* This program generates a data set and uses iml graphics */ /* subsystem to draw a scatterplot matrix. */ data factory; input recno prod temp a defect mon; datalines; 1 1.82675 71.124 1.12404 1.79845 2 2 1.67179 70.9245 0.924523 1.05246 3 3 2.22397 71.507 1.50696 2.36035 4 4 2.39049 74.8912 4.89122 1.93917 5 5 2.45503 73.5338 3.53382 2.0664 6 6 1.68758 71.6764 1.67642 1.90495 7 7 1.98233 72.4222 2.42221 1.65469 8 8 1.17144 74.0884 4.08839 1.91366 9 9 1.32697 71.7609 1.76087 1.21824 10 10 1.86376 70.3978 0.397753 1.21775 11 11 1.25541 74.888 4.88795 1.87875 12 12 1.17617 73.3528 3.35277 1.15393 1 13 2.38103 77.1762 7.17619 2.26703 2 14 1.13669 73.0157 3.01566 1 3 15 1.01569 70.4645 0.464485 1 4 16 2.36641 74.1699 4.16991 1.73009 5 17 2.27131 73.1005 3.10048 1.79657 6 18 1.80597 72.6299 2.62986 1.8497 7 19 2.41142 81.1973 11.1973 2.137 8 20 1.69218 71.4521 1.45212 1.47894 9 21 1.95271 74.8427 4.8427 1.93493 10 22 1.28452 76.7901 6.79008 2.09208 11 23 1.51663 83.4782 13.4782 1.81162 12 24 1.34177 73.4237 3.42369 1.57054 1 25 1.4309 70.7504 0.750369 1.22444 2 26 1.84851 72.9226 2.92256 2.04468 3 27 2.08114 78.4248 8.42476 1.78175 4 28 1.99175 71.0635 1.06346 1.25951 5 29 2.01235 72.2634 2.2634 1.36943 6 30 2.38742 74.2037 4.20372 1.82846 7 31 1.28055 71.2495 1.24953 1.8286 8 32 2.05698 76.0557 6.05571 2.03548 9 33 1.05429 77.721 7.72096 1.57831 10 34 2.15398 70.8861 0.886068 2.1353 11 35 2.46624 70.9682 0.968163 2.26856 12 36 1.4406 73.5243 3.52429 1.72608 1 37 1.71475 71.527 1.52703 1.72932 2 38 1.51423 78.5824 8.5824 1.97685 3 39 2.41538 73.7909 3.79093 2.07129 4 40 2.28402 71.131 1.13101 2.25293 5 41 1.70251 72.3616 2.36156 2.04926 6 42 1.19747 72.3894 2.3894 1 7 43 1.08089 71.1729 1.17288 1 8 44 2.21695 72.5905 2.59049 1.50915 9 45 1.52717 71.1402 1.14023 1.88717 10 46 1.5463 74.6696 4.66958 1.25725 11 47 2.34151 90 20 3.57864 12 48 1.10737 71.1989 1.19893 1.62447 1 49 2.2491 76.6415 6.64147 2.50868 2 50 1.76659 71.7038 1.70377 1.231 3 51 1.25174 76.9657 6.96572 1.99521 4 52 1.81153 73.0722 3.07225 2.15915 5 53 1.72942 71.9639 1.96392 1.86142 6 54 2.17748 78.1207 8.12068 2.54388 7 55 1.29186 77.0589 7.05886 1.82777 8 56 1.92399 72.6126 2.61256 1.32816 9 57 1.38008 70.8872 0.887228 1.37826 10 58 1.96143 73.8529 3.85289 1.87809 11 59 1.61795 74.6957 4.69565 1.65806 12 60 2.02756 75.7877 5.78773 1.72684 1 61 2.41378 75.9826 5.98255 2.76309 2 62 1.41413 71.3419 1.34194 1.75285 3 63 2.31185 72.5469 2.54685 2.27947 4 64 1.94336 71.5592 1.55922 1.96157 5 65 2.094 74.7338 4.73385 2.07885 6 66 1.19458 72.233 2.23301 1 7 67 2.13118 79.1225 9.1225 1.84193 8 68 1.48076 87.0511 17.0511 2.94927 9 69 1.98502 79.0913 9.09131 2.47104 10 70 2.25937 73.8232 3.82322 2.49798 12 71 1.18744 70.6821 0.682067 1.2848 1 72 1.20189 70.7053 0.705311 1.33293 2 73 1.69115 73.9781 3.9781 1.87517 3 74 1.0556 73.2146 3.21459 1 4 75 1.59936 71.4165 1.41653 1.29695 5 76 1.66044 70.7151 0.715145 1.22362 6 77 1.79167 74.8072 4.80722 1.86081 7 78 2.30484 71.5028 1.50285 1.60626 8 79 2.49073 71.5908 1.59084 1.80815 9 80 1.32729 70.9077 0.907698 1.12889 10 81 2.48874 83.0079 13.0079 2.59237 11 82 2.46786 84.1806 14.1806 3.35518 12 83 2.12407 73.5826 3.58261 1.98482 1 84 2.46982 76.6556 6.65559 2.48936 2 85 1.00777 70.2504 0.250364 1 3 86 1.93118 73.9276 3.92763 1.84407 4 87 1.00017 72.6359 2.63594 1.3882 5 88 1.90622 71.047 1.047 1.7595 6 89 2.43744 72.321 2.32097 1.67244 7 90 1.25712 90 20 2.63949 8 91 1.10811 71.8299 1.82987 1 9 92 2.25545 71.8849 1.8849 1.94247 10 93 2.47971 73.4697 3.4697 1.87842 11 94 1.93378 74.2952 4.2952 1.52478 12 95 2.17525 73.0547 3.05466 2.23563 1 96 2.18723 70.8299 0.829929 1.75177 2 97 1.69984 72.0026 2.00263 1.45564 3 98 1.12504 70.4229 0.422904 1.06042 4 99 2.41723 73.7324 3.73238 2.18307 5 ; proc iml; call gstart; /*-- Load graphics --*/ /*--------------------*/ /*-- Define modules --*/ /*--------------------*/ /* Module : compute contours */ /* This routine computes contours for a scatter plot */ /* c returns the contours as consecutive pairs of columns */ /* x and y are the x and y coordinates of the points */ /* npoints is the number of points in a contour */ /* pvalues is a column vector of contour probabilities */ /* the number of contours is controlled by the ncol(pvalue) */ start contour(c,x,y,npoints,pvalues); xx=x||y; n=nrow(x); /* Correct for the mean */ mean=mean(xx); xx=xx-mean; /* Find principal axes of ellipses */ xx=xx` *xx/n; call eigen(v,e,xx); /* Set contour levels */ c=-2*log(1-pvalues); a=sqrt(c*v[1]); b=sqrt(c*v[2]); /* Parameterize the ellipse by angle */ t=((1:npoints)-{1})#atan(1)#8/(npoints-1); s=sin(t); t=cos(t); s=s` *a; t=t` *b; /* Form contour points */ s=((e*(shape(s,1)//shape(t,1)))+mean`@j(1,npoints*ncol(c),1))`; c=shape(s,npoints); /* Returned as ncol pairs of columns */ finish contour; /*-- Module : draw contour curves --*/ start gcontour(t1, t2); run contour(t12, t1, t2, 30, {.5 .8 .9}); window=(min(t12[,{1 3}],t1)||min(t12[,{2 4}],t2))// (max(t12[,{1 3}],t1)||max(t12[,{2 4}],t2)); call gwindow(window); call gdraw(t12[,1],t12[,2],,'blue'); call gdraw(t12[,3],t12[,4],,'blue'); call gdraw(t12[,5],t12[,6],,'blue'); call gpoint(t1,t2,,'red'); finish gcontour;
/*-- Module : find median, quartiles for box and whisker plot --*/ start boxwhskr(x, u, q2, m, q1, l); rx=rank(x); s=x; s[rx,]=x; n=nrow(x); /*-- Median --*/ m=floor(((n+1)/2)||((n+2)/2)); m=(s[m,])[+,]/2; /*-- Compute quartiles --*/ q1=floor(((n+3)/4)||((n+6)/4)); q1=(s[q1,])[+,]/2; q2=ceil(((3*n+1)/4)||((3*n-2)/4)); q2=(s[q2,])[+,]/2; h=1.5*(q2-q1); /*-- step=1.5*(interquartile range) --*/ u=q2+h; l=q1-h; u=(u>s)[+,]; /*-- adjacent values -----------------*/ u=s[u,]; l=(l>s)[+,]; l=s[l+1,]; finish boxwhskr; /*-- Box and Whisker plot --*/ start gbxwhskr(t, ht); run boxwhskr(t, up, q2,med, q1, lo); /*---Adjust screen viewport and data window */ y=min(t)//max(t); call gwindow({0, 100} || y); mid = 50; wlen = 20; /*-- Add whiskers */ wstart=mid-(wlen/2); from=(wstart||up)//(wstart||lo); to=((wstart//wstart)+wlen)||from[,2]; /*-- Add box */ len=50; wstart=mid-(len/2); wstop=wstart+len; from=from//(wstart||q2)//(wstart||q1)// (wstart||q2)//(wstop||q2); to=to//(wstop||q2)//(wstop||q1)// (wstart||q1)//(wstop||q1); /*---Add median line */ from=from//(wstart||med); to=to//(wstop||med);
/*---Attach whiskers to box */ from=from//(mid||up)//(mid||lo); to=to//(mid||q2)//(mid||q1); /*-- Draw box and whiskers */ call gdrawl(from, to,,'red'); /*---Add minimum and maximum data points */ call gpoint(mid, y ,3,'red'); /*---Label min, max, and mean */ y=med//y; s={'med' 'min' 'max'}; call gset("font","swiss"); call gset('height',13); call gscript(wstop+ht, y, char(y,5,2),,,,,'blue'); call gstrlen(len, s); call gscript(wstart-len-ht,y,s,,,,,'blue'); call gset('height'); finish gbxwhskr; /*-- Module : do scatter plot matrix --*/ start gscatmat(data, vname); call gopen('scatter'); nv=ncol(vname); if (nv=1) then nv=nrow(vname); cellwid=int(90/nv); dist=0.1*cellwid; width=cellwid-2*dist; xstart=int((90 -cellwid * nv)/2) + 5; xgrid=((0:nv)#cellwid + xstart)`; /*-- Delineate cells --*/ cell1=xgrid; cell1=cell1||(cell1[nv+1]//cell1[nv+1-(0:nv-1)]); cell2=j(nv+1, 1, xstart); cell2=cell1[,1]||cell2; call gdrawl(cell1, cell2); call gdrawl(cell1[,{2 1}], cell2[,{2 1}]); xstart = xstart + dist; ystart = xgrid[nv] + dist; /*-- Label variables ---*/ call gset("height", 5); call gset("font","swiss"); call gstrlen(len, vname); where=xgrid[1:nv] + (cellwid-len)/2; call gscript(where, 0, vname) ; len=len[nv-(0:nv-1)]; where=xgrid[1:nv] + (cellwid-len)/2; call gscript(4,where, vname[nv - (0:nv-1)],90); /*-- First viewport --*/ vp=(xstart || ystart)//((xstart || ystart) + width) ; /* Since the characters are scaled to the viewport */ /* (which is inversely porportional to the */ /* number of variables), */ /* enlarge it proportional to the number of variables */ ht=2*nv; call gset("height", ht); do i=1 to nv; do j=1 to i; call gportstk(vp); if (i=j) then run gbxwhskr(data[,i], ht); else run gcontour(data[,j], data[,i]); /*-- onto the next viewport --*/ vp[,1] = vp[,1] + cellwid; call gportpop; end; vp=(xstart // xstart + width) || (vp[,2] - cellwid); end; call gshow; finish gscatmat; /*-- Placement of text is based on the character height. */ /* The IML modules defined here assume percent as the unit of */ /* character height for device independent control. */ goptions gunit=pct; use factory; vname={prod, temp, defect}; read all var vname into xyz; run gscatmat(xyz, vname[1:2]); /*-- 2 x 2 scatter plot matrix --*/ run gscatmat(xyz, vname); /*-- 3 x 3 scatter plot matrix --*/ quit; goptions gunit=cell; /*-- reset back to default --*/