%macro plotit( /*-----------------------------------------*/ /* Note that by default you may not */ /* specify a GOPTIONS statement. If you */ /* do, it will be overridden. */ /* All GOPTIONS (except DEVICE=) must be */ /* specified with the four GOP options. */ /* */ /* Modify the GOPPRINT= and GOPPLOT= */ /* options to set default devices so that */ /* you will not be prompted. */ /* */ /* Note that for many analyses, the only */ /* options you need to specify are DATA=, */ /* DATATYPE=, and sometimes METHOD=. To */ /* specify variables to plot, specify */ /* PLOTVARS=, LABELVAR=, and SYMVAR=. */ /* */ /* This macro looks for a special global */ /* macro variable named PLOTITOP. If it */ /* exists, its values are used to override */ /* the macro options. Say you have a */ /* series of calls to the plotting macro */ /* and you want to route them all to a */ /* postscript file, you can specify once, */ /* */ /* %let plotitop = gopts= */ /* gsfmode=append */ /* gaccess=gsasfile */ /* device=qmscolor; */ /* */ /* and run the macro calls without change. */ /* */ /* The value of the macro variable must */ /* begin with a name, followed by an equal */ /* sign, followed by a value. Optionally, */ /* it may continue with a comma, followed */ /* by a name, followed by an equal sign, */ /* followed by a value, and so on. Values */ /* must not contain commas. Example: */ /* */ /* %let plotitop = color=black, */ /* gopts=cback=cyan; */ /*-----------------------------------------*/ method=gplot, /* gplot - displays a graphical */ /* scatter plot on your screen */ /* using the GOPTIONS from */ /* GOPPLOT=. GOPPLOT= should */ /* contain the GOPTIONS that only */ /* apply to plots displayed on the */ /* screen. */ /* */ /* plot - creates a printer plot only. */ /* */ /* print - routes the plot to a graphics */ /* stream file, such as a post */ /* script file, using the GOPTIONS */ /* from GOPPRINT=. GOPPRINT= */ /* should contain the GOPTIONS */ /* that only apply to hard-copy */ /* plots. Specify the file name */ /* with POST=. */ /* */ /* none - Just creates the Annotate data */ /* set and sets up GOPTIONS using */ /* GOPPLOT=. */ /*-----------------------------------------*/ /* The next four options specify GOPTIONS: */ /* gopprint - specifies the GOPTIONS for */ /* printing (creating a */ /* graphics stream file). */ /* gopplot - specifies the GOPTIONS for */ /* directly plotting on the */ /* screen. */ /* gopts2 - specifies the GOPTIONS that */ /* are always used, no matter */ /* which METHOD= is specified. */ /* gopts - provides a way to specify */ /* additional GOPTIONS that are */ /* always used. */ /* */ /* Modify the GOPPRINT= and GOPPLOT= */ /* option defaults to set default devices */ /* so that you will not be prompted. */ /* Example: */ /* GOPPRINT=gsfmode=replace */ /* gaccess=gsasfile */ /* device=qmscolor, */ /* GOPPLOT=cback=black device=xcolor, */ /* */ /* If you would prefer to specify your own */ /* GOPTIONS statement and have the macro */ /* use it, just specify or change the */ /* default for these four options to null: */ /* GOPPLOT=, GOPPRINT=, GOPTS2=, GOPTS=. */ /* */ /* A few device names: */ /* qmscolor - color plotter. */ /* psepsf - encapsulated postscript. */ /* psl - postscript. */ /* xcolor - X windows, color. */ /* */ /* Useful additional goptions for GOPTS= */ /* include: */ /* rotate - landscape orientation */ /* cback=color - background color */ /*-----------------------------------------*/ gopplot=, gopprint=gsfmode=replace gaccess=gsasfile, gopts2=reset=goptions erase, gopts=, /*-----------------------------------------*/ data=_last_, /* Input data set. You should always */ /* specify DATA= since the macro creates */ /* data sets that are not suitable for use */ /* as input. */ /* */ out=anno, /* Output Annotate data set. */ /* */ gout=, /* PROC ANNO GOUT= specification. This */ /* option puts a plot in a catalogue. */ /* With GOUT=gc.slides, first specify: */ /* LIBNAME GC '.'; */ /* Then to replay, run: */ /* PROC GREPLAY IGOUT=GC.SLIDES; RUN; */ /* */ /* Note that replayed plots will not in */ /* general have the correct aspect ratio. */ /* */ gname=, /* Name of catalogue entry, */ /* optionally used with PROC ANNO GOUT=, */ /* provides NAME=. */ /* */ gdesc=, /* Name of catalogue description, */ /* optionally used with PROC ANNO GOUT=, */ /* provides DESCRIPTION=. */ /*-----------------------------------------*/ plotvars=, /* Specify the y variable then the x */ /* variable. To work with say DIM2 and */ /* DIM3, specify PLOTVARS=DIM2 DIM3. The */ /* DATATYPE= option controls the default. */ /* */ labelvar=, /* Variable that contains the point */ /* labels. The default is the last */ /* character variable in the data set. */ /* If LABELVAR=_blank_ is specified, the */ /* macro will create a blank label */ /* variable. */ /* */ symvar=_symbol_, /* Variable that contains the plotting */ /* symbol for input to PROC PLOT. When */ /* _symbol_ is specified, this variable is */ /* created, typically from the SYMBOLS= */ /* list, which may be constructed inside */ /* the macro. (Note that the variable */ /* __symbol is created to contain the */ /* symbol for the graphical scatter plot. */ /* The variables _symbol_ and __symbol may */ /* or may not contain the same values.) */ /* Variables can be specified, and the */ /* first SYMLEN= characters are used for */ /* the symbol. When a null (SYMVAR=,) or */ /* constant value is specified, the symbol */ /* from the printer plot will be used */ /* (which is always length one, no matter */ /* what is specified for SYMLEN=). To get */ /* PROC PLOT pointer symbols, specify */ /* SYMVAR='00'x, (hex null constant). To */ /* center labels with no symbols, specify: */ /* SYMVAR=,PLACE=0. */ /* */ symlen=1, /* Length of symbols. Normally, symbols */ /* are single characters, but the macro */ /* can center longer strings at the symbol */ /* location. */ /*-----------------------------------------*/ datatype=, /* Specifies the type of data analysis */ /* that generated the data set. This */ /* option is used to set defaults for */ /* other options and to do some */ /* preprocessing of the data. */ /* */ /* When the data type is corresp, mds, */ /* mca, row, column, mdpref, mdpref2, */ /* vector, or ideal, LABEL=typical is */ /* implied when LABEL= is not otherwise */ /* specified. The default point label */ /* variable is the last character variable */ /* in the data set. */ /* */ /* Some data types (mdpref, vector, ideal, */ /* corresp, row, mca, column, mds) expect */ /* certain observation types and set the */ /* TYPES= list accordingly. For example, */ /* mdpref expects _TYPE_ = 'SCORE' and */ /* _TYPE_ = 'CORR' observations. The */ /* remaining data types do not expect any */ /* specific value of the TYPEVAR= */ /* variable. So if you do not get the */ /* right data types associated with the */ /* right observation types, specify */ /* TYPES=, and specify the TYPES= values */ /* in an order that corresponds to the */ /* order of the symbol types in the "Types */ /* Legend" table. Unlike SYMTYPE=, the */ /* order in which you specify DATATYPE= */ /* values is irrelevant. */ /* */ /* null value - (DATATYPE=, the default) */ /* no special processing. The default */ /* plotting variables are the first two */ /* numeric variables in the data set. */ /* */ /* corresp, mds, mca, row, column: */ /* sets the default PLOTVARS to DIM2 and */ /* DIM1. */ /* */ /* otherwise when a nonnull value is */ /* specified, the default PLOTVARS are */ /* PRIN2 and PRIN1. */ /* */ /* DATATYPE=symbol, */ /* ordinary scatter plot. */ /* */ /* DATATYPE=mdpref, */ /* specifies multidimensional preference */ /* analysis with vectors and blank labels. */ /* Note that DATATYPE=mdpref can also be */ /* used for ordinary principal component */ /* analysis. */ /* */ /* DATATYPE=mdpref2, */ /* specifies MDPREF with vector labels */ /* (MDPREF and labels *too*). */ /* */ /* DATATYPE=vector, */ /* specifies a PREFMAP vector model. */ /* */ /* DATATYPE=mds vector, */ /* specifies PREFMAP after MDS. */ /* */ /* DATATYPE=ideal, */ /* specifies a PREFMAP ideal point model. */ /* See the ANTIIDEA=, RADII=, and CIRSEGS= */ /* options. */ /* */ /* DATATYPE=mds ideal, */ /* specifies PREFMAP ideal point after */ /* the MDS. */ /* */ /* DATATYPE=corresp, */ /* specifies an ordinary correspondence */ /* analysis. */ /* */ /* DATATYPE=row, */ /* specifies a PROC CORRESP PROFILE=ROW */ /* analysis. Column points are plotted as */ /* vectors. */ /* */ /* DATATYPE=column, */ /* specifies a PROC CORRESP PROFILE=COLUMN */ /* analysis. Row points are plotted as */ /* vectors. */ /* */ /* DATATYPE=mca, */ /* specifies a multiple correspondence */ /* analysis. */ /* */ /* DATATYPE=vector ideal, */ /* both PREFMAP vectors and ideal points. */ /* */ /* DATATYPE=curve, */ /* fit a curve through the scatter plot. */ /* */ /* DATATYPE=curve2, */ /* fit a curve through the scatter plot */ /* and try to make the labels avoid */ /* overprinting the curve too. */ /* */ /* DATATYPE=function, */ /* draws functions. Typically, no labels */ /* or symbols are drawn. This option has */ /* a similar effect to the PROC GPLOT */ /* SYMBOL statement options I=JOIN V=NONE. */ /* */ /* DATATYPE=contour, */ /* draws solid color contour plots. See */ /* the sample code above. When the number */ /* of row points is not the same as the */ /* number of column points in the grid, */ /* use HNOBS= and VNOBS= to specify the */ /* number of points. This method creates */ /* an HNOBS= by VNOBS= grid of colored */ /* rectangles. Each of the rectangles */ /* should touch all adjacent rectangles. */ /* This method works well with a regular */ /* grid of points. METHOD=square is a */ /* good alternative when the data do not */ /* fall in a regular grid. */ /* */ /* DATATYPE=square, */ /* plots each point as a solid square. */ /* DATATYPE=square is useful as a form of */ /* contour plotting when the data do not */ /* form a regular grid. DATATYPE=square */ /* unlike DATATYPE=contour does not try to */ /* scale the size of the square so that */ /* each square will touch another square. */ /* */ /* For some DATATYPE= values, a number may */ /* be specified after the name. This is */ /* primarily useful for biplot data sets */ /* produced by PRINQUAL and PREFMAP data */ /* sets produced by PROC TRANSREG. This */ /* number specifies that the lengths of */ /* vectors should be changed by this */ /* amount. The number must be specified */ /* last. Examples: */ /* DATATYPE=mdpref 2, */ /* DATATYPE=mds vector 1.5. */ /* */ /* The primary purpose of the DATATYPE= */ /* option is to provide an easy mechanism */ /* for specifying defaults for the options */ /* in the next section (TYPEVAR= through */ /* OUTWARD=). */ /*-----------------------------------------*/ options=, /* Binary options. Specify zero, one, or */ /* more in any order. For example: */ /* OPTIONS=nocenter nolegend, */ /* */ /* nocenter - do not center. By default, */ /* when nocenter is not specified, VSIZE= */ /* and HSIZE= are set to their maximum */ /* values, and the VPOS= and HPOS= values */ /* are increased accordingly. The X and Y */ /* coordinates are increased to position */ /* the plot in the center of the full */ /* graphics area. */ /* */ /* noclip - do not clip. By default, when */ /* noclip is not specified, labels that */ /* extend past the edges of the plot are */ /* clipped. Otherwise, do not clip. This */ /* option will not absolutely prevent */ /* labels from extending beyond the plot, */ /* particularly when sizes are greater */ /* than 1. */ /* */ /* textline - put text in the data set, */ /* followed by lines, so lines overwrite */ /* text. Otherwise text overwrites lines. */ /* */ /* square - uses the same ticks for both */ /* axes and tries to make the plot square */ /* by tinkering with the EXTEND= option. */ /* Otherwise, ticks may be different. */ /* */ /* nolegend - suppresses the printing of */ /* the legends. */ /* */ /* nocode - suppresses the printing of the */ /* proc plot and goptions statements. */ /* */ /* nohistory - suppresses the printing of */ /* the iteration history table. */ /* */ /* noprint - equivalent to nolegend, */ /* nocode, and nohistory. */ /* */ /* nodelete - do not delete intermediate */ /* data sets. */ /* */ /* border - draw a border box around the */ /* outside of the graphics area, like the */ /* border goption. */ /* */ /* close - if a border is being drawn */ /* perform the same adjustments on the */ /* border that are performed on the axes. */ /* This option is most useful with contour */ /* plots. */ /* */ /* expand - specifies annotate data set */ /* post processing, typically for use */ /* with extend=close and contour plots. */ /* Makes the plot bigger to fill up more */ /* of the window. */ /*-----------------------------------------*/ /* Defaults for these options are set by */ /* the DATATYPE= option. When you can, */ /* you should use DATATYPE= instead of any */ /* of these options. If you do use these */ /* options, specify a variable, in */ /* TYPEVAR=, whose values distinguish the */ /* observation types. Specify the list of */ /* valid types in TYPES=. Then specify */ /* colors, fonts, sizes, and so on for the */ /* various observation types. */ /* Alternatively, you can use these */ /* options with DATATYPE=. Specify lists */ /* for just those label or symbol */ /* characteristics you want to change, for */ /* example colors, fonts or sizes. */ /* */ typevar=, /* Variable that is looked at for the */ /* observation types. By default, this */ /* will be _TYPE_ if it is in the input */ /* data set. */ /* */ /* These next options specify lists that */ /* are all related. They specify how to */ /* process the plot. Observations are */ /* distinguished by their values on the */ /* TYPEVAR= variable, and each type of */ /* observation can have a different color, */ /* size, symbol and so on. Be aware that */ /* your lists are added to internally. */ /* */ /* These next options consist of lists of */ /* strings. The lists do not all have to */ /* have the same number of elements. The */ /* number of elements in TYPES= determines */ /* how many of the other list elements are */ /* used. When an observation type does */ /* not match one of the TYPE= values, the */ /* results are the same as if the first */ /* type were matched. If one of the other */ /* lists is shorter than the TYPES= list, */ /* the shorter list is extended by adding */ /* copies of the last element to the end. */ /* Individual list values may be quoted, */ /* but quotes are not required. */ /* */ /* ***EMBEDDED BLANKS ARE NOT PERMITTED*** */ /* */ /* IF YOU EMBED BLANKS, YOU WILL NOT GET */ /* THE RIGHT RESULTS. */ /* */ /* Values of the TYPEVAR= variable are */ /* compressed before they are used, so for */ /* example, an _TYPE_ value of 'M COEFFI' */ /* must be specified as 'MCOEFFI'. */ /* */ types=, /* Observation types are usually values of */ /* a variable like _TYPE_. */ /* */ /* ***EMBEDDED BLANKS ARE NOT PERMITTED*** */ /* */ /* Examples: */ /* TYPES='SCORE' */ /* TYPES='OBS' 'SUPOBS' 'VAR' 'SUPVAR' */ /* TYPES='SCORE' */ /* TYPES='SCORE' 'MCOEFFI' */ /* */ /* The order in which values are specified */ /* for the subsequent options depends on */ /* the order of the types. The default */ /* types for various DATATYPE= values are */ /* given next: */ /* */ /* corresp: 'VAR' 'OBS' 'SUPVAR' 'SUPOBS' */ /* row: 'VAR' 'OBS' 'SUPVAR' 'SUPOBS' */ /* mca: 'VAR' 'OBS' 'SUPVAR' 'SUPOBS' */ /* column: 'VAR' 'OBS' 'SUPVAR' 'SUPOBS' */ /* mdpref: 'SCORE' 'CORR' */ /* vector: 'SCORE' 'MCOEFFI' */ /* ideal: 'SCORE' 'MPOINT' */ /* mds: 'SCORE' 'CONFIG' */ /* */ /* For combinations, these lists are */ /* combined in order, but without */ /* repeating 'SCORE', for example with */ /* DATATYPE=mdpref vector ideal, the */ /* default TYPES= list is: */ /* 'SCORE' 'CORR' 'MCOEFFI' 'MPOINT'. */ /* */ symbols=, /* Plotting symbols. Symbols may be more */ /* than a single character. You must */ /* specify SYMLEN=n for longer lengths. */ /* Blank symbols *MUST* be specified as '' */ /* with no embedded blanks. */ /* Examples: */ /* SYMBOLS='*', */ /* SYMBOLS='**' */ /* SYMBOLS='*' '+' '*' '' */ /* SYMBOLS='NC' 'OH' 'NJ' 'NY' */ /* */ symtype=, /* Types of symbols. Valid values are */ /* symbol, vector, circle, contour, */ /* square. Examples: */ /* SYMTYPE='symbol' */ /* SYMTYPE='symbol' 'vector' */ /* SYMTYPE='symbol' 'circle' */ /* */ symcol=, /* Colors of symbols. The default list */ /* is constructed from the COLORS= option. */ /* Examples: */ /* SYMCOL='red' */ /* SYMCOL='red' 'white' 'blue' */ /* */ symsize=, /* Sizes of symbol. */ /* Examples: */ /* SYMSIZE=1 */ /* SYMSIZE=1 1.5 */ /* */ symfont=, /* Symbol fonts. The font is ignored for */ /* vectors with no symbols. Examples: */ /* SYMFONT='swiss' */ /* SYMFONT='swiss' 'swissi' */ /* */ labcol=, /* Colors for the label associated with */ /* the symbol. The default list is */ /* constructed from the COLORS= option. */ /* Examples: */ /* LABCOL='red' */ /* LABCOL='red' 'white' 'blue' */ /* */ labsize=, /* Sizes for the label associated with the */ /* symbol. Examples: */ /* LABSIZE=1 */ /* LABSIZE=1 1.5 */ /* LABSIZE=1 0 */ /* */ labfont=, /* Fonts for the label associated with the */ /* symbol. Examples: */ /* LABFONT='swiss' */ /* LABFONT='swiss' 'swissi' */ /*-----------------------------------------*/ britypes=symbol, /* Types to which BRIGHT= applies. */ /* */ rgbtypes=symbol, /* Types to which PAINT=, RED=, GREEN=, */ /* and BLUE= apply. */ /* */ exttypes=vector, /* Types to always put in the EXTRAOBS= */ /* data set when they have blank labels. */ /*-----------------------------------------*/ filepref=sasplot, /* File name prefix. */ /* */ post=, /* Graphics stream file name. The default */ /* name is constructed from the FILEPREF= */ /* value and "ps" in a host specific way. */ /* */ tempdat1=tempdat1, /* Data sets used to hold intermediate */ tempdat2=tempdat2, /* results. */ tempdat3=tempdat3, /* */ tempdat4=tempdat4, /* */ tempdat5=tempdat5, /* */ /* */ preproc=preproc, /* Data set to contain the preprocessed */ /* DATA= data set. */ /* */ extraobs=extraobs, /* Data set to contain the extra */ /* observations that do not go through */ /* PROC PLOT. */ /* */ regdat=regdat, /* Data set used to contain intermediate */ /* regression results for curve fitting. */ /*-----------------------------------------*/ procopts=nolegend, /* PROC PLOT statement options. */ /* */ plotopts=, /* PLOT statement options. BOX will be */ /* specified, even if you do not specify */ /* it. Reference lines should not be */ /* specified using the PROC PLOT HREF= and */ /* VREF= options. Instead, directly use */ /* the macro options. */ /* */ href=, /* Horizontal reference lines. Specify a */ /* DATA step DO list. */ /* */ vref=, /* Vertical reference lines. Specify a */ /* DATA step DO list. */ /* */ hminor=, /* Number of horizontal axis minor tick */ /* marks between major tick marks. A */ /* typical value is 9. The number cannot */ /* be specified when HAXIS= is specified */ /* with PLOTOPTS=. Alternatively, specify */ /* a data step DO list. Note that with */ /* log scaling, specify log10's of the */ /* data values. For example, HMINOR=0.25 */ /* to 5 by 0.25, with data ranging up to */ /* 10**5. */ /* */ vminor=, /* Number of vertical axis minor tick */ /* marks between major tick marks. A */ /* typical value is 9. The number cannot */ /* be specified when VAXIS= is specified */ /* with PLOTOPTS=. Alternatively, specify */ /* a data step DO list. Note that with */ /* log scaling, specify log10's of the */ /* data values. For example, VMINOR=0.25 */ /* to 5 by 0.25, with data ranging up to */ /* 10**5. */ /* */ label=, /* LABEL statement. Note that specifying */ /* the keyword LABEL is optional. */ /* Abbreviation: LABEL=typical specifies */ /* that a label statement be constructed */ /* with 'Dimension' and the numeric suffix */ /* of the variable name, for example, */ /* LABEL DIM1 = 'Dimension 1' */ /* DIM2 = 'Dimension 2'; */ /* when PLOTVARS=DIM2 DIM1. LABEL=typical */ /* can only be used with variable names */ /* that consist of a prefix and a numeric */ /* suffix. */ /* */ place=2 search, /* Generates a PLACEMENT= option for the */ /* plot request. Specify a nonnegative */ /* integer. Values greater than 13 are */ /* set to 13. As the value gets larger, */ /* the procedure is given more freedom to */ /* move the labels farther from the */ /* symbols. The generated placement list */ /* will be printed in the log. You can */ /* still specify PLACEMENT= directly on */ /* the PLOTOPTS= option. This option just */ /* gives you a shorthand notation. */ /* For example: */ /* PLACE=0 - placement=((s=center)) */ /* PLACE=1 - placement=(h=2 -2 : s=right */ /* left) (v=1 * h=0 -1 to -2 by alt)) */ /* PLACE=2 - placement=(h=2 -2 : s=right */ /* left) (v=1 -1 * h=0 -1 to -5 by alt)) */ /* PLACE=3 - placement=(h=2 -2 : s=right */ /* left) (v=1 to 2 by alt * h=0 -1 to -10 */ /* by alt)) */ /* PLACE=4 - placement=((h=2 -2 : s=right */ /* left) (v=1 to 2 by alt * h=0 -1 to -10 */ /* by alt) (s=center right left * v=0 1 to */ /* 2 by alt * h=0 -1 to -6 by alt * l= 1 */ /* to 2)) */ /* and so on. */ /* */ /* The PLACE= option, along with the LS= */ /* option can be used to search for an */ /* optimal placement list and an optimal */ /* line size. By default, the macro will */ /* create and recreate the plot until it */ /* avoids all collisions. The search is */ /* turned off when a PLACEMENT= option is */ /* detected in the plot request or plot */ /* options. */ /* */ /* If search is not specified with PLACE= */ /* or LS=, the specified value is fixed. */ /* If search is specified with the other */ /* option, only that option's value is */ /* incremented in the search. */ /* */ ls=compute search, /* Specifies how line sizes are generated. */ /* When the second word is "search", the */ /* macro searches for an optimal line */ /* size. See the PLACE= option for more */ /* information on searches. When the */ /* first word is "compute", the line size */ /* is computed from the iteration number */ /* so that the line sizes are: */ /* 65 80 100 125 150 175 200. */ /* Otherwise the first word is the first */ /* linesize and with each iteration the */ /* linesize is incremented by the LSINC= */ /* amount. Example: LS=65 search. */ /* */ maxiter=15, /* Maximum number of iterations. */ /* */ maxokpen=0, /* Maximum acceptable penalty sum. */ /* */ lsinc=15, /* Increment to line size in iterations */ /* when line size is not computed. */ /*-----------------------------------------*/ font=swiss, /* Default font. */ /* */ lsizes=1 1 1 1 1, /* Line sizes (thicknesses) for frame, */ /* ticks, vectors, circles, curves. */ /* */ tsize=1, /* Default text size. */ /* */ ticklen=1.5, /* Length of tick mark in horizontal */ /* cells. A negative value can be */ /* specified to indicate that only half */ /* ticks should be used, which means the */ /* ticks run to but not across the axes. */ /* */ tickaxes=LRTBFlb, /* Axes to draw tick marks. Default: */ /* TICKAXES=LRTBFlb, means major ticks on */ /* left (L), right (R), top (T), and */ /* bottom (B), and the full frame (F) is */ /* to be drawn, and potentially minor tick */ /* marks on the left (l) and bottom (b). */ /* Minor ticks on the right (r) and top */ /* (t) can also be requested. To just */ /* have major tick marks on the left and */ /* bottom axes, and no full frame, specify */ /* TICKAXES=LB. Order and spacing do not */ /* matter. HMINOR= and VMINOR= must also */ /* be specified to get minor ticks. */ /* */ extend=, /* This option is used to extend the X and */ /* Y axes beyond their default lengths. */ /* Specify four values, for left, right, */ /* top, and bottom. Missing values are */ /* set by the macro. If the word 'close' */ /* is specified somewhere in the string, */ /* then macro moves the axes in close to */ /* the extreme data values, and the */ /* computed values are added to the */ /* specified values (if any). Sample */ /* specifications: */ /* EXTEND=2 2, or EXTEND=3 3 -0.5 0.5. */ /* Specifying a positive value n extends */ /* the axis n positions in the indicated */ /* direction. Specifying a negative value */ /* shrinks the axis. The defaults for */ /* missing values are in the range -2 to */ /* 2, and are chosen in an attempt to add */ /* a little extra horizontal space and */ /* make equal the extra space next to each */ /* of the four extreme ticks. When there */ /* is enough space, the horizontal axis is */ /* slightly extended by default to */ /* decrease the chance of a label slightly */ /* extending outside the plot. PROC PLOT */ /* usually puts one or two more lines on */ /* the top of the plot than in the bottom. */ /* The macro tries to eliminate this */ /* discrepancy. This option does not add */ /* any tick marks; it just extends or */ /* shrinks the ends of the axis lines. So */ /* typically, only small values should be */ /* specified. Be careful with this option */ /* and a positive MAKEFIT= value. */ /* */ offset=0.25, /* Move symbols for coincident points */ /* OFFSET= spaces up/down and left/right. */ /* This helps with the resolution of */ /* coincident symbols. Specify a null */ /* value (OFFSET=,) to turn off */ /* offsetting. */ /* */ interpol=yes, /* Specifies the interpolation method. */ /* The default, unless ls or no is */ /* specified, is to interpolate symbol */ /* locations, starting with least squares */ /* but replacing them with tick-based */ /* estimates when they are available. */ /* ls - use the least-squares method only. */ /* Compute the mapping between data and */ /* positions using OLS linear regression. */ /* Usually, you should not specify */ /* INTERPOL=ls because slight inaccuracies */ /* may result, producing aesthetically */ /* unappealing plots. */ /* tick - use tick mark method. Compute */ /* the slope and intercept using tick */ /* marks and their values. Tick marks are */ /* read using the TICKFOR= format. */ /* no - do not interpolate. */ /* hlog - x-axis is on a log scale. */ /* vlog - y-axis is on a log scale. */ /* This option makes the symbols, vectors, */ /* and circles map to the location they */ /* would in a true graphical scatter plot, */ /* not the cell locations from PROC PLOT. */ /* This option has no effect on labels, */ /* frame, reference lines, titles, or */ /* ticks. INTERPOL=no plots tend to look */ /* nicer while INTERPOL=yes plots are */ /* slightly more accurate. Note that the */ /* strategy used to interpolate can be */ /* defeated in certain cases. If the */ /* horizontal axis tick values print */ /* vertically, specify INTERPOL=ls. The */ /* hlog and vlog values are specified in */ /* addition to the method. For example, */ /* INTERPOL=yes vlog hlog. */ /* */ tickfor=32., /* Tick format used by INTERPOL=tick. */ /* Change this if the tick values in the */ /* PROC PLOT output cannot be read with */ /* the default format, for example, */ /* specify TICKFOR=date7., with dates. */ /* */ inc=, /* HAXIS=BY INC and VAXIS=BY INC values. */ /* The specified increments apply to both */ /* axes. To individually control the */ /* increments, you must specify the PROC */ /* PLOT PLOT statement HAXIS= and VAXIS= */ /* options on the PLOTOPTS= option. When */ /* you are plotting variables that have */ /* very different scales, you may need to */ /* independently specify appropriate tick */ /* increments for both axes to get a */ /* reasonable plot. Here is an example: */ /* PLOTOPTS=haxis=by 20 vaxis=by 5000. */ /*-----------------------------------------*/ /* Note that the symbol and point label */ /* colors are set by the LABCOL= and */ /* SYMCOL= options. */ /* */ color=cyan, /* Default color, used when no other color */ /* is set. */ /* */ framecol=, /* Color of frame, defaults to COLOR=. */ /* */ titlecol=, /* Color of title, defaults to COLOR=. */ /* */ labelcol=, /* Color of variable labels, defaults to */ /* COLOR=. */ /* */ tickcol=, /* Color of ticks, defaults to COLOR=. */ /* */ curvecol=, /* Color of curve, defaults to COLOR=. */ /* */ cframe=, /* Color of background within the frame, */ /* analagous to cframe= option. */ /* By default, when CFRAME= is null, */ /* this option has no effect. */ /* */ monochro=, /* Overrides all other specified colors. */ /* This option is useful when you have */ /* specified colors and you want to */ /* temporarily override them to send the */ /* plot to a monochrome device. By */ /* default when MONOCHRO= is null, this */ /* option has no effect. Typical usage: */ /* MONOCHRO=black. */ /* */ bright=, /* Generate random label colors for */ /* BRITYPES= values. Normalize so */ /* mean(red,green,blue) equals BRIGHT=. */ /* The valid range is 5 <= BRIGHT <= 250. */ /* 128 is a good value. Small values will */ /* produce essentially black labels and */ /* large values will produce essentially */ /* white labels, and so should be avoided. */ /* null value - (BRIGHT=, the default) */ /* means no random labels. If you get a */ /* "color table full" error message, you */ /* need to specify larger values for the */ /* RGBROUND= option */ /* */ /* COLORS= specifies the default color */ /* list for SYMCOL= and LABCOL=, which are */ /* other color options described in a */ /* different section. */ /*-----------------------------------------*/ colors=blue red green cyan magenta orange gold lilac olive purple brown gray rose violet salmon yellow, /*-----------------------------------------*/ excolors=, /* Exclude observations from the annotate */ /* data set with colors in this list. For */ /* example with a black background, to */ /* exclude all observations that have a */ /* color set to "black" and those with a */ /* computed black value, for example from */ /* BRIGHT= or PAINT=, specify */ /* EXCOLORS=black CX000000. This is */ /* simply done for efficiency, to make the */ /* annotate data set smaller. */ /*-----------------------------------------*/ /* These next options are used to create */ /* label and symbol colors using some */ /* function of input data set variables. */ /* PAINT= gives you a simple and fairly */ /* general way to interpolate. RED=, */ /* GREEN=, and BLUE= are used together for */ /* many other types of interpolations, but */ /* are much harder to use. These options */ /* apply to RGBTYPES= observations. If */ /* RED=, GREEN=, and BLUE= are not */ /* flexible enough, for example if you */ /* need full statements, specify RED=128 */ /* (so later code will know you are */ /* computing colors) then insert the full */ /* statements you need to generate the */ /* colors using ADJUST1=. */ /* */ paint=, /* Used to interpolate between colors */ /* based on the values of a variable. The */ /* simplest specification is */ /* PAINT=variable. More generally, */ /* specify: PAINT=variable */ /* optional-color-list */ /* optional-data-value-list. */ /* The colors must be selected from: red, */ /* green, blue, yellow, magenta, cyan, */ /* black, white, orange, brown, gray, */ /* olive, pink, purple, violet. For other */ /* colors, specify the RGB color name */ /* (CXrrggbb where rr is the red value, gg */ /* is the green, and bb is blue, all three */ /* specified in hex). When a variable */ /* name Z is specified with no other */ /* arguments, the default is */ /* PAINT=z blue magenta red. */ /* PAINT=z red green 1 10, interpolates */ /* between red and green, based on the */ /* values of the variable z, where values */ /* of 1 or less map to red, values of 10 */ /* or more map to green, and values in */ /* between map to colors in between. */ /* PAINT=z red yellow green 1 5 10, */ /* interpolates between red at Z=1, yellow */ /* at Z=5, and green at Z=10. If the data */ /* value list is omitted it is computed */ /* from the data. */ /* */ rgbround=-240 1 1 1, /* Rounding factors used for the PAINT= */ /* variable and RGB values. The first */ /* value is used to round the PAINT=var */ /* variable. Specify a positive value to */ /* have the variable rounded to multiples */ /* of that value. Specify a negative */ /* value n to have a maximum of abs(n) */ /* colors. For the other three values, */ /* specify positive values. The last */ /* three are rounding factors for the red, */ /* green, and blue component of the color. */ /* If more than 256 colors are generated, */ /* you will get the error that a color was */ /* not added because the color table is */ /* full. By default, when a value is */ /* missing, there is no rounding. */ /* Rounding the PAINT= variable is useful */ /* with contour plots. */ /* */ red=, /* Specify for RED=, GREEN=, and BLUE= */ green=, /* arithmetic expressions that produce */ blue=, /* integers in the range 0 to 255. Colors */ /* will be created as follows: */ /* __color = */ /* 'CX' || put(%if &red ne %then */ /* round(&red,__roured); %else 128; */ /* ,hex2.) || put(%if &green ne %then */ /* round(&green,__rougre); %else 128;, */ /* hex2.) || put(%if &blue ne %then */ /* round(&blue,__roublu); %else 128; */ /* ,hex2.); */ /* Where the __rou variables are extracted */ /* from RGBROUND=. Example: */ /* RED = min(100 + (z - 10) * 3, 255), */ /* BLUE=50, GREEN=50. */ /* Then all labels are various shades of */ /* red, depending on the value of z. */ /* Be aware that light colors (small red- */ /* green-blue values) do not show up well */ /* on white backgrounds and dark colors do */ /* not show up well on dark backgrounds, */ /* so typically, you will not want to use */ /* the full range of possible */ /* red-green-blue values. The computed */ /* value was minned with 255 so that if a */ /* larger value is computed, it will not */ /* go over 255 and effectively become */ /* mod(red,255). */ /*-----------------------------------------*/ /* Use these options with contour plots. */ /* For example if the grid for a contour */ /* plot was generated as follows */ /* */ /* do x = -4 to 4 by 0.1; */ /* do y = -2 to 2 by 0.1; */ /* */ /* then specify HNOBS=81, VNOBS=41. By */ /* default, the square root of the number */ /* of contour type observations is used */ /* for both (which assumes a square grid). */ /* */ hnobs=, /* Number of horizontal observations in */ /* the grid for contour plots. */ /* */ vnobs=, /* Number of vertical observations in the */ /* grid for contour plots. */ /*-----------------------------------------*/ /* You can use the adjust options to add */ /* full SAS data step statements to */ /* strategic places in the macro, such as */ /* the PROC PLOT step, the end of the */ /* preprocessing and last full data steps */ /* to do minor adjustments before the */ /* final plot is produced. */ /* */ adjust1=, /* The following variables are created in */ /* the preprocessing data set: */ /* __lsize - label size */ /* __lfont - label font */ /* __lcolor - label color */ /* __ssize - symbol size */ /* __sfont - symbol font */ /* __scolor - symbol color */ /* __stype - symbol type */ /* __symbol - symbol value */ /* __otype - observation type */ /* */ /* Use ADJUST1= to adjust these variables */ /* in the preprocessing data set from */ /* their usual values. You must specify */ /* complete statements with semicolons. */ /* Examples: */ /* ADJUST1=%str(__lsize = mysize; */ /* __lcolor = mycolor;) */ /* */ /* adjust1=%str(if z > 20 then do; */ /* __scolor = 'green'; __lcolor = 'green'; */ /* end;)) */ /* */ adjust2=, /* This option can be used to include */ /* statements with PROC PLOT such as */ /* FORMAT statements. Just specify the */ /* full statement. */ /* */ /* Use ADJUST3= and ADJUST4= to adjust the */ /* final Annotate data set. For example, */ /* in swiss fonts asterisks are not */ /* vertically centered when printed, so */ /* ADJUST3= converts to use the SYMBOL */ /* function. */ /* */ adjust3=%str(if text = '*' and function = 'LABEL' then do; style = ' '; text = 'star'; function = 'SYMBOL'; end;), /* */ adjust4=, /* ADJUST4 can add additional adjustments. */ /* If you add new variables to the data */ /* set, you must also include a KEEP */ /* statement. Here is an example of using */ /* ADJUST4= to vertically print the y-axis */ /* label, like it would be in PROC PLOT. */ /* adjust4=%str(if angle = 90 then do; */ /* angle = 270; */ /* rotate = 90; */ /* keep rotate; */ /* end;) */ /* This example changes the size of title */ /* lines. adjust4=%str(if index(comment, */ /* 'title') then size = 2;) */ /* */ adjust5=, /* Adds extra statements to the final */ /* data step that is used only for */ /* DATATYPE=function. For example, to */ /* periodically mark the function with */ /* plusses, specify: ADJUST5=%str( */ /* if mod(_n_,30) = 0 then do; size=0.25; */ /* function = 'LABEL'; text = '+'; output; */ /* end;) */ /*-----------------------------------------*/ antiidea=, /* Eliminate PREFMAP anti-ideal points. */ /* */ /* null value - (ANTIIDEA=, the default) - */ /* do nothing. */ /* */ /* 1 - reverse in obs whose _TYPE_ */ /* contains 'POINT' when _ISSQ_ > 0. */ /* Specify ANTIIDEA=1 with DATATYPE=ideal */ /* when large data values are positive */ /* or ideal. */ /* */ /* -1 - reverse in obs whose _TYPE_ */ /* contains 'POINT' when _ISSQ_ < 0. */ /* Specify ANTIIDEA=-1 with DATATYPE=ideal */ /* when small data values are positive */ /* or ideal. */ /* */ radii=%str(1, 2), /* Radii of circles (data step do list). */ /* The unit corresponds to the horizontal */ /* axis variable. The RADII= option can */ /* also specify a variable in the input */ /* data set when radii vary for each */ /* point. */ /* */ cirsegs=.1, /* A circle smoothness parameter used in */ /* determining the number of line segments */ /* in each circle. Smaller values create */ /* smoother circles. The CIRSEGS= value */ /* is approximately related to the length */ /* of the line segments that compose the */ /* circle. */ /* */ vechead=0.2 0.05, /* How to draw vector heads. For example, */ /* VECHEAD=0.2 0.05, specifies draw a head */ /* consisting of two hypotenuses from */ /* triangles with sides 0.2 units long */ /* along the vector and 0.05 units on the */ /* side perpendicular to the vector. */ /* */ outward=, /* String for the PLOT statement OUTWARD= */ /* option. Normally, this option's value */ /* is constructed from the symbol that */ /* holds the place for vectors. Specify */ /* OUTWARD=none if you want to not have */ /* OUTWARD= specified for vectors: */ /*-----------------------------------------*/ regopts=, /* TRANSREG options for curve fitting. */ /* These are specified after the slash in */ /* the functional specification for the */ /* independent variable. Example: */ /* REGOPTS=nkn=10 evenly. */ /* */ nknots=, /* TRANSREG number of knots option. */ /* */ regprint=noprint, /* PROC TRANSREG PROC statement options, */ /* typically printing options such as: */ /* NOPRINT - no regression printed output, */ /* SS2 - regression results, */ /* SHORT - suppress iteration histories. */ /* To see the regression table, specify: */ /* REGPRINT=SS2 SHORT. */ /* */ regfun=spline, /* Function for curve fitting. Possible */ /* values include LINEAR, SPLINE, MSPLINE, */ /* MONOTONE. */ /* */ cursegs=200, /* Number of segments in a curve. */ /*-----------------------------------------*/ debug=time, /* vars - print macro options and macro */ /* variables for debugging. */ /* dprint - print intermediate data sets. */ /* notes - do not specify OPTIONS NONOTES */ /* during most of the macro. */ /* time - prints total macro run time. */ /* mprint - run with OPTIONS MPRINT. */ /* Concatenate names for more than one */ /* type of debugging. Example: */ /* DEBUG=vars dprint notes time mprint. */ /*-----------------------------------------*/ /* Normally, you should not specify any */ /* options from this section. The macro */ /* has or chooses suitable defaults. */ /* */ vtoh=2, /* PROC PLOT VTOH= option. Do not specify */ /* values much different than 2, */ /* especially by default when you are */ /* using proportional fonts. There is no */ /* one-to-one correspondence between */ /* characters and cells and character */ /* widths vary, but characters tend to be */ /* approximately half as wide as they are */ /* high. When you specify VTOH= values */ /* larger than 2, near-by labels may */ /* overlap, even when they do not collide */ /* in the printer plot. A null value can */ /* be specified, VTOH=, when you want the */ /* macro to just fill the window, like a */ /* typical GPLOT. */ /* */ /* Smaller values give you more lines and */ /* smaller labels. VTOH=1.75 is a good */ /* alternative to VTOH=2 when you need */ /* more lines to avoid collisions. */ /* VTOH=1.75 means 7 columns for each 4 */ /* rows between ticks (7 / 4 = 1.75). */ /* VTOH=2 means the plot will have 8 */ /* columns for each 4 rows between ticks. */ /* Note that PROC PLOT sometimes takes */ /* this value as a "hint," not a */ /* specification so the actual value may */ /* be slightly different, particularly */ /* when a value other than 2.0 is */ /* specified. This is generally not a */ /* problem; the macro adjusts accordingly. */ /* */ makefit=-0.95, /* Proportion of graphics window to use. */ /* When the MAKEFIT= is negative, the */ /* absolute value will be used, and the */ /* final value may be changed if the macro */ /* thinks part of the plot may extend over */ /* the edge. When a positive value is */ /* specified, it will not be changed by */ /* the macro. When nonnull, the macro */ /* uses GASK to determine the minimum and */ /* maximum graphics window sizes and makes */ /* sure the plot can fit in them. The */ /* macro uses GOPPRINT= or GOPPLOT= to */ /* determine the device. */ /* */ unit=in, /* HSIZE=, VSIZE=, unit: in or cm. */ /* */ /* If you specify just the HSIZE= or the */ /* VSIZE= but not both, you can control */ /* the absolute size of one axis and the */ /* size of the other axis will be scaled */ /* accordingly. */ /* */ hsize=, /* Horizontal graphics area size in UNIT= */ /* units. The default is the maximum size */ /* for the device. By default when */ /* OPTIONS=nocenter is not specified, */ /* HSIZE= affects the size of the plot but */ /* not the HSIZE= GOPTION. When */ /* OPTIONS=nocenter is specified, HSIZE= */ /* affects both the plot size and the */ /* HSIZE= GOPTION. */ /* */ vsize=, /* Vertical graphics area size in UNIT= */ /* units. The default is the maximum size */ /* for the device. By default when */ /* OPTIONS=nocenter is not specified, */ /* VSIZE= affects the size of the plot but */ /* not the VSIZE= GOPTION. When */ /* OPTIONS=nocenter is specified, VSIZE= */ /* affects both the plot size and the */ /* VSIZE= GOPTION. */ /* */ xmax=, /* Maximum horizontal size of the graphics */ /* area. */ /* */ ymax=, /* Maximum vertical size of the graphics */ /* area. */ /* */ hpos=, /* Horizontal positions in graphics area. */ /* */ vpos=, /* Vertical positions in graphics area. */ /* */ ps=, /* Page size. */ /* */ ); /*-----------------------------------------*/ *=========================initial macro stuff=========================; %if not %index(%nrbquote(&debug),notes) %then %str(options nonotes;); %let abort = 0; options noserror; %if %nrquote(&&plotitop) eq %nrstr(&)plotitop %then %let plotitop = ; options serror; *------store starting time, initialize a few variables-------; data _null_; length name $ 8 debug value $ 500 glob $ 32767; __time = time(); call symput('start',compress(put(__time,best15.))); *------override parameters?-------; glob = left(symget('plotitop')); if glob ne ' ' then put 'Overridden Parameters:'; do while(glob ne ' '); i = index(glob, '='); name = substr(glob, 1, i - 1); glob = left(substr(glob, i + 1)); i = index(glob, ','); if i = 0 then i = length(glob) + 1; value = substr(glob, 1, i - 1); glob = left(substr(glob, i + 1)); put name +(-1) '=' value; call symput(name, trim(value)); end; *------debugging flags-------; __debug = symget('debug'); call symput('dbyes' ,compress(put(index(__debug,'vars') ,3.))); call symput('dbprint' ,compress(put(index(__debug,'dprint'),3.))); call symput('dbtime' ,compress(put(index(__debug,'time') ,3.))); call symput('dbmprint',compress(put(index(__debug,'mprint'),3.))); if _error_ then call symput('abort','1'); run; %if &syserr > 4 %then %let abort = 1; %if &abort %then %goto endit; %if &dbmprint %then %str(options mprint;); %let red = %nrbquote(&red); %let green = %nrbquote(&green); %let blue = %nrbquote(&blue); %let gout = %nrbquote(&gout); %let gname = %nrbquote(&gname); %let gdesc = %nrbquote(&gdesc); %if &dbyes %then %put _local_; data _null_; *------mention var names for ordinary SAS syntax-------; retain &plotvars &labelvar &symvar &typevar __junk 0; array __1 &plotvars &labelvar &symvar &typevar __junk; *------store current linesize and pagesize to restore later------; length __ls __ps __var $ 8 ; __ls = getoption('linesize'); __ps = getoption('pagesize'); __lab = getoption('label'); __var = getoption('validvarname'); __page = input(__ps, 8.); if __page < 200 then __logps = __page + 1; else __logps = 200; if __logps < 20 then __logps = 20; call symput('v7' , put(index(__var, '6') eq 0, 1.)); call symput('restorla', compress(__lab)); call symput('restorls', compress(__ls)); call symput('restorps', compress(__ps)); call symput('logps' , compress(put(__logps, best8.))); if _error_ then call symput('abort','1'); run; %if &syserr > 4 %then %let abort = 1; %if &abort %then %goto endit; options label; *------start parameter checking, initialization------; %if %length(%nrbquote(&types)) > 500 or %length(%nrbquote(&symbols)) > 500 or %length(%nrbquote(&symcol)) > 500 or %length(%nrbquote(&symtype)) > 500 or %length(%nrbquote(&symsize)) > 500 or %length(%nrbquote(&symfont)) > 500 or %length(%nrbquote(&labsize)) > 500 or %length(%nrbquote(&labcol)) > 500 or %length(%nrbquote(&plotopts)) > 500 or %length(%nrbquote(&labfont)) > 500 %then %do; %put ERROR: A list is more than 500 characters.; %plotdump(TYPES SYMBOLS SYMCOL SYMTYPE SYMSIZE SYMFONT LABSIZE LABCOL PLOTOPTS LABFONT) %let abort = 1; %goto endit; %end; *------initialization------; data _null_; file log ps=&logps; length data f1-f10 $ 72 name $ 35 opts datatype plotvars $ 500; ok = 1; datatype = upcase(symget('datatype')); *------initialize some macro variables------; call symput('singular','1e-8'); /* essentially zero */ call symput('allblank','1'); /* all labels blank */ call symput('botblank','0'); /* symbol and lab blank*/ call symput('nlines' ,'0'); /* last line of plot */ call symput('symnumer','0'); /* character symvar */ call symput('typenum' ,'0'); /* character typevar */ call symput('search' ,' '); /* ls, place search */ call symput('actualls','-1'); /* actual line size */ call symput('symdummy','#'); /* vector, curve sym */ call symput('paintcol',' '); /* paint color list */ call symput('paintmin','.'); /* paint variable min */ call symput('paintmax','.'); /* paint variable max */ call symput('paintnum','0'); /* num of paint colors */ call symput('ncontour','0'); /* num of contour obs */ call symput('hcontour','0'); /* horizo contour size */ call symput('vcontour','0'); /* vertic contour size */ call symput('hcondir ','0'); /* horizo cont grid dir*/ call symput('vcondir ','0'); /* vertic cont grid dir*/ call symput('looklist','0'); /* look for listing */ call symput('sizsquar','1'); /* size square symbol */ call symput('device' ,symget('sysdevic')); /* current device */ call symput('datatype',trim(datatype)); /* upcased data type */ call symput('listtitl','*** Wrapped Listing of Point Locations ***'); *------set vector scale factor------; name = ' '; do i = 5 to 2 by -1; if name = ' ' then name = scan(datatype,i,' '); end; if name = ' ' or nmiss(input(name,?? 32.)) then name = '1'; call symput('biplot',trim(name)); *------make sure there are input data------; data = left(upcase(symget('data'))); if data in (' ' '_LAST_') then do; data = symget('syslast'); call symput('data',trim(data)); end; if data = '_NULL_' then do; put 'ERROR: No input data set.'; ok = 0; end; *------some options cannot have null values------; if symget('filepref') = ' ' then call symput('filepref','sasplot'); if symget('out') = ' ' then call symput('out' ,'anno'); if symget('tempdat1') = ' ' then call symput('tempdat1','tempdat1'); if symget('tempdat2') = ' ' then call symput('tempdat2','tempdat2'); if symget('tempdat3') = ' ' then call symput('tempdat3','tempdat3'); if symget('tempdat4') = ' ' then call symput('tempdat4','tempdat4'); if symget('tempdat5') = ' ' then call symput('tempdat5','tempdat5'); if symget('regdat') = ' ' then call symput('regdat' ,'regdat'); if symget('preproc') = ' ' then call symput('preproc' ,'preproc'); if symget('extraobs') = ' ' then call symput('extraobs','extraobs'); if symget('radii') = ' ' then call symput('radii' ,'1, 2'); if symget('cirsegs') = ' ' then call symput('cirsegs' ,'.1'); if symget('cursegs') = ' ' then call symput('cursegs' ,'200'); if symget('maxiter') = ' ' then call symput('maxiter' ,'15'); if symget('lsinc') = ' ' then call symput('lsinc' ,'15'); if symget('place') = ' ' then call symput('place' ,'2 search'); if symget('symlen') = ' ' then call symput('symlen' ,'1'); if symget('ls') = ' ' then call symput('ls','compute search'); if symget('maxokpen') = ' ' then call symput('maxokpen','0'); if symget('ticklen') = ' ' then call symput('ticklen' ,'1.5'); if symget('tickfor') = ' ' then call symput('tickfor' ,'32.'); if symget('hnobs') = ' ' then call symput('hnobs' ,'0'); if symget('vnobs') = ' ' then call symput('vnobs' ,'0'); *------is radii a variable name?------; name = upcase(substr(left(symget('radii')),1,1)); call symput('radname', put('A' <= name <= 'Z' or name = '_' or name = '"' or name = "'", 1.)); *------always use a formchar------; call symput('procopts', trim(symget('procopts')) || " formchar='|----|+|---'"); *------was TYPES= specified?------; call symput('typespec', put(symget('types') ne ' ',1.)); *------set default plotvars------; plotvars = symget('plotvars'); if plotvars = ' ' then do; if index(datatype,'MDS') or index(datatype,'MCA') or index(datatype,'ROW') or index(datatype,'COLUMN') or index(datatype,'CORRESP') then plotvars = 'Dim2 Dim1'; else if index(datatype,'MDPREF') or index(datatype,'VECTOR') or index(datatype,'IDEAL') then plotvars = 'Prin2 Prin1'; call symput('plotvars',trim(plotvars)); end; *------check for conflicting data set names------; f1 = left(upcase(symget('data'))); f2 = left(upcase(symget('out'))); f3 = left(upcase(symget('tempdat1'))); f4 = left(upcase(symget('tempdat2'))); f5 = left(upcase(symget('tempdat3'))); f6 = left(upcase(symget('tempdat4'))); f7 = left(upcase(symget('tempdat5'))); f8 = left(upcase(symget('preproc'))); f9 = left(upcase(symget('extraobs'))); f10 = left(upcase(symget('regdat'))); opts = 'DATA OUT TEMPDAT1 TEMPDAT2 TEMPDAT3 TEMPDAT4 TEMPDAT5 ' || 'PREPROC EXTRAOBS REGDAT'; array f[10] f1-f10; do i = 1 to 10; if f[i] =: 'WORK.' then f[i] = substr(f[i],6); __name = f[i]; link norm; f[i] = __name; do j = 1 to (i - 1); if f[i] = f[j] then do; oi = scan(opts,i,' '); oj = scan(opts,j,' '); put 'ERROR: Data sets ' oi +(-1) '=' f[i] 'and ' oj +(-1) '=' f[j] 'must be different.'; if oj = 'DATA' then put 'WARNING: You may have not specified DATA=.'; ok = 0; end; end; end; if not ok or _error_ then call symput('abort','1'); return; norm: * Normalize name, upper case, strip n-literals. * Input: __name * Output: __name (updated) * Sample usage: * __name = '"a b"n'; * link norm; * Creates: __name = 'A B'; __name = upcase(__name); if substr(__name,1,1) in ("'", '"') then __name = substr(__name, 2, length(__name) - 3); drop __name; return; run; %if &syserr > 4 %then %let abort = 1; %if &abort %then %goto endit; *------store input data set variable names------; proc contents data=&data noprint out=&tempdat1; run; %if &syserr > 4 %then %do; %let abort = 1; %goto endit; %end; proc sort data=&tempdat1(keep=varnum type name); by varnum; run; %if &syserr > 4 %then %do; %let abort = 1; %goto endit; %end; %if &dbprint %then %do; proc print data=&tempdat1; title3 "&tempdat1 - temporary data set, proc contents results"; run; title3; %end; *------look for the type variable, plot variables------; data _null_; file log ps=&logps; length tvname vplotvar hplotvar __name $ 35 upname vnormvar hnormvar $ 32 __list plotvars $ 500 __c $ 1; retain tvname vplotvar hplotvar hnormvar vnormvar ' ' ok 1 vfound hfound 0; if _n_ = 1 then do; f = (index(symget('datatype'), 'FUNCTION') or index(upcase(symget('symtype')), 'FUNCTION')); call symput('functype', put(f, 1.)); __name = symget('typevar'); link norm; tvname = __name; __list = symget('plotvars'); __n = 1; plotvars = __list; link namescan; vplotvar = __name; link norm; vnormvar = __name; link namescan; hplotvar = __name; link norm; hnormvar = __name; __list = symget('paint'); link namescan; call symput('paintvar',trim(__name)); call symput('paint' ,trim(__list)); end; set &tempdat1 end=eof; upname = upcase(name); if upname = tvname or (tvname = ' ' and upname = '_TYPE_') then do; if tvname = ' ' then call symput('typevar','_type_'); if (type = 1) then call symput('typenum','1'); end; *------plotting variables must be numeric------; if (upname = hnormvar or upname = vnormvar) and type = 2 then do; put 'ERROR: PLOTVARS=' plotvars 'must be numeric.'; ok = 0; end; *------set default plotting variables if not set yet------; if type = 1 then do; if hplotvar = ' ' then do; hplotvar = name; hnormvar = upname; end; else if vplotvar = ' ' then do; vplotvar = name; vnormvar = upname; end; end; *------make sure axis variables are found------; if upname = hnormvar then do; hfound = 1; __name = name; link nliteral; hplotvar = __name; end; if upname = vnormvar then do; vfound = 1; __name = name; link nliteral; vplotvar = __name; end; *------at end, output results------; if eof then do; call symput('vplotvar',trim(vplotvar)); call symput('hplotvar',trim(hplotvar)); __list = trim(hplotvar) || ' ' || trim(vplotvar); call symput('plotvars',trim(hplotvar) || ' ' || trim(vplotvar)); name = 'A' || vplotvar; call symput('appvar1',trim(name)); if vplotvar = ' ' or hplotvar = ' ' then do; put 'ERROR: Not enough variables to plot.'; ok = 0; end; if not hfound then do; put 'ERROR: Horizontal axis variable ' hplotvar 'not found.'; ok = 0; end; if not vfound then do; put 'ERROR: Vertical axis variable ' vplotvar 'not found.'; ok = 0; end; if hnormvar = '_TYPE_' or vnormvar = '_TYPE_' then put 'WARNING: _TYPE_ is one of the axis variables.'; end; if not ok or _error_ then call symput('abort','1'); return; norm: * Normalize name, upper case, strip n-literals. * Input: __name * Output: __name (updated) * Sample usage: * __name = '"a b"n'; * link norm; * Creates: __name = 'A B'; __name = upcase(__name); if substr(__name,1,1) in ("'", '"') then __name = substr(__name, 2, length(__name) - 3); drop __name; return; nliteral: * Puts n-literal on name if necessary. * Input: __name * Output: __name (updated) * Sample usage: * __name = 'a b'; * link nliteral; * Creates: __name = "'a b'n"; __v7 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789'; if (not (substr(__name, 1, 1) in ("'", '"'))) and (index(__name,' ') < length(__name) or compress(upcase(__name), __v7) ne ' ') then __name = "'" || trim(__name) || "'n"; drop __name __v7; return; namescan: * Returns nth name from a list. * Input: __list, __n * Output: __list, (trashed) * __name * Sample usage: * __list = 'a "b"n "C d"N d'; * __n = 2; * link namescan; * Creates: __name = '"b"n'; __list = left(__list); do __i = 1 to __n; __c = substr(__list, 1, 1); if trim(__c) in ("'", '"') then __e = index(substr(__list, 2), trim(__c)) + 2; else __e = index(__list, ' ') - 1; if __e < 1 then __e = length(__list); __name = substr(__list, 1, __e); __list = left(substr(__list, __e + 2)); end; drop __list __n __i __name __c __e; return; run; %if &syserr > 4 %then %let abort = 1; %if &abort %then %goto endit; *------generate TYPES= list from data?------; %if (&functype or %nrbquote(&datatype) = ) and (not &typespec) and &typevar ne %then %do; proc freq data=&data noprint order=data; tables &typevar / out=&tempdat2; run; %if &syserr > 4 %then %do; %let abort = 1; %goto endit; %end; %if &dbprint %then %do; proc print data=&tempdat2; title3 "&tempdat2 - temporary data set - proc freq results"; run; title3; %end; data _null_; set &tempdat2 end=eof; length __list $ 500; retain __list; __list = trim(__list) || ' ' || compress( %if &typenum %then put(&typevar,best12.); %else &typevar;); if eof then call symput('types',trim(left(__list))); if _error_ then call symput('abort','1'); run; %if &syserr > 4 %then %let abort = 1; %if &abort %then %goto endit; %end; *------preliminary preprocessing that changes the data------; data &preproc; set &data; if n(&vplotvar,&hplotvar) = 2; *------eliminate anti-ideal points------; %if &antiidea ne %then %do; if index(&typevar,'POINT') then do; if n(_issq_) and ((&antiidea > 0 and _issq_ > 0) or (&antiidea <= 0 and _issq_ < 0)) then do; &vplotvar = -(&vplotvar); %if &hplotvar ne &vplotvar %then %do; &hplotvar = -(&hplotvar); %end; end; end; %end; if _error_ then call symput('abort','1'); run; %if &syserr > 4 %then %let abort = 1; %if &abort %then %goto endit; *------more initializations------; data _null_; file log ps=&logps; length name symvar $ 35 color framecol titlecol labelcol tickcol curvecol monochro font size name1-name2 tsize $ 12 anele anele2 $ 16 word $ 24 list list2 datatype types colors symbols symcol symtype symfont symsize labcol labfont labsize britypes rgbtypes exttypes $ 500; *------set default symbol variable------; symvar = symget('symvar'); *------list of valid DATATYPE= values------; array dts[15] corresp mca row column mdpref mdpref2 vector ideal mds curve curve2 function contour square symbol; *------22 lists, 10 lists of ntypes elements, 9 single-element lists 3 longer lists------; listn = 22; listm = 10; listo = 19; array vars[22] $ types colors symbols symcol symtype symfont symsize labcol labfont labsize /* <= listm */ color framecol titlecol labelcol tickcol curvecol monochro font cframe /* <= list0 */ britypes rgbtypes exttypes; ok = 1; *------check method------; name = symget('method'); word = lowcase(compress(name,' 2')); if not (word in ('gplot' 'print' 'plot' 'none')) then do; put 'ERROR: METHOD=' name 'is not valid.'; ok = 0; end; else do; call symput('method',trim(word)); if word = 'plot' then call symput('looklist', '1'); end; *------convert binary options ------; list = lowcase(symget('options')); call symput('border' ,put(index(list,'border') > 0,1.)); call symput('expand' ,put(index(list,'expand') > 0,1.)); call symput('closebord',put(index(list,'close') > 0,1.)); call symput('center' ,put(index(list,'nocenter') = 0,1.)); call symput('clip' ,put(index(list,'noclip') = 0,1.)); call symput('delete' ,put(index(list,'nodelete') = 0,1.)); call symput('linetext' ,put(index(list,'textline') = 0,1.)); call symput('squarplt' ,put(index(list,'square') > 0,1.)); print = (index(list,'noprint') = 0); call symput('legend' ,put(index(list,'nolegend') = 0 && print,1.)); call symput('history',put(index(list,'nohistory') = 0 && print,1.)); call symput('code' ,put(index(list,'nocode') = 0 && print,1.)); *------make sure all options are recognized------; list2 = 'nocenter noclip textline square border expand close ' || 'nolegend nohistory nocode noprint nodelete'; do i = 1 to 12; word = scan(list2,i); j = index(list,trim(word)); if j then substr(list,j,length(word)) = ' '; end; if list ne ' ' then do; put 'ERROR: The following options are not recognized: ' list +(-1) '.'; ok = 0; end; *------check INTERPOL=------; list = lowcase(symget('interpol')); call symput('intrtick',put((index(list,'tick') or not (index(list,'ls') or index(list,'no'))),1.)); call symput('intrls' ,put((index(list,'ls') or not index(list,'no')),1.)); call symput('hlogscal',put((index(list,'hlog') > 0),1.)); call symput('vlogscal',put((index(list,'vlog') > 0),1.)); *------parse the DATATYPE= option------; datatype = symget('datatype'); list = datatype; do i = 1 to 15; call vname(dts[i],name); j = index(datatype,trim(upcase(name))); if j then substr(list,j,length(name)) = ' '; dts[i] = (j ne 0); call symput(name,compress(put(dts[i],1.))); end; list = compress(list,'0123456789.e+-'); if list ne ' ' then do; put 'ERROR: Invalid DATATYPE=' datatype +(-1) '.'; ok = 0; end; *------get the lists that must be quoted------; do i = 1 to listn; call vname(vars[i],name); vars[i] = symget(name); end; symtype = lowcase(symtype); britypes = lowcase(britypes); rgbtypes = lowcase(rgbtypes); exttypes = lowcase(exttypes); *-----make sure these are set------; if font = ' ' then font = 'swiss'; tsize = symget('tsize'); if tsize = ' ' then do; tsize = '1'; call symput('tsize','1'); end; *------process DATATYPE= option------; if datatype ne ' ' then do; if contour then do; symbols = trim(symbols) || " ''"; symtype = trim(symtype) || ' contour'; symsize = trim(symsize) || ' 1'; symfont = trim(symfont) || ' solid'; labsize = trim(labsize) || ' ' || tsize; labfont = trim(labfont) || ' ' || font; rgbtypes = trim(rgbtypes) || ' contour'; exttypes = trim(exttypes) || ' contour'; end; if square then do; symbols = trim(symbols) || ' U'; symtype = trim(symtype) || ' square'; symsize = trim(symsize) || ' 1'; symfont = trim(symfont) || ' marker'; labsize = trim(labsize) || ' ' || tsize; labfont = trim(labfont) || ' ' || font; rgbtypes = trim(rgbtypes) || ' square'; exttypes = trim(exttypes) || ' square'; end; if function then do; symbols = trim(symbols) || " ''"; symtype = trim(symtype) || ' function'; symsize = trim(symsize) || ' 1'; symfont = trim(symfont) || ' '; labsize = trim(labsize) || ' ' || tsize; labfont = trim(labfont) || ' ' || font; exttypes = trim(exttypes) || ' function'; name = symget('labelvar'); if name = ' ' then call symput('labelvar','_blank_'); if symvar = ' ' then put 'WARNING: Null symbol variable ' 'specified with ' 'DATATYPE=function.'; end; if mdpref or vector or ideal then types = trim(types) || ' SCORE'; if mdpref or vector or ideal or symbol then do; symbols = trim(symbols) || ' *'; symtype = trim(symtype) || ' symbol'; symsize = trim(symsize) || ' ' || tsize; symfont = trim(symfont) || ' ' || font; labsize = trim(labsize) || ' ' || tsize; labfont = trim(labfont) || ' ' || font; end; if corresp or row or mca or column then do; types = trim(types) || ' VAR OBS SUPVAR SUPOBS'; if row then do; symtype = trim(symtype) || ' vector symbol symbol symbol'; symbols = trim(symbols) || " '' * * *"; end; else if column then do; symtype = trim(symtype) || ' symbol vector symbol symbol'; symbols = trim(symbols) || " * '' * *"; end; else do; symtype = trim(symtype) || ' symbol symbol symbol symbol'; symbols = trim(symbols) || ' * * * *'; end; symsize = trim(symsize) || repeat(' ' || trim(tsize),3); symfont = trim(symfont) || repeat(' ' || trim(font) ,3); labsize = trim(labsize) || repeat(' ' || trim(tsize),3); labfont = trim(labfont) || repeat(' ' || trim(font) ,3); end; if mdpref then do; types = trim(types) || ' CORR'; symbols = trim(symbols) || " ''"; symtype = trim(symtype) || ' vector'; symsize = trim(symsize) || ' ' || tsize; symfont = trim(symfont) || ' ' || trim(font) || 'i'; labfont = trim(labfont) || ' ' || trim(font) || 'i'; if mdpref2 then labsize = trim(labsize) || ' ' || compress(put(input(tsize, ?? 32.) * 0.75, best8.)); else labsize = trim(labsize) || ' 0'; end; size = compress(put(input(tsize,?? 32.) * 1.5, best8.)); if vector then do; types = trim(types) || ' MCOEFFI'; symbols = trim(symbols) || " ''"; symtype = trim(symtype) || ' vector'; symsize = trim(symsize) || ' ' || tsize; symfont = trim(symfont) || ' ' || trim(font) || 'i'; labsize = trim(labsize) || ' ' || size; labfont = trim(labfont) || ' ' || trim(font) || 'i'; end; if ideal then do; types = trim(types) || ' MPOINT'; symbols = trim(symbols) || ' +'; symtype = trim(symtype) || ' circle'; symsize = trim(symsize) || ' ' || tsize; symfont = trim(symfont) || ' ' || trim(font) || 'i'; labsize = trim(labsize) || ' ' || size; labfont = trim(labfont) || ' ' || trim(font) || 'i'; end; if mds then do; types = trim(types) || ' CONFIG'; symbols = trim(symbols) || ' *'; symtype = trim(symtype) || ' symbol'; symsize = trim(symsize) || ' ' || tsize; symfont = trim(symfont) || ' ' || font; labsize = trim(labsize) || ' ' || tsize; labfont = trim(labfont) || ' ' || font; end; if (mds or corresp or mca or row or column or mdpref or mdpref2 or vector or ideal) and symget('label') = ' ' then call symput('label','typical'); end; *------ in case these were only specified in the symtype------; if index(symtype, 'contour' ) then call symput('contour' , '1'); if index(symtype, 'square' ) then call symput('square' , '1'); *------set colors, other defaults------; if color = ' ' then color = 'cyan'; if colors = ' ' then colors = color; if framecol = ' ' then framecol = color; if titlecol = ' ' then titlecol = color; if labelcol = ' ' then labelcol = color; if tickcol = ' ' then tickcol = color; if curvecol = ' ' then curvecol = color; if symtype = ' ' then symtype = 'symbol'; if symsize = ' ' then symsize = tsize; if symfont = ' ' then symfont = font; if labsize = ' ' then labsize = tsize; if labfont = ' ' then labfont = font; if exttypes = ' ' then exttypes = "''"; if rgbtypes = ' ' then rgbtypes = "''"; labcol = trim(labcol) || ' ' || colors; symcol = trim(symcol) || ' ' || colors; *------default symbols when unspecified------; if index(symtype, 'symbol') and symvar eq '_symbol_' and symbols = ' ' then do; word = scan(symtype, 1, ' '); do i = 1 to 500 while(word ne ' '); if index(word, 'symbol') then symbols = trim(symbols) || ' *'; else symbols = trim(symbols) || " ''"; word = scan(symtype, i + 1, ' '); end; end; if symbols = ' ' then symbols = "''"; *------count the number of types------; if types = ' ' then types = "''"; do until(word eq ' '); ntypes + 1; word = scan(types, ntypes + 1, ' '); end; holdntyp = ntypes; *------output number of observation types------; call symput('ntypes',compress(put(ntypes,3.))); *------output lists, make sure they are quoted------; do i = 1 to listn; if i > listm then ntypes = 1; if i > listo then ntypes = 200; link qlist; end; ntypes = holdntyp; *------output sizes for squares------; do i = 1 to ntypes; word = scan(symtype, i, ' '); if index(word, 'square') then call symput('sizsquar', compress(scan(symsize, i, ' '), " '"||'"')); end; *------check for constant symvar with vectors------; symcon = (symvar = ' ' or (compress(symvar,"'"||'"') ne symvar)); call symput('symcon',put(symcon,1.)); /* constant symbol? */ if symcon and index(symtype,'vector') then do; put 'ERROR: Constant SYMVAR= is not allowed with vectors.'; ok = 0; end; *------parse RGBROUND= option------; list = symget('rgbround'); list2 = ' '; do i = 1 to 4; name = scan(list, i, ' '); num = input(name, ?? 32.); if nmiss(num) then num = .; if i > 1 and num <= 0 then num = 1; list2 = trim(list2) || ' ' || compress(put(num,best8.)); end; call symput('rgbround',trim(left(list2))); *------anything specified for the BRIGHT= option?------; if symget('bright') = ' ' then do; britypes = ' '; call symput('britypes', compress(britypes)); end; *------anything specified for the PAINT= option?------; list = left(symget('paint')); if symget('paintvar') = ' ' then do; rgbtypes = ' '; call symput('rgbtypes', compress(rgbtypes)); if contour then put 'WARNING: PAINT= was not specified ' 'with a contour plot.'; end; *------parse PAINT= option------; else do; *------count list elements------; do n = 1 to 500 until(name2 = ' '); name2 = scan(list,n,' '); if n(input(name2,?? 32.)) then name2 = ' '; end; n = n - 1; *------set default, when only a variable name is specified------; if n < 1 then do; n = 3; list = 'blue magenta red'; end; else if n < 2 then do; n = 2; name2 = scan(list,1,' '); list = compress(name2) || ' ' || compress(name2); end; call symput('paintcol', trim(list)); *------store, check number of list elements------; call symput('paintnum',compress(put(n,3.))); *------table of recognized colors and their hex rgb------; allcols = 'BLACK--BLUE---BROWN--GRAY---GREEN--OLIVE--ORANGE-' || 'PINK---PURPLE-RED----VIOLET-WHITE--YELLOW-MAGENTA' || 'CYAN---'; hexcols = '000000 0000ff a05000 808080 00ff00 2a8307 ff8000 ' || 'ff0080 703070 ff0000 b090d0 ffffff ffff00 ff00ff ' || '00ffff '; list2 = ' '; *------construct list of (decimal) RGB values------; do j = 1 to 3; do i = 1 to n; color = upcase(scan(list, i, ' ')); k = index(allcols,trim(color)); *------grab hex code for name, or parse CXrrggbb------; if k then name1 = substr(hexcols,k + (j - 1) * 2,2); else name1 = substr(color ,(j - 1) * 2 + 3,2); *------check for validity------; num = input(name1,?? hex2.); if nmiss(num) then do; put 'ERROR: PAINT= color of ' color 'is not valid.'; ok = 0; j = 4; end; name1 = compress(put(num,3.)); if length(list2) + length(name1) + 1 > 500 then do; put 'ERROR: PAINT= list is too long.'; ok = 0; j = 3; i = n; end; *------build list------; list2 = trim(list2) || ' ' || trim(name1); end; end; *------store line segment end points in list if specified------; list2 = left(list2); name1 = scan(list,n + 1,' '); if name1 ne ' ' then do; do i = 1 to n; name1 = scan(list,n + i,' '); if nmiss(input(name1,?? 32.)) then do; put 'ERROR: PAINT= data value of ' name1 'is not valid.'; ok = 0; end; if length(list2) + length(name1) + 1 > 500 then do; put 'ERROR: PAINT= list is too long.'; ok = 0; i = n; end; list2 = trim(list2) || ' ' || name1; end; name1 = scan(list,2 * n + 1,' '); if name1 ne ' ' then do; put 'ERROR: PAINT= data value list is too long.'; ok = 0; end; end; *------store processed PAINT= list------; call symput('paint',trim(list2)); end; if input(symget('legend'), ?? 32.) then do; awidth = 9; do i = 1 to ntypes; anele = scan(types, i, ' '); awidth = max(awidth, length(anele) + 1); awidth = max(awidth, length(scan(symbols, i, ' ')) + 1); end; cols = min(15 + awidth * ntypes, &restorls); cols = 15 + floor((cols - 15) / awidth) * awidth; m = floor((&restorls - cols) / 2); cols = cols - 1; put / +m 'Types Legend |' @@; list = types; link legend; list = repeat('-', cols); substr(list, 15, 1) = '+'; put +m list; put +m 'Symbol Types |' @@; list = symtype; link legend; put +m 'Symbols |' @@; list = symbols; link legend; put +m 'Symbol Colors |' @@; list = symcol; link legendc; put +m 'Label Colors |' @@; list = labcol; link legendc; put +m 'Symbol Sizes |' @@; list = symsize; link legend; put +m 'Label Sizes |' @@; list = labsize; link legend; put +m 'Symbol Fonts |' @@; list = symfont; link legend; put +m 'Label Fonts |' @@; list = labfont; link legend; list = repeat('-', cols); put +m list; end; if _error_ or not ok then call symput('abort','1'); stop; return; legend: *------print legend------; j = 0; do i = 1 to ntypes; anele = compress(scan(list, i, ' '), "'"||'"'); link printele; end; put; return; legendc: *------print legend for colors------; j = 0; do i = 1 to ntypes; anele2 = scan(symtype, i, ' '); if index(rgbtypes, trim(anele2)) or index(britypes, trim(anele2)) then anele = ' '; else anele = compress(scan(list, i, ' '), "'"||'"'); link printele; end; put; return; printele: *------print one table element------; j = j + 1; if (15 + awidth * j) > &restorls then do; put / +(m+14) '|' @@; j = 1; end; put @(m + 17 + (j - 1) * awidth) anele $ @@; return; qlist: *------quote the elements of a list------; call vname(vars[i],name); list2 = ' '; list = vars[i]; charv = not index(upcase(name),'SIZE'); word = scan(list,1,' '); do n = 1 to ntypes while(word ne ' '); if charv then do; word = compress("'" || compress(word,"'"||'"') || "'"); if not index(substr(word,2),"'") then do; put 'ERROR: The list element ' name +(-1) '=' word 'is too long.'; call symput('abort','1'); stop; end; end; if (length(list2) + length(word)) >= 500 then do; put 'ERROR: The list ' name +(-1) '=' list2 'is too long.'; call symput('abort','1'); stop; end; else do; list2 = trim(list2) || ' ' || word; word = scan(list,n + 1,' '); if word = ' ' and i <= listm then word = scan(list2,1,' '); end; end; call symput(name,trim(left(list2))); vars[i] = list2; return; run; %if &syserr > 4 %then %let abort = 1; %if &abort %then %goto endit; *------inertias for correspondence analysis variable labels------; %if &corresp %then %do; data &tempdat2; set &data; keep contr: inertia; if _type_ = 'INERTIA' then do; output; if _error_ then call symput('abort','1'); stop; end; file log ps=&logps; put 'ERROR: _TYPE_ = "INERTIA" first observation not found.'; call symput('abort','1'); stop; run; %if &syserr > 4 %then %let abort = 1; %if &abort %then %goto endit; %if &dbprint %then %do; proc print data=&tempdat2; title3 "&tempdat2 - temporary data set, inertias"; run; title3; %end; %end; *------check, set remaining variables------; data _null_; file log ps=&logps; set &tempdat1 end=eof; length __name setl labelvar tvname symvar paintvar $ 35 upname $ 32; retain setl labelvar tvname symvar paintvar ' ' paintfou typefoun 0 ok 1; upname = upcase(name); *------get current names------; if _n_ = 1 then do; __name = upcase(symget('typevar')); link norm; tvname = __name; __name = upcase(symget('symvar')); link norm; symvar = __name; __name = upcase(symget('labelvar')); link norm; labelvar = __name; __name = upcase(symget('paintvar')); link norm; paintvar = __name; end; *------is the symbol variable numeric or character?------; if upname = symvar and type = 1 then call symput('symnumer','1'); *------find _type_ variable------; if upname = tvname then typefoun = 1; *------find PAINT= variable------; if upname = paintvar and type = 1 then paintfou = 1; *------find default label variable name------; else if type = 2 and (setl = ' ' or upname ne '_TYPE_') then setl = name; *------at end, output results------; if eof then do; if labelvar = ' ' and setl ne ' ' then labelvar = setl; if labelvar = ' ' then labelvar = '_blank_'; __name = labelvar; link nliteral; call symput('labelvar',trim(__name)); *------assorted error checking------; if not typefoun and tvname ne ' ' then do; put 'ERROR: TYPEVAR=' tvname 'not found.'; ok = 0; end; if not typefoun and input(symget('typespec'), ?? 32.) then do; put 'ERROR: A type variable must be available ' 'when TYPES= ' 'is specified.'; ok = 0; end; if not (paintvar = ' ' or paintfou) then do; put 'ERROR: A numeric PAINT=' paintvar 'variable was not found.'; ok = 0; end; end; if not ok or _error_ then call symput('abort','1'); return; norm: * Normalize name, upper case, strip n-literals. * Input: __name * Output: __name (updated) * Sample usage: * __name = '"a b"n'; * link norm; * Creates: __name = 'A B'; __name = upcase(__name); if substr(__name,1,1) in ("'", '"') then __name = substr(__name, 2, length(__name) - 3); drop __name; return; nliteral: * Puts n-literal on name if necessary. * Input: __name * Output: __name (updated) * Sample usage: * __name = 'a b'; * link nliteral; * Creates: __name = "'a b'n"; __v7 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789'; if (not (substr(__name, 1, 1) in ("'", '"'))) and (index(__name,' ') < length(__name) or compress(upcase(__name), __v7) ne ' ') then __name = "'" || trim(__name) || "'n"; drop __name __v7; return; run; %if &syserr > 4 %then %let abort = 1; %if &abort %then %goto endit; *------find minima, maxima------; proc means data=&preproc noprint; output out=&tempdat1 max(&vplotvar &hplotvar &paintvar)=vmax hmax %if &paintvar ne %then paintmax; min(&vplotvar &hplotvar &paintvar)=vmin hmin %if &paintvar ne %then paintmin;; run; %if &syserr > 4 %then %do; %let abort = 1; %goto endit; %end; %if &dbprint %then %do; proc print data=&tempdat1; title3 "&tempdat1 - temporary data set - proc means results"; run; title3; %end; *------set goptions------; goptions &gopts2 device=&device %if &method = print %then &gopprint; %else &gopplot; &gopts; *------check some parameters for valid values, set up others------; data _null_; file log ps=&logps; length c $ 1 post $ 65 vplotvar hplotvar labelvar $ 35 opt sysscp $ 8 str place vecheadr vecheadw tinc device $ 12 outward search vechead ls filepref $ 32 label plotreq plotopts upopts pl list labely labelx label $ 500 ind1 ind2 $ 35; ok = 1; call symput('somedata','0'); set &tempdat1(drop=_type_); call symput('somedata','1'); *------check missings------; if n(vmin,hmin,vmax,hmax) < 4 then do; put 'ERROR: At least one variable is all missing.'; ok = 0; end; *------check for nonpositive data with log scales------; if (vmin <= 0 and &vlogscal) or (hmin <= 0 and &hlogscal) then do; put "ERROR: Nonpositive data with INTERPOL=&interpol.."; ok = 0; end; *------store extend values------; list = symget('extend'); call symput('close',compress(put(index(list,'close'),best3.))); if nmiss(input(scan(list,1,' '),?? 32.)) then call symput('extendl',' '); else call symput('extendl',scan(list,1,' ')); if nmiss(input(scan(list,2,' '),?? 32.)) then call symput('extendr',' '); else call symput('extendr',scan(list,2,' ')); if nmiss(input(scan(list,3,' '),?? 32.)) then call symput('extendt',' '); else call symput('extendt',scan(list,3,' ')); if nmiss(input(scan(list,4,' '),?? 32.)) then call symput('extendb',' '); else call symput('extendb',scan(list,4,' ')); *------make sure PAINT= minimum, maximum are stored------; %if &paintvar ne %then %do; if n(paintmin,paintmax) ne 2 then do; put "ERROR: All missing PAINT= variable &paintvar.."; ok = 0; end; if paintmax - paintmin < &singular then do; put "ERROR: Insufficient range in PAINT= minimum and maximum."; ok = 0; end; else do; list = symget('rgbround'); n = input(scan(list,1,' '),?? 32.); if n(n) and n < 0 then n = -(paintmax - paintmin) / n; list = trim(list) || ' ' || compress(put(n,best8.)); call symput('rgbround',trim(list)); list = symget('paint'); *------store the paint value list if unspecified------; if scan(list,3 * &paintnum + 1,' ') = ' ' then do; inc = (paintmax - paintmin) / (&paintnum - 1); do i = paintmin to paintmax by inc; if abs(i) < inc * 0.01 then opt = '0'; else if i < 0 then opt = compress(put(i,best7.)); else opt = compress(put(i,best6.)); if length(list) + length(opt) + 1 > 500 then do; put 'ERROR: PAINT= list is too long.'; ok = 0; i = paintmax; end; list = trim(list) || ' ' || compress(opt); end; call symput('paint',trim(list)); end; end; *------print the paint legend, the value for each color------; if &legend then do; length legend $ 64; legend = 'Paint Legend - ' || symget('paintvar'); m = floor((&restorls - length(legend)) / 2); put / +m legend; m = floor((&restorls - 24) / 2); put +m '------------------------'; do j = 1 to &paintnum; str = scan(symget('paintcol'), j, ' '); opt = scan(list, 3 * &paintnum + j, ' '); opt = right(opt); put +m +3 opt $char8. ' = ' str; end; put +m '------------------------'; end; %end; *------set default file names------; sysscp = symget('sysscp'); filepref = symget('filepref'); post = symget('post'); if post = ' ' then do; if sysscp = 'CMS' then post = trim(filepref) || ' ' || 'ps'; else if sysscp =: 'VMS' or sysscp = 'WIN' or sysscp = 'OS2' then post = trim(filepref) || '.' || 'ps'; else post = '.' || trim(filepref) || '.' || 'ps'; end; *------compute (possibly adjusted) range------; isavec = index(sy