(FILECREATED "17-Apr-86 16:44:13" {MITFS1-E40:SLOAN% SCHOOL:MASSINSTTECH}<EDAN% KABATCHNIK>BOXPLOT.;7        

      previous date: "16-Apr-86 17:24:30" 
{MITFS1-E40:SLOAN% SCHOOL:MASSINSTTECH}<EDAN% KABATCHNIK>BOXPLOT.;4)


(* Copyright (c) 1986 by Massachusetts Institute of Technology. All rights reserved.)

(PRETTYCOMPRINT BOXPLOTCOMS)

(RPAQQ BOXPLOTCOMS ((RECORDS BoxPlotRecord)
		    (FNS BOXPLOT BOXPLOT.CALCULATE BOXPLOT.GETNAMES BOXPLOT.INITIALIZE BOXPLOT.MAKE 
			 LISTMAX LISTMIN)))
[DECLARE: EVAL@COMPILE 

(RECORD BoxPlotRecord (Minimum Maximum BoxPlotNumber Median LowerHinge UpperHinge LowerFence 
			       UpperFence LeftExtreme RightExtreme Middle LeftMarker RightMarker 
			       SortedDataSet Length))
]
(DEFINEQ

(BOXPLOT
  [LAMBDA (ListOfLists OptionalListOfBoxPlotNames OptionalPlotObject)
                                                             (* enk "17-Apr-86 15:18")

          (* BOXPLOT accumulates all necessary information for each dataset within the list of lists in BoxPlotData by calling
	  BOXPLOT.CALCULATE and calls BOXPLOT.INITIALIZE to calculate and set the extent of the BoxPlot object.
	  BOXPLOT.MAKE is then called to actually place the BoxPlot parts within the PlotObject.)


    (LET* [(Plot (if (NULL OptionalPlotObject)
		     then (CREATEPLOT NIL NIL (QUOTE BoxPlot))
		   else OptionalPlotObject))
       (NumberOfBoxPlots (LENGTH ListOfLists))
       (BoxPlotNames (BOXPLOT.GETNAMES NumberOfBoxPlots 1 OptionalListOfBoxPlotNames))
       (BoxPlotData (for BoxPlotNumber from 1 to NumberOfBoxPlots as DataSet in ListOfLists
		       collect (BOXPLOT.CALCULATE Plot DataSet BoxPlotNumber]
      (BOXPLOT.INITIALIZE Plot NumberOfBoxPlots BoxPlotData BoxPlotNames)
      (for BoxPlotRecordItem in BoxPlotData as BoxPlotName in BoxPlotNames
	 do (BOXPLOT.MAKE Plot BoxPlotRecordItem BoxPlotName)
	 finally (REDRAWPLOTWINDOW Plot)
		 (RETURN Plot])

(BOXPLOT.CALCULATE
  [LAMBDA (Plot DataSet BoxPlotNumber)                       (* enk "16-Apr-86 16:35")
                                                             (* BOXPLOT.CALCULATE calculates all necessary BoxPlot 
							     information and packs it into a BoxPlotRecord which is 
							     accumulate by the calling function)
    (LET* ((Length (LENGTH DataSet))
       [SortedDataSet (MAKEARRAY Length (QUOTE INITIALCONTENTS)
				 (SORT DataSet (QUOTE LESSP]
       (Minimum (AREF SortedDataSet 0))
       (Maximum (AREF SortedDataSet (DIFFERENCE Length 1)))
       (DepthOfMedian (FIX (FQUOTIENT (FDIFFERENCE Length 1)
				      2.0)))
       (Median (if (ODDP Length)
		   then (AREF SortedDataSet DepthOfMedian)
		 else (FQUOTIENT (FPLUS (AREF SortedDataSet DepthOfMedian)
					(AREF SortedDataSet (PLUS DepthOfMedian 1)))
				 2.0)))
       (DepthOfLowerHinge (FQUOTIENT DepthOfMedian 2.0))
       [LowerHinge (LET ((IntegerDepthOfLowerHinge (FIX DepthOfLowerHinge)))
		     (if (EVENP DepthOfMedian)
			 then (AREF SortedDataSet IntegerDepthOfLowerHinge)
		       else (FQUOTIENT (FPLUS (AREF SortedDataSet IntegerDepthOfLowerHinge)
					      (AREF SortedDataSet (PLUS IntegerDepthOfLowerHinge 1)))
				       2.0]
       (DepthOfUpperHinge (FIX (FPLUS Length (MINUS DepthOfLowerHinge)
				      -1)))
       (UpperHinge (if (EVENP DepthOfMedian)
		       then (AREF SortedDataSet DepthOfUpperHinge)
		     else (FQUOTIENT (FPLUS (AREF SortedDataSet DepthOfUpperHinge)
					    (AREF SortedDataSet (PLUS DepthOfUpperHinge 1)))
				     2.0)))
       (HSpread (FDIFFERENCE UpperHinge LowerHinge))
       (LowerFence (FDIFFERENCE LowerHinge (FTIMES 1.5 HSpread)))
       (UpperFence (FPLUS UpperHinge (FTIMES 1.5 HSpread)))
       (LeftExtreme (FDIFFERENCE BoxPlotNumber .25))
       (RightExtreme (FPLUS BoxPlotNumber .25))
       (Middle BoxPlotNumber)
       (LeftMarker (FDIFFERENCE BoxPlotNumber .05))
       (RightMarker (FPLUS BoxPlotNumber .05)))
      (create BoxPlotRecord
	      Minimum ← Minimum
	      Maximum ← Maximum
	      BoxPlotNumber ← BoxPlotNumber
	      Median ← Median
	      LowerHinge ← LowerHinge
	      UpperHinge ← UpperHinge
	      LowerFence ← LowerFence
	      UpperFence ← UpperFence
	      LeftExtreme ← LeftExtreme
	      RightExtreme ← RightExtreme
	      Middle ← Middle
	      LeftMarker ← LeftMarker
	      RightMarker ← RightMarker
	      SortedDataSet ← SortedDataSet
	      Length ← Length])

(BOXPLOT.GETNAMES
  [LAMBDA (TotalNumberOfBoxPlots BoxPlotCounter ListOfBoxPlotNames)
                                                             (* enk "17-Apr-86 16:39")
    (if (GREATERP BoxPlotCounter TotalNumberOfBoxPlots)
	then NIL
      elseif (NULL ListOfBoxPlotNames)
	then (CONS (CONCAT "DataSet" (MKSTRING BoxPlotCounter))
		   (BOXPLOT.GETNAMES TotalNumberOfBoxPlots (PLUS BoxPlotCounter 1)))
      else (CONS (CAR ListOfBoxPlotNames)
		 (BOXPLOT.GETNAMES TotalNumberOfBoxPlots (PLUS BoxPlotCounter 1)
				   (CDR ListOfBoxPlotNames])

(BOXPLOT.INITIALIZE
  [LAMBDA (Plot NumberOfBoxPlots BoxPlotData BoxPlotNames)   (* enk "17-Apr-86 15:46")

          (* BOXPLOT.INITIALIZE calculates the extent of the BoxPlot and sets the interval of the X and Y axes.
	  It also creates two dummy points in the lower-left and upper-right hand corner of the BoxPlot to prevent a rescale 
	  function from making the BoxPlot ugly.)


    (LET* ([MinimumY (fetch (BoxPlotRecord Minimum) of (for BoxPlotItem in BoxPlotData
							  smallest (fetch (BoxPlotRecord Minimum)
								      of BoxPlotItem]
       [MaximumY (fetch (BoxPlotRecord Maximum) of (for BoxPlotItem in BoxPlotData
						      largest (fetch (BoxPlotRecord Maximum)
								 of BoxPlotItem]
       (ModifyY (TIMES (DIFFERENCE MaximumY MinimumY)
		       .05))
       (RelativeMinimumY (DIFFERENCE MinimumY ModifyY))
       (RelativeMaximumY (PLUS MaximumY ModifyY)))           (* The following block sets the extent of the X-axis.)
      (PLOTAXISINTERVAL Plot (QUOTE X)
			(CHOOSESCALE 0.0 NumberOfBoxPlots)
			T)                                   (* The following block sets the extent of the Y-axis.)
      (PLOTAXISINTERVAL Plot (QUOTE Y)
			(CHOOSESCALE RelativeMinimumY RelativeMaximumY)
			T)
      (PLOTTICS Plot (QUOTE LEFT)
		(QUOTE BOTH)
		T)
      (PLOTTICS Plot (QUOTE BOTTOM)
		(QUOTE BOTH)
		T)
      (PLOTTICMETHOD Plot (QUOTE BOTTOM)
		     (for I from 1 to NumberOfBoxPlots as BoxPlotName in BoxPlotNames
			collect (CONS I BoxPlotName))
		     T)                                      (* The following two blocks create the dummy points.)
      (PLOTPOINT Plot (create POSITION
			      XCOORD ← 0
			      YCOORD ← RelativeMinimumY)
		 NIL CIRCLE NIL T)
      (PLOTPOINT Plot (create POSITION
			      XCOORD ←(PLUS NumberOfBoxPlots 1)
			      YCOORD ← RelativeMaximumY)
		 NIL CIRCLE NIL T)
      NIL])

(BOXPLOT.MAKE
  [LAMBDA (Plot BoxPlotRecordItem BoxPlotName)               (* enk "17-Apr-86 14:58")
    (LET ((BoxPlotNumber (fetch BoxPlotNumber BoxPlotRecordItem))
       (Median (fetch Median BoxPlotRecordItem))
       (LowerHinge (fetch LowerHinge BoxPlotRecordItem))
       (UpperHinge (fetch UpperHinge BoxPlotRecordItem))
       (LowerFence (fetch LowerFence BoxPlotRecordItem))
       (UpperFence (fetch UpperFence BoxPlotRecordItem))
       (LeftExtreme (fetch LeftExtreme BoxPlotRecordItem))
       (RightExtreme (fetch RightExtreme BoxPlotRecordItem))
       (Middle (fetch Middle BoxPlotRecordItem))
       (LeftMarker (fetch LeftMarker BoxPlotRecordItem))
       (RightMarker (fetch RightMarker BoxPlotRecordItem))
       (SortedDataSet (fetch SortedDataSet BoxPlotRecordItem))
       (Length (fetch Length BoxPlotRecordItem)))            (* The following block creates the Median)
      (PLOTCURVE Plot (LIST (create POSITION
				    XCOORD ← LeftExtreme
				    YCOORD ← Median)
			    (create POSITION
				    XCOORD ← RightExtreme
				    YCOORD ← Median))
		 (LIST BoxPlotName (LIST (QUOTE Median:)
					 Median))
		 3 NIL T)                                    (* The following 2 blocks create the sides of the box)
      (PLOTCURVE Plot (LIST (create POSITION
				    XCOORD ← LeftExtreme
				    YCOORD ← LowerHinge)
			    (create POSITION
				    XCOORD ← LeftExtreme
				    YCOORD ← UpperHinge))
		 NIL 2 NIL T)
      (PLOTCURVE Plot (LIST (create POSITION
				    XCOORD ← RightExtreme
				    YCOORD ← LowerHinge)
			    (create POSITION
				    XCOORD ← RightExtreme
				    YCOORD ← UpperHinge))
		 NIL 2 NIL T)                                (* The following block creates the UpperHinge)
      (PLOTCURVE Plot (LIST (create POSITION
				    XCOORD ← LeftExtreme
				    YCOORD ← UpperHinge)
			    (create POSITION
				    XCOORD ← RightExtreme
				    YCOORD ← UpperHinge))
		 (LIST BoxPlotName (LIST (QUOTE UpperHinge:)
					 UpperHinge))
		 2 NIL T)                                    (* The following block creates the LowerHinge)
      (PLOTCURVE Plot (LIST (create POSITION
				    XCOORD ← LeftExtreme
				    YCOORD ← LowerHinge)
			    (create POSITION
				    XCOORD ← RightExtreme
				    YCOORD ← LowerHinge))
		 (LIST BoxPlotName (LIST (QUOTE LowerHinge:)
					 LowerHinge))
		 2 NIL T)                                    (* The following block finds and creates the 
							     UpperAdjacentValue, the LowerAdjacentValue, and all 
							     Outliers)
      (bind (LowerAdjacentValue ← NIL)
	    (UpperAdjacentValue ← NIL)
	    (NOVBLAVALH ← 0)
	    (NOVBUHAUAV ← 0) for X from 0 to (DIFFERENCE Length 1)
	 do (LET ((ADataItem (AREF SortedDataSet X)))
	      (if (OR (GREATERP ADataItem UpperFence)
		      (LESSP ADataItem LowerFence))
		  then (PLOTPOINT Plot (create POSITION
					       XCOORD ← Middle
					       YCOORD ← ADataItem)
				  (LIST BoxPlotName (LIST (QUOTE Outlier:)
							  ADataItem))
				  CIRCLE NIL T)
		else (if (NULL UpperAdjacentValue)
			 then (SETQ LowerAdjacentValue ADataItem))
		     (if (LESSP ADataItem LowerHinge)
			 then (SETQ NOVBLAVALH (ADD1 NOVBLAVALH))
		       elseif (GREATERP ADataItem UpperHinge)
			 then (SETQ NOVBUHAUAV (ADD1 NOVBUHAUAV)))
		     (SETQ UpperAdjacentValue ADataItem)))
	 finally (PLOTCURVE Plot (LIST (create POSITION
					       XCOORD ← LeftMarker
					       YCOORD ← LowerAdjacentValue)
				       (create POSITION
					       XCOORD ← RightMarker
					       YCOORD ← LowerAdjacentValue))
			    (LIST BoxPlotName (LIST (QUOTE LowerAdjacentValue:)
						    LowerAdjacentValue))
			    1 NIL T)
		 (PLOTCURVE Plot (LIST (create POSITION
					       XCOORD ← Middle
					       YCOORD ← LowerAdjacentValue)
				       (create POSITION
					       XCOORD ← Middle
					       YCOORD ← LowerHinge))
			    (LIST BoxPlotName (LIST (QUOTE ValuesWithin:)
						    (DIFFERENCE NOVBLAVALH 1)))
			    1 NIL T)
		 (PLOTCURVE Plot (LIST (create POSITION
					       XCOORD ← LeftMarker
					       YCOORD ← UpperAdjacentValue)
				       (create POSITION
					       XCOORD ← RightMarker
					       YCOORD ← UpperAdjacentValue))
			    (LIST BoxPlotName (LIST (QUOTE UpperAdjacentValue:)
						    UpperAdjacentValue))
			    1 NIL T)
		 (PLOTCURVE Plot (LIST (create POSITION
					       XCOORD ← Middle
					       YCOORD ← UpperAdjacentValue)
				       (create POSITION
					       XCOORD ← Middle
					       YCOORD ← UpperHinge))
			    (LIST BoxPlotName (LIST (QUOTE ValuesWithin:)
						    (DIFFERENCE NOVBUHAUAV 1)))
			    1 NIL T)))
    NIL])

(LISTMAX
  [LAMBDA (List)                                             (* enk "15-Apr-86 16:07")
    (if (NULL List)
	then MIN.FLOAT
      else (MAX (CAR List)
		(LISTMAX (CDR List])

(LISTMIN
  [LAMBDA (List)                                             (* enk "15-Apr-86 16:06")
    (if (NULL List)
	then MAX.FLOAT
      else (MIN (CAR List)
		(LISTMIN (CDR List])
)
(PUTPROPS BOXPLOT COPYRIGHT ("Massachusetts Institute of Technology" 1986))
STOP