*
;
/**************************************************************************
 * SAS-Makro: GRFTREE   zur Erzeugung von Dendrogramms aus                *
 *                      Proc CLUSTER - Daten gezeichnet mit               *
 *                      PROC GPLOT                                        *
 * Veraenderungem am Original:                                            *
 *   28.12.93  Die GOPTIONS NOCELL, HPOS und VPOS weggelassen,            *
 *             CBACK hinzugefuegt                                         *
 *   28.06.94  Im Beispielprogramm wird in der Input-Anweisung die        *                                                                        *
 *             Plazierungsanweisung (1-3) für die Variable Strain         *
 *             entfernt.                                                  *
 *   25.01.95  Das Makro wird durch die modifizierte Version ersetzt,     *
 *             Hinzufügen des Beispielprogramms und der Goption CBACK.    *
 * Beispiel:                                                              *

   The program:

   DATA A(TYPE=DISTANCE); * TEST DATA SET OF SIMILARITIES;
     INFILE CARDS MISSOVER;
     INPUT STRAIN $  X1-X5 ;
     ARRAY X(I) X1-X5;
     DO OVER X;
       IF X NE . THEN X = 1 - X; * CONVERT TO DISSIMILARITY;
     END;
     DROP I;
     CARDS;
   X1 1.0
   X2 0.9 1.0
   X3 0.7 0.7 1.0
   X4 0.5 0.8 0.9 1.0
   X5 0.5 0.7 0.8 0.9 1.0
   RUN;
   PROC CLUSTER DATA=A METHOD=AVERAGE NOPRINT NONORM NOSQUARE
     OUTTREE=A;
     ID STRAIN;
   RUN;
   DATA A; SET A; * BACKTRANSFORM TO SIMILARITY VALUES;
     _HEIGHT_ = ABS(_HEIGHT_ - 1);
   RUN;
   TITLE ;
   %GRFTREE(CLUSDSN=A,ITEMS=5,AXIS=S);


   and the graph should look similar to this:

   X4    ----------------------------+
                                     |
                                     |
                                     +-------------------+
                                     |                   |
                                     |                   |
   X5    ----------------------------+                   |
                                                         |
                                                         +------+
                                                         |      |
                                                         |      |
                                                         |      |
                                                         |      |
   X3    ------------------------------------------------+      |
                                                                |
                                                                |
                                                                |
                                                                |
                                                                |
   X1    --------------------------------------------+          |
                                                     |          |
                                                     |          |
                                                     +----------*
                                                     |
                                                     |
   X2     -------------------------------------------+

       ---+---------+---------+---------+---------+---------+---------+---
         1.0       0.9       0.8       0.7       0.6       0.5       0.4

                                   SIMILARITY
  *************************************************************************/

%MACRO GRFTREE(CLUSDSN=,ITEMS=,AXIS=,GROUPAT=,TRIML=,TRIMR=,ITEMLIST=N,
               SPLIT=N,FONT=SIMPLEX,LABEL=,CTREE=BLACK,CAXIS=BLACK,
               GOUT=,GNAME=,GDES=);
  /*
    GRFTREE - DRAWS DENDROGRAMS USING PROC CLUSTER OUTPUT DATA SET

    Written:  October 5, 1989     Modified:  October 16, 1989
                                               March  9, 1990
                                               April 29, 1990
                                            November 27, 1990
                                             October  6, 1994
                                            November 16, 1994
    Originally developed using SAS 5.18 on VM/CMS
    Procs:  PROC GPLOT, PROC MEANS, PROC PRINT, PROC SORT, PROC TREE
    Other:  SAS MACRO language
    Macros: GRFTREE, ORDER (both included in this file)
    Note:   Do not use TREEDATA, TREESTUF, ANNOSTUF or ANNOSPLT
            as a data set name.
            Titles should be specified prior to the macro call.
            No footnotes are allowed.

    Converts output data set from PROC CLUSTER into an easy to
    inteprete dendrogram.  The X axis scale is in distance or
    similarity (depending on data used in PROC CLUSTER), and the
    Y axis scale is the item names that were clustered.

    MACRO VARIABLE      DESCRIPTION
    In Request:
    CLUSDSN             Name of SAS data set created by PROC CLUSTER
    ITEMS               Number of objects that you clustered
    AXIS                How to scale the X axis
                        S - similarity
                        D - distance
    DEBUG               YES for some debugging prints (default is NO)
    GROUPAT             Value to join items into a cluster and
                        a filled triangle is used (optional)
    TRIML               Value to truncate the left side of the X axis.
                        Used with TRIMR to 'zoom in' on a part of
                        the tree. Both TRIML and TRIMR are optional
    TRIMR               Value to truncate the right side of the X axis
    FONT                Font to print all text (default is SIMPLEX)
    LABEL               Text to label the X axis (default is SIMILARITY
                        if AXIS = S, DISTANCE if AXIS = D)
    CTREE               Color of the tree (default is BLACK)
    CAXIS               Color of the axes (default is BLACK)
    GOUT                Name of a graphics catalog (optional)
    GNAME               Name of the tree is stored in GOUT (optional)
    GDES                Description of the tree stored in GOUT (optional)
    ITEMLIST            Print the tree item order (default is N)  (Y/N)
    SPLIT               Spread tree over several pages (default N) (Y/N)

    Internal:
    GROUP               group some of the items? (YES or NO)
    MAXL                length of longest item label
    MINVAL              minimum (rightmost) X axis value used to
                        scale similarity axis in 1/10ths
    WINDOW              zooming done? (YES or NO)
    S                   FROM GRFTREE: (leader for notes from the macro)
    ST                  items - 1
    SCALE               scale of the X axis (_HEIGHT_)

    For more information:

    Dr. Dan Jacobs                       Internet: DAN@UMDD.UMD.EDU
    Maryland Sea Grant College Program
    University of Maryland
    0102 Skinner Hall
    College Park, Maryland  20742
    (301) 405-6379

    Please acknowledge Dan Jacobs as the provider of the macro code
    in any publication that uses the results of this macro.  Thank you.
  */
  %LET S = %STR(GRFTREE:  );
  OPTIONS NONOTES;
  goptions cback=white;
  %PUT %STR(   );
  %PUT &S Please remember to acknowledge Dan Jacobs as the provider;
  %PUT &S of the dendrogram macro software in any publication that;
  %PUT &S uses the results of this macro.  Thank you.;
  %PUT %STR(  );
  %PUT &S Starting to figure out how to draw the tree . . . ;
  %* CHECK MACRO CALL ENTRIES;
  %IF &CLUSDSN =   %THEN %GOTO BADDSN;
  %IF &TRIML =  AND &TRIMR =  %THEN %LET WINDOW = NO;
  %ELSE %LET WINDOW = YES;
  %IF &GROUPAT =   %THEN %LET GROUP = NO;
  %ELSE %LET GROUP = YES;
  %LET AXIS = %UPCASE(%SUBSTR(&AXIS,1,1));
  %IF &AXIS = S OR &AXIS = D %THEN %LET SCALE = _HEIGHT_;
  %ELSE %DO;
    %PUT &S  AXIS can only be S or D and not &AXIS;
    %PUT &S  No dendrogram will be done.;
    %GOTO ENDALL;
  %END;
  %LET ST = %EVAL(&ITEMS - 1);
  %IF &LABEL =  %THEN %DO; %* DEFAULT X AXIS LABEL;
    %IF &AXIS = S %THEN %LET LABEL = SIMILARITY;
    %ELSE %LET LABEL = DISTANCE;
  %END;
  %IF %UPCASE(%SUBSTR(&ITEMLIST,1,1)) NE Y %THEN %LET ITEMLIST = N;
  %IF %UPCASE(%SUBSTR(&SPLIT,1,1)) NE Y %THEN %LET SPLIT = N;
  %* CHECK IF DATA SET EXISTS AND CALC. MAX. ITEM LABEL LENGTH;
  %LET MAXL = 0;
  DATA TREEDATA; SET &CLUSDSN END=EOF;
    RETAIN MAXL 0;
    MAXL = MAX(MAXL,LENGTH(_NAME_));
    %IF &WINDOW = YES %THEN %DO;
      %* ZOOM IN TO PART OF RANGE TO PLOT, IF REQUESTED;
      %IF &AXIS = D %THEN %DO;
        %IF &TRIML NE  %THEN %DO;
          IF &SCALE < &TRIML THEN &SCALE = &TRIML; %END;
        %IF &TRIMR NE  %THEN %DO;
          IF &SCALE > &TRIMR THEN &SCALE = &TRIMR; %END;
      %END;
      %ELSE %DO;
        %IF &TRIML NE  %THEN %DO;
          IF &SCALE > &TRIML THEN &SCALE = &TRIML; %END;
        %IF &TRIMR NE  %THEN %DO;
          IF &SCALE < &TRIMR THEN &SCALE = &TRIMR; %END;
      %END;
    %END;
    IF EOF THEN CALL SYMPUT('MAXL',TRIM(PUT(MAXL,2.)));
  RUN;
  %IF &MAXL = 0 %THEN %GOTO BADDSN;
  %IF &GROUP = YES %THEN %DO;
    %IF &AXIS = S %THEN %DO;
      PROC TREE H=HEIGHT SIM LEVEL=&GROUPAT NOPRINT
        DATA=TREEDATA OUT=TREESTUF;
    %END;
    %ELSE %DO; %* DISTANCE;
      PROC TREE H=HEIGHT DIS LEVEL=&GROUPAT NOPRINT
        DATA=TREEDATA OUT=TREESTUF;
    %END;
    RUN; %* CLOSE OFF PROC TREE;
    DATA TREESTUF; SET TREESTUF;
      IF _NAME_ NE CLUSNAME;
    RUN;
    PROC SORT DATA=TREEDATA; BY _NAME_; RUN;
    PROC SORT DATA=TREESTUF; BY _NAME_; RUN;
    DATA TREEDATA(KEEP=_NAME_ FROMHT FROMFREQ FROM CLUSTER)
         TREESTUF(KEEP=_NAME_ TOHT TOFREQ TO);
      MERGE TREEDATA TREESTUF(IN=INB); BY _NAME_;
     IF INB THEN _PARENT_ = CLUSNAME;
  %END;
  %ELSE %DO; %* NO GROUPING AT SOME VALUE DONE;
    DATA TREEDATA(KEEP=_NAME_ FROMHT FROMFREQ FROM CLUSTER)
         TREESTUF(KEEP=_NAME_ TOHT TOFREQ TO);
      SET TREEDATA;
      CLUSTER = .;
  %END;
    %* FINISH OFF SPLITTING THE DATA SET INTO PARENT AND CHILD SETS;
    TO = _NAME_; TOHT = &SCALE; TOFREQ = _FREQ_; OUTPUT TREESTUF;
    FROM = _NAME_; _NAME_ = _PARENT_;
    FROMHT = &SCALE; FROMFREQ = _FREQ_; OUTPUT TREEDATA;
  RUN;
  %PUT &S   . . . determining item order based on the clustering;
  PROC SORT DATA=TREEDATA; BY _NAME_; RUN;
  PROC SORT DATA=TREESTUF; BY _NAME_; RUN;
  DATA TREEDATA;
    MERGE TREESTUF TREEDATA(IN=INA); BY _NAME_;
    IF INA ;
   %IF &GROUP = YES %THEN %DO;
     %IF &AXIS = D %THEN %DO;
       %IF &TRIML =  %THEN %LET TRIML = 0.00;
       IF &TRIML LT TOHT LT &GROUPAT THEN DO;
         IF &TRIML LT FROMHT LT &GROUPAT THEN DELETE;
         IF CLUSTER = . AND FROMHT = &TRIML THEN DELETE;
       END;
     %END;
     %ELSE %DO;
       %IF &TRIML =  %THEN %LET TRIML = 1.00;
       IF &GROUPAT LT TOHT LT &TRIML THEN DO;
         IF &GROUPAT LT FROMHT LT &TRIML THEN DELETE;
         IF CLUSTER = . AND FROMHT = &TRIML THEN DELETE;
       END;
     %END;
   %END;
   CLUSNUM = SUBSTR(_NAME_,3) + 0.0;
   DROP _NAME_;
  RUN;
  %IF &AXIS = S %THEN %DO;
    PROC MEANS NOPRINT MIN DATA=TREEDATA; VAR FROMHT;
      OUTPUT OUT=TREESTUF MIN=FROMHT; RUN;
    DATA TREESTUF; SET TREESTUF;
      %* ROUND DOWN THE LOWEST (RIGHT MOST) VALUE TO SCALE IN TENTHS;
      FROMHT = FLOOR(FROMHT * 10)/10;
      CALL SYMPUT('MINVAL',TRIM(LEFT(FROMHT)));
    RUN;
  %END;
  %ORDER; %* GET ORDER THAT THE ITEMS ARE TO GO ON THE Y AXIS;
  %IF &ITEMLIST = Y %THEN %DO;
    %PUT &S   . . . printing the item order;
    PROC SORT DATA=TREESTUF; BY Y; RUN;
    PROC PRINT DATA=TREESTUF SPLIT=' ';
      VAR FROM Y;
      LABEL FROM = 'ITEM' Y = 'Y COORD.';
      TITLE3 'ITEM ORDER FOR THE DENDROGRAM';
    RUN;
  %END;
  TITLE3 ;
  %PUT &S   . . . determining how to draw the dendrogram (tree);
  PROC SORT DATA=TREESTUF; BY DESCENDING CLUSNUM FROM; RUN;
  PROC SORT DATA=TREEDATA; BY DESCENDING CLUSNUM FROM; RUN;
  DATA TREEDATA(KEEP=X Y FROM TO)
       TREESTUF(KEEP=XSYS YSYS HSYS SIZE POSITION TEXT STYLE
                     COLOR X Y FUNCTION LINE)
       ANNOSTUF(KEEP=XSYS YSYS HSYS SIZE POSITION TEXT STYLE
                     COLOR X Y FUNCTION LINE);
    MERGE TREEDATA TREESTUF; BY DESCENDING CLUSNUM FROM;
    LENGTH FUNCTION STYLE COLOR $ 8
           TEXT $ &MAXL
           XSYS YSYS HSYS WHEN POSITION $ 1;
    ARRAY CLUS{*} CL1-CL&ST.;
    RETAIN CL1-CL&ST. LASTY SAMEHT;
    XSYS = '2'; YSYS = '2'; HSYS = '4'; SIZE = 1;
    IF TOHT = . THEN DO;
      %IF &AXIS = D AND &TRIML = 0.00 %THEN %DO;
         %* MAKE SURE DISTANCE AXIS INCLUDES 0 UNLESS TRIMMED (04/24/90);
         X = 0; Y = 1; OUTPUT TREEDATA;
         X = .; Y = .; OUTPUT TREEDATA;
      %END;
      RETURN; %* THIS OBS NOT NEEDED;
    END;
    IF FROMFREQ = 1 THEN DO; %* EACH ITEM IS ITS OWN CLUSTER;
      I1 = SUBSTR(TO,3) + 0.0;
      %* PUT THE ITEM NAMES IN AN ANNOTATE DATA SET TO LABEL Y AXIS;
      %* X COORDINATE (Y COORD ALREADY IN TREESTUF);
      %* 5/10/93 - WINDOW COORD, NOT DATA;
      POSITION = '6'; XSYS = '5'; X = 0;
      FUNCTION = 'LABEL'; WHEN = 'B';
      COLOR = "&CTREE"; STYLE = "&FONT";
      %IF &ITEMS > 50 AND &SPLIT NE Y %THEN SIZE = 1.0 * 50/&ITEMS;
      %ELSE SIZE = 1.0;;
      SUBSTR(TEXT,1,&MAXL) = TRIM(LEFT(FROM));
      OUTPUT TREESTUF;
      X = FROMHT; XSYS = '2'; %* DATA COORD. SYSTEM, 5/10/93;
      %* DETERMINE HOW THE PLOTTER SHOULD DRAW THE LINES OF THE TREE;
      SIZE = 1;
      IF FIRST.CLUSNUM THEN DO;
        CLUS{I1} = Y;
        LASTY = Y;
        IF CLUSTER = . THEN DO;
          OUTPUT TREEDATA;
          X = TOHT; OUTPUT TREEDATA;
          X = .; Y = .; OUTPUT TREEDATA;
        END;
        ELSE DO;
          %* STORE IN SEPARATE DATA SET (NOT IN TREESTUF) SINCE
            POLY AND POLYCONT OBS. MUST BE IN SEQUENTIAL ORDER AND
            NOT SEPARATED BY AXIS LABEL OBS.;
          FUNCTION = 'POLY'; STYLE = 'S'; COLOR = "&CTREE"; LINE = 1;
          OUTPUT ANNOSTUF;
        END;
      END;
      ELSE IF LAST.CLUSNUM THEN DO;
        IF SAMEHT = 'Y' THEN DO;
          SAMEHT = 'N';
          CLUS{I1} = (CLUS{I1}*(TOFREQ - FROMFREQ) + Y) / TOFREQ;
        END;
        ELSE CLUS{I1} = (CLUS{I1} + Y) / 2;
        IF CLUSTER = . THEN DO;
          OUTPUT TREEDATA;
          X = TOHT; OUTPUT TREEDATA;
          Y = LASTY; OUTPUT TREEDATA;
          X = .; Y = .; OUTPUT TREEDATA;
        END;
        ELSE DO;
          FUNCTION = 'POLYCONT'; COLOR = "&CTREE"; OUTPUT ANNOSTUF;
          X = TOHT; Y = CLUS{I1}; OUTPUT ANNOSTUF;
        END;
      END;
    END;
    ELSE DO; %* DETERMINE HOW TO DRAW THE LINES OF THE TREE;
     I1 = SUBSTR(FROM,3) + 0.0;
     I2 = SUBSTR(TO,3) + 0.0;
     X = FROMHT;
     IF FIRST.CLUSNUM THEN DO;
       IF ROUND(TOHT,.00001) = ROUND(FROMHT,.00001) THEN SAMEHT = 'Y';
       ELSE SAMEHT = 'N';
       CLUS{I2} = CLUS{I1};
       LASTY = CLUS{I1};
       Y = CLUS{I1};
       OUTPUT TREEDATA;
       X = TOHT; OUTPUT TREEDATA;
       X = .; Y = .; OUTPUT TREEDATA;
     END;
     ELSE IF LAST.CLUSNUM THEN DO;
       IF ROUND(TOHT,.00001) = ROUND(FROMHT,.00001) THEN SAMEHT = 'Y';
       IF SAMEHT = 'Y' THEN DO;
         SAMEHT = 'N';
         CLUS{I2} = (CLUS{I1}*FROMFREQ + CLUS{I2}*(TOFREQ-FROMFREQ))
                    / TOFREQ;
       END;
       ELSE CLUS{I2} = (CLUS{I1} + CLUS{I2}) / 2;
       Y = CLUS{I1};
       OUTPUT TREEDATA;
       X = TOHT; OUTPUT TREEDATA;
       Y = LASTY; OUTPUT TREEDATA;
       X = .; Y = .; OUTPUT TREEDATA;
     END;
    END;
  RUN;
  %* PUT POLY AND POLYCONT WITH THE AXIS LABEL ANNOTATE DATA;
  DATA ANNOSTUF; SET ANNOSTUF TREESTUF; RUN;
  %PUT &S   . . . drawing the dendrogram;
  %IF &AXIS NE D AND &TRIML NE    %THEN %DO;
    DATA _NULL_; %* ROUND UP THE LEFT MOST VALUE TO SCALE IN TENTHS;
      CALL SYMPUT('TRIML',CEIL(&TRIML * 10) / 10);
    RUN;
  %END;
  %ELSE %LET TRIML = 1.00;
  GOPTIONS NOCELL NOCHARACTERS HPOS=91 VPOS=53;
  SYMBOL1 L=1 V=NONE C=&CTREE I=JOIN;
  %IF &GOUT NE  %THEN %DO; * OUTPUT GRAPH INFO;
    %LET GOUT = %STR(GOUT=&GOUT);
    %LET GNAME = %STR(NAME="&GNAME");
    %LET GDES = %STR(DES="&GDES");
  %END;
  %* ADDED 10/19/90, MODIFIED 11/16/94;
  DATA _NULL_;  %* CALCULATE THE AMOUNT TO OFFSET THE X AXIS ORIGIN;
    %IF &ITEMS > 50 AND &SPLIT NE Y %THEN ORIGIN = &MAXL * 50/&ITEMS;
    %ELSE ORIGIN = &MAXL.;;
    CALL SYMPUT('ORIGIN',TRIM(LEFT(ORIGIN)));
  RUN;
  %IF &SPLIT = Y %THEN %DO; %* ADDED 10/06/94;
    DATA TREESTUF;
      DO DIV = 40 TO 50 BY 1;
        TIMES =  INT(&ITEMS/DIV);
        NITEMS = INT(&ITEMS/TIMES);
        DONE = TIMES * NITEMS;
        LEFT = &ITEMS - DONE;
        IF TIMES > 1 THEN OUTPUT TREESTUF;
      END;
    RUN;
    PROC SORT DATA=TREESTUF OUT=TREESTUF; BY LEFT TIMES; RUN;
    DATA TREESTUF; SET TREESTUF(FIRSTOBS=1 OBS=1);
      CALL SYMPUT('TIMES',TRIM(LEFT(TIMES)));
      CALL SYMPUT('NITEMS',TRIM(LEFT(NITEMS)));
    RUN;
    %DO I = 1 %TO &TIMES;
      GOPTIONS GSFMODE=
        %IF &I = 1 %THEN REPLACE; %ELSE APPEND;;
      %LET FITEMS = %EVAL(((&I - 1) * &NITEMS) + 1);
      %IF &I = &TIMES %THEN %LET LITEMS = &ITEMS;
      %ELSE %LET LITEMS = %EVAL(&FITEMS + &NITEMS - 1);
      %PUT &S   . . . working on OTUs &FITEMS to &LITEMS (&I of &TIMES);
      DATA TREESTUF; SET TREEDATA;
        LAGY = LAG(Y); LAGX = LAG(X);
        IF X = . AND Y = . THEN OUTPUT;
        ELSE IF ((&FITEMS - 1) < Y < (&LITEMS + 1)) THEN DO;
          OUTPUT;
          IF LAGY <= (&FITEMS - 1) AND LAGY NE . THEN DO;
            IF LAGX = X THEN DO;
              Y = &FITEMS - 1;
              IF Y > 0 THEN DO;
                OUTPUT; Y = .; X = .; OUTPUT; END;
            END;
          END;
          ELSE IF LAGY > &LITEMS THEN DO;
            IF LAGX = X THEN DO;
              Y = &LITEMS + 1; OUTPUT;
              Y = .; X = .; OUTPUT;
            END;
          END;
        END;
        ELSE IF (&FITEMS LE LAGY LE &LITEMS) THEN DO;
          IF Y < &FITEMS AND Y NE . THEN DO;
            IF LAGX = X THEN DO;
              Y = &FITEMS - 1;
              IF Y NE . AND Y NE 0 THEN DO;
                OUTPUT; Y = .; X = .; OUTPUT; END;
            END;
          END;
          ELSE IF Y > &LITEMS THEN DO;
            IF LAGX = X THEN DO;
              Y = &LITEMS + 1; OUTPUT;
              Y = .; X = .; OUTPUT;
            END;
          END;
        END;
        ELSE IF Y < &FITEMS AND LAGY > &LITEMS THEN DO;
          IF LAGX = X THEN DO;
            Y = &FITEMS - 1;
            IF Y NE . AND Y NE 0 THEN DO;
              OUTPUT; Y = &LITEMS + 1;
              OUTPUT; Y = .; X = .; OUTPUT; END;
          END;
        END;
        ELSE IF Y > &LITEMS AND LAGY < &FITEMS THEN DO;
          IF LAGX = X THEN DO;
            Y = &FITEMS - 1;
            IF Y > 0 THEN DO;
              OUTPUT; Y = &LITEMS + 1;
              OUTPUT; Y = .; X = .; OUTPUT; END;
          END;
        END;
      RUN;
      DATA ANNOSPLT; SET ANNOSTUF;
        RETAIN X1 Y1 X2 Y2 FLAG 0;
        Y2 = LAG(Y); X2 = LAG(X); LAGF = LAG(FUNCTION);
        IF FUNCTION = 'LABEL' THEN DO;
          IF (&FITEMS LE Y LE &LITEMS) THEN DO;
            TEXT = TRIM(LEFT(TEXT)); OUTPUT;
            %IF &I NE 1 %THEN %DO;
              IF FLAG = 0 THEN DO;
                XSYS = '3'; YSYS = '3'; HSYS = '4'; SIZE = 0.5;
                X = 2; Y = 2; FUNCTION = 'LABEL'; POSITION = '5';
                TEXT = TRIM(LEFT("&I")); OUTPUT;
                FLAG = 1;
              END;
            %END;
          END;
          RETURN;
        END;
        IF FUNCTION = 'POLY' THEN DO;
          X1 = X; Y1 = Y; RETURN;
        END;
        IF LAGF = 'POLY' THEN RETURN;
        X3 = X; Y3 = Y;
        FUNCTION = 'POLY'; %* FIRST POINT IN POLY;
        IF Y1 < &FITEMS THEN DO;
          IF Y2 < &FITEMS THEN RETURN; %* POLY BELOW CUT;
          X = X1; Y = &FITEMS - 1; OUTPUT;
        END;
        ELSE IF Y1 <= &LITEMS THEN DO;
          X = X1; Y = Y1; OUTPUT;
        END;
        ELSE RETURN; %* POLY ABOVE CUT;
        FUNCTION = 'POLYCONT'; %* REST OF THE POINTS IN POLY;
        IF Y2 <= &LITEMS THEN DO;
          X = X2; Y = Y2; OUTPUT;
        END;
        ELSE DO;
          X = X2; Y = &LITEMS + 1; OUTPUT;
        END;
        IF Y3 < &FITEMS THEN DO;
          IF Y2 > &LITEMS THEN DO;
            X =
              %IF &AXIS = S %THEN 1 -;
              ((&LITEMS + 1) - Y2)/(Y3 - Y2) * ABS(X3 - X2);
            Y = &LITEMS + 1; OUTPUT;
          END;
          X =
            %IF &AXIS = S %THEN 1 -;
            ((&FITEMS - 1) - Y2)/(Y3 - Y2) * ABS(X3 - X2);
          Y = &FITEMS - 1; OUTPUT;
        END;
        ELSE IF Y3 <= &LITEMS THEN DO;
          IF Y2 > &LITEMS THEN DO;
            X =
              %IF &AXIS = S %THEN 1 -;
              ((&LITEMS + 1) - Y2)/(Y3 - Y2) * ABS(X3 - X2);
            Y = &LITEMS + 1; OUTPUT;
          END;
          X = X3; Y = Y3; OUTPUT;
          IF Y1 < &FITEMS THEN DO;
            X =
              %IF &AXIS = S %THEN 1 -;
              ((&FITEMS - 1) - Y1)/(Y3 - Y1) * ABS(X3 - X1);
            Y = &FITEMS - 1; OUTPUT;
          END;
        END;
        ELSE DO;
          X =
            %IF &AXIS = S %THEN 1 -;
            ((&LITEMS + 1) - Y1)/(Y3 - Y1) * ABS(X3 - X1);
          Y = &LITEMS + 1; OUTPUT;
          IF Y1 < &FITEMS THEN DO;
            X =
              %IF &AXIS = S %THEN 1 -;
              ((&FITEMS - 1) - Y1)/(Y3 - Y1) * ABS(X3 - X1);
            Y = &FITEMS - 1; OUTPUT;
          END;
        END;
        DROP X1-X3 Y1-Y3 LAGF FLAG;
      RUN;
      SYMBOL1 L=1 V=NONE W=2 C=BLACK I=JOIN;
      PROC GPLOT DATA=TREESTUF ANNO=ANNOSPLT;
        PLOT Y*X / SKIPMISS HAXIS=AXIS1 VAXIS=AXIS2
                   CAXIS=&CAXIS;

        %IF &I = 1 %THEN %DO;
        AXIS1 VALUE=(F=&FONT H=1 C=&CAXIS)
              LABEL=(F=&FONT H=1.5 C=BLACK "&LABEL")
              MINOR=(N=9)
        %END;
        %ELSE %DO;
        AXIS1 VALUE=(F=SIMPLEX H=1 C=&CAXIS
                     %DO DD = 0 %TO 10; "`" %END; )
              LABEL=(F=SIMPLEX H=1.5 C=&CAXIS "`````")
              MAJOR=NONE
              MINOR=NONE
              STYLE = 0
        %END;
              ORDER=&TRIML TO &MINVAL BY -.1
              ORIGIN=(&ORIGIN)
              OFFSET=(0,0)
              COLOR = &CAXIS;
        AXIS2 VALUE=NONE
              LABEL=NONE
              MINOR=NONE
              MAJOR=NONE
              ORDER=
              %IF &I = 1 %THEN 1 TO %EVAL(&LITEMS + 1) BY 1;
              %ELSE %IF &I = &TIMES %THEN %EVAL(&FITEMS - 1) TO &LITEMS BY 1;
              %ELSE %EVAL(&FITEMS - 1) TO %EVAL(&LITEMS + 1) BY 1 ;
              STYLE = 0
              OFFSET=(2,2)
              COLOR = &CAXIS;
        FOOTNOTE ;
      RUN;
    %END;
  %END;
  %ELSE %DO;
    PROC GPLOT DATA=TREEDATA ANNO=ANNOSTUF &GOUT;
      PLOT Y*X / SKIPMISS HAXIS=AXIS1 VAXIS=AXIS2
                 CAXIS=&CAXIS &GNAME &GDES;
      AXIS1 VALUE=(F=&FONT H=1 C=&CAXIS)
            LABEL=(F=&FONT H=1.5 C=&CAXIS "&LABEL")
          %IF &AXIS = S %THEN %DO;
            ORDER=&TRIML TO &MINVAL BY -.1
            MINOR=(N=9)
          %END;
            OFFSET=(0,0)
            ORIGIN=(&ORIGIN)
            COLOR = &CAXIS;
      AXIS2 VALUE=NONE
            LABEL=NONE
            MINOR=NONE
            MAJOR=NONE
            ORDER= 1 TO &ITEMS BY 1
            STYLE = 0
            OFFSET=(2,2)
            COLOR = &CAXIS;
      FOOTNOTE ;
    RUN;
  %END;
  %GOTO ENDALL;
  %BADDSN: %PUT &S No tree produced since an output data set from ;
    %PUT &S PROC CLUSTER was not provided.;
  %ENDALL: %PUT %STR(   );  OPTION NOTES;
%MEND GRFTREE;
%MACRO ORDER;
  PROC SORT DATA=TREEDATA; BY CLUSNUM FROM; RUN;
  DATA TREESTUF; SET TREEDATA; BY CLUSNUM;
    ARRAY CLUS{*} CL1-CL&ST.;
    RETAIN CL1-CL&ST. LASTY;
    IF TOHT = . THEN DO;
      IF MOD(FROMFREQ,2) = 1 THEN Y = FROMFREQ/2;
      ELSE Y = (FROMFREQ + 1)/2;
      CLUS{1} = Y;
    END;
    ELSE DO;
     Y = (TOFREQ - FROMFREQ)/2;
     IF FROMFREQ NE 1 THEN DO;
      I1 = SUBSTR(TO,3) + 0.0;
      I2 = SUBSTR(FROM,3) + 0.0;
      IF FIRST.CLUSNUM THEN DO;
       CLUS{I2} = CLUS{I1} + Y;
       LASTY = CLUS{I2};
      END;
      ELSE CLUS{I2} = CLUS{I1} - Y;
      Y = CLUS{I2};
     END;
     ELSE DO;
      I2 = SUBSTR(TO,3) + 0.0;
      IF FIRST.CLUSNUM THEN DO;
        Y = CLUS{I2} + Y;
        LASTY = Y;
      END;
      ELSE DO;
       IF CLUSTER = . THEN Y = CLUS{I2} - Y;
       ELSE DO;
        Y = LASTY - 1;
        LASTY = Y;
       END;
      END;
     END;
    END;
    IF FROMFREQ = 1 THEN DO;
      IF MOD(Y,1) = 0.5 THEN Y = Y + .5; %* ODD NUMBER OF ITEMS;
      OUTPUT;
    END;
    KEEP CLUSNUM FROM Y;
  RUN;
%MEND ORDER;

*
;