Psych 285: Computational Statistics
and Statistical Visualization

Professor Forrest Young

ViSta Model Object Programming Example


To understand the examples presented here, you need to have Chapter 14 of the ViSta user's guide. This chapter is available as a Adobe Acrobat file, for which you need the Adobe Acrobat Reader. The chapter describes how to extend ViSta by adding new model objects. While it describes an earlier release of ViSta and is somewhat out of date, it is still accurate in general, and most details have not changed.

The code presented here is completely up-to-date and accurate, whereas the older code example in Chapter 14 is not. Until Chapter 14 is updated, I recommend that you compare the example in Chapter 14 with the examples presented here, and with the code in the pcamob.lsp file that comes with the program distribution.


Example 1: A simple ViSta regression model object.

This example show how to write a ViSta model object that uses an already existing XLispStat object. In this example a very simple model object is written to do univariate regression. It uses Luke Tierney's regression-model object to do the actual work. Thus, this example shows how to construct a ViSta model object that acts as an interface to the underlying XLS system.
  1. Define prototype and its slots
    (defproto reg-model-proto '(reg-object response predictors) () 
      mv-model-object-proto)
    
  2. Define slot accessor methods
    (defmeth reg-model-proto  :reg-object (&optional (object-id nil set))
      (if set (setf (slot-value 'reg-object) object-id))
      (slot-value 'reg-object))
    
    (defmeth reg-model-proto  :response (&optional (vector nil set))
      (if set (setf (slot-value 'response) vector))
      (slot-value 'response))
    
    (defmeth reg-model-proto  :predictors (&optional (matrix nil set))
      (if set (setf (slot-value 'predictors) matrix))
      (slot-value 'predictors))
    
  3. Define ViSta system methods
    (defmeth reg-model-proto  :analysis () 
      (let* ((response (send self :response))
             (predictors (send self :predictors))
             (object (regression-model predictors response :print nil))
             )
        (send self :reg-object object)
        t))
    
    (defmeth reg-model-proto :report (&key (dialog nil))
      (send (send self :reg-object) :display))
    
    (defmeth reg-model-proto :visualize ()
        (send (send self :reg-object) :plot-bayes-residuals))
    
    
  4. Define object-specific non-system methods
    (none)
    
  5. Define the isnew method
    (defmeth reg-model-proto :isnew (response predictors &rest args)
      (when (or (< (send *current-data* :active-nvar '(numeric)) 2)
                (< (send *current-data* :active-nobs) 4))
            (fatal-message "The minimum size data is 2 numeric variables and 4 observations"))
      (send self :model-abbrev "REG")
      (send self :response (send *current-data* :variable response))
      (send self :predictors (apply #'bind-columns 
                 (map-elements #'send *current-data* :variable predictors)))
      (apply #'call-next-method args))
    
  6. Define the object constructor function
    (defun reg 
      (&key
       (data *current-data*)
       (title "Linear Regression")
       (name (strcat "REG-" (send *current-data* :name)))
       (dialog nil)
       (response nil)
       (predictors nil))
      (if (not (eq *current-data* data)) (setcd data))
      (send reg-model-proto :new response predictors 0 data title name dialog))
    
  7. Test the code
    (load "abrasion")
    (reg :response "Abrasion-Loss" 
         :predictors '("Hardness" "Tensile-Strength"))
    

    Example 2: A simple ViSta Summary Statistics model object.

    The second example shows how to write DESCRIBE-MODEL-PROTO, a prototype ViSta model object which takes a multivariate data matrix and calculates simple statistics (moments and quartiles) for the active numeric variables in the current data.

    The code is tested by creating instances of the object using various ViSta data objects. These results can be compared to the Data menu's Summarize Data item.


    1. Define prototype and its slots
      (defproto describe-model-proto '(moments quartiles) () 
           mv-model-object-proto)
      
    2. Define slot accessor methods
      (defmeth describe-model-proto  :moments (&optional (values nil set))
      "Slot-Accessor method"
        (if set (setf (slot-value 'moments) values))
        (slot-value 'moments))
       
      (defmeth describe-model-proto  :quartiles (&optional (values nil set))
      "Slot-Accessor method"
        (if set (setf (slot-value 'quartiles) values))
        (slot-value 'quartiles))
      
    3. Define ViSta system methods
      (defmeth describe-model-proto  :options ()
        )
      
      (defmeth describe-model-proto  :analysis () 
        (let ((means (send self :means))
              (stdvs (send self :standard-deviations))
              (varis (send self :variances))
              (skews (send self :skewnesses))
              (kurts (send self :kurtoses))
              (5nums (mapcar #'fivnum 
                             (column-list 
                              (send self :active-data-matrix '(numeric))))))
          (send self :moments (list means stdvs varis skews kurts))
          (send self :quartiles 5nums))
        t)
      
      (defmeth describe-model-proto :report (&key (dialog nil))
        (if (not (eq current-object self)) (setcm self))
        (let ((numeric-vars (send self :active-variables '(numeric)))
              (moments-mat (apply #'bind-columns (send self :moments)))
              (fivenum-mat (apply #'bind-rows (send self :quartiles)))
              (w (report-header (send self :title)))
              )
          (display-string (format nil "Summary Statistics") w)
          (display-string (format nil "~2%Moments") w)
          (display-string (format nil "~%Means, Standard Deviations, Variances, Skewnesses & Kurtoses~%") w)
          (print-matrix-to-window moments-mat w :labels numeric-vars :decimals 3)
          (display-string (format nil "~2%Five Number Summary") w)
          (display-string (format nil "~%Minimum, 1st Quartile, Median, 3rd Quartile, Maximum~%") w)
          (print-matrix-to-window fivenum-mat w :labels numeric-vars :decimals 3)
          )
        t)
      
      (defmeth describe-model-proto :visualize ()
      "Method args: none
      Plots the data. Produces histogram, scatterplot, spin-plot or scatterplot matrix, depending on the number of variables in the data."
        (let* ((data (send self :active-data-matrix '(numeric)))
               (title (send self :title))
               (nvars (second (array-dimensions data))))
          (cond
            ((= nvars 1) (histogram (column-list data) :title title))
            ((= nvars 2) (plot-points (column-list data) :title title))
            ((= nvars 3) (spin-plot (column-list data) :title title))
            ((and (> nvars 3) (< nvars 10))
             (spread-plot 
              (matrix '(1 2)
                      (list
                       (scatterplot-matrix (column-list data) :title title)
                       (spin-plot (column-list data) :title title)))
              :model self))
            (t (error "Too Many Variables")))))
      
    4. Define object-specific non-system methods
      ;(none for this example)
      
    5. Define ISNEW method
      (defmeth describe-model-proto :isnew (&rest args)
        (when (or (< (send *current-data* :active-nvar '(numeric)) 1)
                  (< (send *current-data* :active-nobs) 4))
              (error "The minimum size data is one variable and 4 observations"))
        (send self :model-abbrev "STS")
        (apply #'call-next-method args))
      
    6. Define constructor function
      (defun describe-data 
        (&key
         (data *current-data*)
         (title "Data Summary Statistics")
         (name (strcat "STS-" (send *current-data* :name)))
         (dialog nil))
        (if (not (eq *current-data* data)) (setcd data))
        (send describe-model-proto :new 0 data title name dialog))
      

      Test it out

      (load (strcat *vista-dir-name* "sprdplt1"))
      (load-data (strcat *data-dir-name* "cars"))
      (describe-data)
      (report-model)
      (visualize-model)
      


    To get in touch:

    email: forrest@unc.edu
    WWW: http://forrest.psych.unc.edu