From: Francogrex
Subject: Simple plot of points
Date: 
Message-ID: <1a67599e-5357-4996-88e3-00c75623aacf@l16g2000pra.googlegroups.com>
Hi, I've started with this but got stuck at the plot. I'm trying to
print a simple plot with probably * as points (the val-x/val-y points
below) on a grid of 9 to 9 points. Not using CLOS or anything. Is it
possible? I only managed to print a lame version of the x and y axis.

;;Some values
(setf x (list 1 2 2 2 3 4 5 5 6 7 7 8 9 8 7 7 6 5 5))
(setf x (sort x #'<))

(defmacro unique (val lst)
  `(setf ,val (remove-duplicates ,lst :test #'equal)))

;;Select bins as unique values
(unique bins x)

;;Define the empirical cumulative distribution:
(setf ecdf (loop for i in bins collect
		 (list i (/ (count i x :test #'>=) (length x) 1.0))))

;;The points with val-x and val-y coordinates
(setf val-x (mapcar #'car ecdf))
(setf val-y (mapcar #'cadr ecdf))

;;Lame attempt at a plot, still needs to add the points at the right
place in it:
(with-open-file (str "c:/lispGraph.doc" :direction :output)
		(format str "~{~a~%~%~%~}" (loop for i from 9 downto 1 collect i))
		(format str "~{~a     ~}" (loop for i from 0 to 9 collect i)))

From: GP lisper
Subject: Re: Simple plot of points
Date: 
Message-ID: <slrngvacjk.o8t.spambait@phoenix.clouddancer.com>
On Sun, 26 Apr 2009 14:43:06 -0700 (PDT), <······@grex.org> wrote:
>
> Hi, I've started with this but got stuck at the plot. I'm trying to
> print a simple plot with probably * as points (the val-x/val-y points
> below) on a grid of 9 to 9 points. Not using CLOS or anything. Is it
> possible? I only managed to print a lame version of the x and y axis.


I use the following, and just tinker a couple of functions at the top
Gnuplot is a handy solution, since you have a ton of options available
and don't need to mess with axis values, etc.  Yup, it's CLOS, but
it's boilerplate, look at the ml-rl-plot function.



(require :clsql)
(clsql-user:connect '("localhost" "fee" "fie" "foo") :if-exists :old :database-type :mysql)   <- just where this example got it's data
(clsql-user:locally-enable-sql-reader-syntax)
; (clsql:start-sql-recording)  (clsql:stop-sql-recording)

(unless (packagep (find-package :plotit))  (make-package :plotit))
(in-package :plotit)

;;;;;;;;;;;;;;;;;;;   globals

(defun fixit (foo)  "fix int+string"    <- fixing an artifact in the data
       (let ( (ml (car foo)) (rl (read-from-string (cadr foo))) )	 (list ml rl)))

(defun ml-rl()  "ML vs RL data"
       (clsql:select [ml] [rln] :from [line] :where [and [<> [rln] " "] [<> [win] "tbd"]] :field-names nil))


(defun ml-rl-plot ()  "heavy lifting"
  (let ( (series (make-series-2d (mapcar #'fixit (ml-rl))))
	 (plot (make-plot)) )

    (plot-add-series plot series
                     :style  "points"
                     :title  ""
                     :axes   "x1y1")

    (plot-title plot "ML v RL")
    (plot-xlabel plot "ML")
    (plot-ylabel plot "RL")
    (plot-draw plot)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ripped from Ryan cl-gnuplot

(defstruct series-format
  style
  title
  smooth
  axes)

;;; SERIES-2D CLASS
(defclass series-2d ()
  ( (data :initarg :data) )
  (:documentation "A class for managing data to be plotted with gnuplot."))

;;; PLOT CLASS
(defclass plot ()
  ((series    :initform ()
              :allocation :instance)
   (seriesf   :initform (make-hash-table))
   
   (title     :initform nil)
   (xlabel    :initform nil)
   (x2label   :initform nil)
   (ylabel    :initform nil)
   (y2label   :initform nil)
   
   (process   :initform (extensions:run-program
                         "gnuplot"        ; program to run
                         nil              ; no arguments
                         :wait   nil      ; wait for child
                         :pty    nil      ; no terminal
                         :input  :stream  ; need an input stream
                         :error  :output  ; print to stdout for debugging
                         :output t)       ; print to stdout for debugging
              :allocation :instance)   
   (stream    :initform nil))
  (:documentation
   "A class for plotting data with gnuplot."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun string-join (delimiter strings)
  (format nil (format nil "~~{~~a~~^~a~~}" delimiter) strings))

(defun make-plot ()  (make-instance 'plot))

(defun make-series-2d (data)
  (make-instance 'series-2d :data data))

(defgeneric plot-add-series (plot series-2d &key))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmethod plot-title ((p plot) &optional value)
  (unless (null value)
    (setf (slot-value p 'title) value)
    (format (slot-value p 'stream) "set title \"~a\"~%" value))
  (slot-value p 'title))

(defmethod plot-xlabel ((p plot) &optional value)
  (unless (null value)
    (setf (slot-value p 'xlabel) value)
    (format (slot-value p 'stream) "set xlabel \"~a\"~%" value))
  (slot-value p 'xlabel))

(defmethod plot-x2label ((p plot) &optional value)
  (unless (null value)
    (setf (slot-value p 'x2label) value)
    (format (slot-value p 'stream) "set x2label \"~a\"~%" value))
  (slot-value p 'x2label))

(defmethod plot-ylabel ((p plot) &optional value)
  (unless (null value)
    (setf (slot-value p 'ylabel) value)
    (format (slot-value p 'stream) "set ylabel \"~a\"~%" value))
  (slot-value p 'ylabel))

(defmethod plot-y2label ((p plot) &optional value)
  (unless (null value)
    (setf (slot-value p 'y2label) value)
    (format (slot-value p 'stream) "set y2label \"~a\"~%" value))
  (slot-value p 'y2label))

(defmethod initialize-instance :after ((plt plot) &key)
  (setf (slot-value plt 'stream)
        (extensions:process-input (slot-value plt 'process))))

(defmethod plot-close ((plt plot))  (extensions:process-close (slot-value plt 'process)))

(defmethod plot-cmd ((plt plot) command)  (format (slot-value plt 'stream) "~a~%" command))

(defmethod plot-draw ((plt plot))
  (let ((plot-string ()))
    (dolist (subplot (slot-value plt 'series))  ; Loop through the series, sending format information
      (let ((subplot-string '("'-'"))
            (sf (gethash subplot (slot-value plt 'seriesf))))
        (unless (null (series-format-axes sf))
          (push "axes" subplot-string)
          (push (series-format-axes sf) subplot-string))
        (unless (null (series-format-title sf))
          (push "title" subplot-string)
          (push (format nil "\"~a\"" (series-format-title sf))
                subplot-string))
        (unless (null (series-format-style sf))
          (push "with" subplot-string)
          (push (series-format-style sf) subplot-string))
        (unless (null (series-format-smooth sf))
          (push "smooth" subplot-string)
          (push (series-format-smooth sf) subplot-string))
        (push (string-join " " (reverse subplot-string)) plot-string)))

    (format (slot-value plt 'stream) "plot ~a~%"  (string-join ", " (reverse plot-string)))  ; Join our list of subplots and print them to the stream

    ; Loop through the series, sending the data
    (dolist (subplot (slot-value plt 'series))
      (dolist (line (slot-value subplot 'data))
        (format (slot-value plt 'stream) "~{~a~^ ~}~%" line))
      (format (slot-value plt 'stream) "e~%"))

    (force-output (slot-value plt 'stream))))  ; Make sure the plot string is written to the stream


(defmethod plot-add-series
    ((plt plot) (series series-2d) &key style title smooth axes)
  (push series (slot-value plt 'series))
  (let ((sf (make-series-format)))
    (setf (gethash series (slot-value plt 'seriesf)) sf)
    (unless (null style)  (setf (series-format-style  sf) style))
    (unless (null title)  (setf (series-format-title  sf) title))
    (unless (null axes)   (setf (series-format-axes   sf) axes))
    (unless (null smooth) (setf (series-format-smooth sf) smooth))))

(defmethod plot-remove-series
    ((p plot) (series series-2d))
  (remhash series (slot-value p 'seriesf))
  (setf (slot-value p 'series) (remove series (slot-value p 'series))))


-- 
Lisp:  Powering `Impossible Thoughts since 1958
From: Tamas K Papp
Subject: Re: Simple plot of points
Date: 
Message-ID: <75k453F18ruaeU1@mid.individual.net>
On Sun, 26 Apr 2009 14:43:06 -0700, Francogrex wrote:

> Hi, I've started with this but got stuck at the plot. I'm trying to
> print a simple plot with probably * as points (the val-x/val-y points
> below) on a grid of 9 to 9 points. Not using CLOS or anything. Is it
> possible? I only managed to print a lame version of the x and y axis.
> 
> ;;Some values
> (setf x (list 1 2 2 2 3 4 5 5 6 7 7 8 9 8 7 7 6 5 5)) (setf x (sort x
> #'<))
> 
> (defmacro unique (val lst)
>   `(setf ,val (remove-duplicates ,lst :test #'equal)))
> 
> ;;Select bins as unique values
> (unique bins x)
> 
> ;;Define the empirical cumulative distribution: (setf ecdf (loop for i
> in bins collect
> 		 (list i (/ (count i x :test #'>=) (length x) 1.0))))
> 
> ;;The points with val-x and val-y coordinates (setf val-x (mapcar #'car
> ecdf))
> (setf val-y (mapcar #'cadr ecdf))
> 
> ;;Lame attempt at a plot, still needs to add the points at the right
> place in it:
> (with-open-file (str "c:/lispGraph.doc" :direction :output)
> 		(format str "~{~a~%~%~%~}" (loop for i from 9 downto 1 collect i))
> 		(format str "~{~a     ~}" (loop for i from 0 to 9 collect i)))

I rewrote it in a more lispy style, and put some comments in it.
Hopefully pan (my newsreader) will not screw up the formatting.

;;Some values TP: use defparameter, not setf
(defparameter *x* (list 1 2 2 2 3 4 5 5 6 7 7 8 9 8 7 7 6 5 5))
(setf *x* (sort *x* #'<))

(let* (;;Select bins as unique values  TP: macro unnecessary, was bad style
       (bins (remove-duplicates *x* :test #'equal))
       ;; define the empirical cumulative distribution
       ;; TP: pointless to save bins again, you already have them
       (ecdf (loop for i in bins collect
		  (/ (count i *x* :test #'>=) (length *x*) 1.0)))
       (width 40)			; width of largest column
       (scale (/ width (apply #'max ecdf))))
       ;; plot, not sure what you want to do
  (with-open-file (str "/tmp/plot" :direction :output)
    (mapc #'(lambda (bin prob)		; yes, I hate loop :-)
	      (format str "~2d " bin)
	      (dotimes (i (round (* prob scale))) ; we scale to the screen
		(princ #\* str)) 	; points
	      (terpri str))	; newline
	  bins ecdf)))

Tamas
From: Pascal J. Bourguignon
Subject: Re: Simple plot of points
Date: 
Message-ID: <87ab63awow.fsf@galatea.local>
> Hi, I've started with this but got stuck at the plot. I'm trying to
> print a simple plot with probably * as points (the val-x/val-y points
> below) on a grid of 9 to 9 points. 

So you have grids of points.

(defstruct grid points)

and you want to plot points:

(defun plot (grid x y &optional (point '*))
    ...)

and you will probably want to display this grid once you've ploted the points:

(defun display (grid)
    ...)


Ok, how could we do that?  You say the grid has points with 2
coordinates.  We could use a 2D array of characters to store them.

(defstruct (grid (:constructor %make-grid)) points)

(defun make-grid (width height &optional (initial-point #\space))
   (%make-grid  :points (make-array (list width height)
                                    :element-type 'character
                                    :initial-element initial-point)))


Now you can plot in that:

(defun plot (grid x y &optional (point '*))
   (setf (aref (grid-points grid) (round x) (round y)) (character (string point)))
   grid)

and you can easily display it:

(defun display (grid)
  (loop
    :for y :from 0 :below (array-dimension (grid-points grid) 1)
    :do (loop
           :for x :from 0 :below (array-dimension (grid-points grid) 0)
           :do (princ (aref (grid-points grid) x y))
           :finally (terpri)))
  grid)



(let ((grid (make-grid 72 24)))
  (loop :for x :from 0 :below 72 :do (plot grid x 12 '-))
  (loop :for x :from 0 :below 72 :do (plot grid x (+ 12 (* 9 (sin (* 2 pi (/ x 72))))) '+)) 
  (display grid)
  (values))
                                                                        
                                                                        
                                                                        
                                                   +++++++              
                                                +++       +++           
                                              ++             ++         
                                            ++                 ++       
                                           +                     +      
                                         ++                       ++    
                                        +                           +   
                                      ++                             ++ 
                                     +                                 +
+-----------------------------------+-----------------------------------
 +                                 +                                    
  ++                             ++                                     
    +                           +                                       
     ++                       ++                                        
       +                     +                                          
        ++                 ++                                           
          ++             ++                                             
            +++       +++                                               
               +++++++                                                  
                                                                        

      

-- 
__Pascal Bourguignon__