[CM] gnuplot (was: Pest Question?)
Torsten Anders
t.anders at nici.kun.nl
Fri Jun 14 08:14:47 PDT 2002
Attached is a somewhat evolved version of my interface to gnuplot. I also
added examples and explaination.
I just found out: there exists a more elaborated lisp->gnuplot as a part of
CLLIB (which is now part of CLOCC) at http://clocc.sourceforge.net
Anyway, I assume my attempt is more easy to use, partly because it is so
tiny. But I also simplify matters: the user does not need to know the details
of gnuplot (e.g. specifying a 'z' coordinate always results in a 3D plot).
Although, therefore some gnuplot features can not be used (e.g. certain line
styles need more parameter and therefore can no be used).
On Thursday 13 June 2002 18:33, you wrote:
> also cm should have a SHELL call defined
> for all lisps, ill check
Sure the definition of SHELL should go somewhere else. I only placed it in
the file for easy testing (I wrote the core of this years ago, didn't check
whether CM2 also includes such a function...).
> > BTW, there is a gnuplot port for the Mac + Win too.
> please send me urls to these!
main gnuplot site:
http://www.gnuplot.info/
at sourceforge:
http://sourceforge.net/projects/gnuplot/
port for Macintosh:
http://homepage.mac.com/gnuplot/
port for dos and windows (probably not the only one...):
http://archives.math.utk.edu/software/multi-platform/gnuplot/msdos/
front end (surely not the only one):
http://www.flash.net/~dmishee/xgfe/xgfe.html
emacs mode (!?!):
http://feff.phys.washington.edu/~ravel/software/gnuplot-mode/Welcome.html
-------------- next part --------------
;;;
;;; The function 'plot' is an interface to gnuplot.
;;; Very little error checking (would cost performance, esp. for large lists)
;;;
;;; No performance enhancement, but seems to be OK.
;;; (take 1-1.5 sec for 2000 points to compute, scales linear,
;;; messured on a Celeron 333 running CMU in SuSE 7.3)
;;;
;;; copyright 2002 by Torsten Anders
;;; anders at uni-weimar.de
;;;
#| ; tests / doc
(plot '(0 5 3 4)) ; simple plot
(plot '(1 2 3 4) :style "impulses") ; line style
(plot '(1 2 3 4) :x '(0.1 0.5 2 2.1)) ; x and y given
(plot '(1 2 3 4) ; 3D plot
:x '(0.1 0.5 2 2.1)
:z '(0.5 3 2 -1)
:style "lines")
(plot '((1 5 3) (4 6 0))) ; multiple plots
(plot '((1 5 3) (4 6 0)) ; multiple line styles
:style '("points" "linespoints"))
(plot '((1 5 3) (4 6 0)) ; multiple 3D plots
:x '((1 2 1.5) (1 7 6))
:z '((0 1 4) (0 3 2)))
(plot '(0 5 3 4) ; additional settings (out to ps file)
:set '("title 'test'"
"output '/home/to/plot.ps'"
"terminal postscript"))
--> all doc following is quoted from doc of gnuplot, see that for (much) more info <--
;; some styles (all styles using 2 (2D) or 3 (3D) parameters) can be used)
"lines" The `lines` style connects adjacent points with straight line segments.
"points" The `points` style displays a small symbol at each point. (:set "pointsize <number>" may be used to change the size of the points)
"linespoints" The `linespoints` style does both `lines` and `points`, that is, it draws a small symbol at each point and then connects adjacent points with straight line segments. `linespoints` may be abbreviated `lp`. (:set "pointsize <number>" may be used to change the size of the points).
"impulses" The `impulses` style displays a vertical line from the x axis (not the graph border), or from the grid base in a 3D plot, to each point.
"dots" The `dots` style plots a tiny dot at each point -- this is useful for scatter plots with many points.
"steps" The `steps` style is only relevant to 2-d plotting. It connects consecutive points with two line segments: the first from (x1,y1) to (x2,y1) and the
second from (x2,y1) to (x2,y2).
"boxes" The `boxes` style is only relevant to 2-d plotting. It draws a box centered about the given x coordinate from the x axis (not the graph border) to the given y coordinate.
;; additional style settings
(plot '(1 2 3 4) :style "linespoints linetype 1 linewidth 1.5 pointtype 3 pointsize 3")
;; same with short hands
(plot '(1 2 3 4) :style "linesp lt 1 lw 1.5 pt 3 ps 3")
;; title for graphs
(plot '(1 2 3 4) :title "test")
(plot '((1 2 3 4) (2 3 4 5)) :title '("test1" "test2"))
;; further settings
The `set` command of gnuplot can be used to sets _lots_ of options.
;; output type
"terminal <val>" sets what kind of output to generate, many formats are supported, e.g.:
x11 X11 Window System
aifm Adobe Illustrator 3.0 Format
corel EPS format for CorelDRAW
fig FIG 3.1 graphics language: can be edited by xfig graphics editor
mif Frame maker MIF 3.00 format
postscript PostScript graphics language
latex LaTeX picture environment
[further special Tex/LaTeX environments]
[many special printer formats]
;; output file
"output '<filename>'" output file
(plot '(0 5 3 4)
:set '("output '/home/to/plot.ps'"
"terminal postscript"))
;; title
"title '<title>'" title of whole plot
(plot '(0 5 3 4) :set '("title 'test'"))
;; view
"view <rot_x> {,{<rot_z>}{,{<scale>}{,<scale_z>}}}" sets the viewing angle for 3D plots, where <rot_x> and <rot_z> control the rotation angles (in degrees). <rot_x> is bounded to the [0:180] range with a default of 60 degrees, while <rot_z> is bounded to the [0:360] range with a default of 30 degrees. <scale> controls the scaling of the entire `splot`, while <scale_z> scales the z axis only. Both scales default to 1.0.
(plot '(0 1 5) :x '(0 1 2) :z '(0 5 1) :set '("view 120, 30, 1, 1"))
|#
(defun plot (y &key x z (style "linespoints") set title
(data-file "/tmp/gnuplot_daten")
(command-file "/tmp/gnuplot_command"))
"Generates script and data file for gnuplot and calls gnuplot with these files.
Coordinates (i.e. x, y, and z) may be either a list of numbers (for a single plot) or a list of lists (for multiple plots) -- the nesting of all lists should be the same. Specifying z results in a 3D plot. style (sets the lines style) expects either a single string for all or a list of styles with a new value for every plot. set expects a list of strings describing arbitrary additional settings to gnuplot (without the leading 'set').
data-file gives the beginning of the data file names (every plot is written to an own data file). command-file is the name of the command file."
(let* ((plot-cmd (if z "splot" "plot")) ; 2D or 3D ?
(data-files ; write-string-to-file returns filename
(loop for d in (combine-coordinates x y z)
for i from 1
collect (write-string-to-file
(make-lines d)
(format nil "~a~a" data-file i))))
(l (length data-files))
(titles (if title
(listify title l)
(loop for i from 1 to l
collect (format NIL "data~A" i))))
(styles (listify style l))
(plots ; strings for every plot
(mapcar #'(lambda (data title style)
(format NIL " '~A' title '~A' with ~A"
data title style))
data-files titles styles))
(settings (format NIL "~{set ~a~%~}" set)))
(write-string-to-file
(format nil "~a~a ~a ~{, ~a~} ; pause -1 'Hit return to continue' ~%"
settings plot-cmd
(first plots) (rest plots)) ; to put commata at correct position
command-file))
(shell (format nil "xterm -e gnuplot ~a &" command-file)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; utils
;;;
(defun make-lines (data)
"Writes each sublist of data in an own line"
(format NIL "~{~{~,7F ~}~%~}" data))
; (make-lines '((0 1) (0.2 2) (1 3) (5 4)))
(defun combine-coordinates (x y z)
"Combines the lists of x (and possibly y and z) coordinates into a list of the form (((x1 y1 z1) ...) [(<coors for second plot>) ...]). Both x or z may be NIL."
(when (and z (or (not x) (not y)))
(error "z can not be given without x or y."))
(flet ((prepare (x y z) (remove NIL (list x y z))))
(if (listp (first y)) ; checks only first element !!
(apply #'mapcar #'(lambda (xx &optional yy zz)
;(print (list xx yy zz))
(mat-trans (prepare xx yy zz)))
(prepare x y z))
(list (mat-trans (prepare x y z))))))
; (combine-coordinates '(1 2 3) NIL NIL)
; (combine-coordinates '(1 2 3) '(a b c) NIL)
; (combine-coordinates '((1 2 3) (5 6 7)) '((a b c) (x y z)) NIL)
(defun write-string-to-file (string out-file)
"Writes (or overwrites) string into out-file and returns out-file."
(with-open-file (out-stream out-file
:direction :output
:if-exists :supersede)
(format out-stream string))
out-file)
;; idea for mat-trans descends to PatchWork (but not code)
(defun mat-trans (in-list)
"Transforms a list of form ((a1 a2 a3) (b1 b2 b3) (c1 c2 c3) ...) into ((a1 b1 c1 ...) (a2 b2 c2 ...) (a3 b3 c3 ...))."
(apply #'mapcar #'(lambda (&rest all) all)
in-list))
(defun listify (x l)
(if (listp x)
x
(make-list l :initial-element x)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; quote (should be defined elsewhere for [hopefully] every platform)
;;; modified version of 'shell' in CM1 by Heinrich Taube
;;; for support of other Lisp platforms see "impl.lisp"
#+CMU
(defun shell (string &key (wait T) (output T))
"'Evaluates' string in /bin/sh and outputs result on *standard-output*. Start a child process and does not wait until process is finished. Therefore output of process may be mixed in outputs of other programm..."
(unwind-protect
(let* ((process (ext:run-program "/bin/sh" (list "-c" string)
:output output
:wait wait)))
(ext:process-close process)
process)))
More information about the Cmdist
mailing list