Update maintainer's address.
[bpt/emacs.git] / lisp / calc / calc-graph.el
CommitLineData
3132f345
CW
1;;; calc-graph.el --- graph output functions for Calc
2
58ba2f8f 3;; Copyright (C) 1990, 1991, 1992, 1993, 2001, 2002, 2003, 2004,
f0fa15c5 4;; 2005, 2006, 2007 Free Software Foundation, Inc.
3132f345
CW
5
6;; Author: David Gillespie <daveg@synaptics.com>
e8fff8ed 7;; Maintainer: Jay Belanger <jay.p.belanger@gmail.com>
136211a9
EZ
8
9;; This file is part of GNU Emacs.
10
7c671b23
GM
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation; either version 2, or (at your option)
14;; any later version.
15
136211a9 16;; GNU Emacs is distributed in the hope that it will be useful,
7c671b23
GM
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to the
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
136211a9 25
3132f345 26;;; Commentary:
136211a9 27
3132f345 28;;; Code:
136211a9
EZ
29
30;; This file is autoloaded from calc-ext.el.
136211a9 31
808cd573 32(require 'calc-ext)
136211a9
EZ
33(require 'calc-macs)
34
808cd573
JB
35;;; Graphics
36
fa1c95df
JB
37;; The following three variables are customizable and defined in calc.el.
38(defvar calc-gnuplot-name)
39(defvar calc-gnuplot-plot-command)
40(defvar calc-gnuplot-print-command)
136211a9 41
2c37c14b 42(defvar calc-gnuplot-tempfile "calc")
136211a9 43
ac39a77c
JB
44(defvar calc-gnuplot-default-device)
45(defvar calc-gnuplot-default-output)
46(defvar calc-gnuplot-print-device)
47(defvar calc-gnuplot-print-output)
136211a9
EZ
48(defvar calc-gnuplot-keep-outfile nil)
49(defvar calc-gnuplot-version nil)
50
51(defvar calc-gnuplot-display (getenv "DISPLAY"))
ac39a77c 52(defvar calc-gnuplot-geometry)
136211a9 53
ac39a77c
JB
54(defvar calc-graph-default-resolution)
55(defvar calc-graph-default-resolution-3d)
136211a9
EZ
56(defvar calc-graph-default-precision 5)
57
58(defvar calc-gnuplot-buffer nil)
59(defvar calc-gnuplot-input nil)
60
61(defvar calc-gnuplot-last-error-pos 1)
62(defvar calc-graph-last-device nil)
63(defvar calc-graph-last-output nil)
64(defvar calc-graph-file-cache nil)
65(defvar calc-graph-var-cache nil)
66(defvar calc-graph-data-cache nil)
67(defvar calc-graph-data-cache-limit 10)
3132f345
CW
68(defvar calc-graph-no-auto-view nil)
69(defvar calc-graph-no-wait nil)
68d1b30d 70(defvar calc-gnuplot-trail-mark)
136211a9
EZ
71
72(defun calc-graph-fast (many)
73 (interactive "P")
74 (let ((calc-graph-no-auto-view t))
75 (calc-graph-delete t)
76 (calc-graph-add many)
bf77c646 77 (calc-graph-plot nil)))
136211a9
EZ
78
79(defun calc-graph-fast-3d (many)
80 (interactive "P")
81 (let ((calc-graph-no-auto-view t))
82 (calc-graph-delete t)
83 (calc-graph-add-3d many)
bf77c646 84 (calc-graph-plot nil)))
136211a9
EZ
85
86(defun calc-graph-delete (all)
87 (interactive "P")
88 (calc-wrapper
89 (calc-graph-init)
90 (save-excursion
91 (set-buffer calc-gnuplot-input)
92 (and (calc-graph-find-plot t all)
93 (progn
94 (if (looking-at "s?plot")
95 (progn
96 (setq calc-graph-var-cache nil)
97 (delete-region (point) (point-max)))
98 (delete-region (point) (1- (point-max)))))))
bf77c646 99 (calc-graph-view-commands)))
136211a9
EZ
100
101(defun calc-graph-find-plot (&optional before all)
102 (goto-char (point-min))
103 (and (re-search-forward "^s?plot[ \t]+" nil t)
104 (let ((beg (point)))
105 (goto-char (point-max))
106 (if (or all
107 (not (search-backward "," nil t))
108 (< (point) beg))
109 (progn
110 (goto-char beg)
111 (if before
112 (beginning-of-line)))
113 (or before
114 (re-search-forward ",[ \t]+")))
bf77c646 115 t)))
136211a9
EZ
116
117(defun calc-graph-add (many)
118 (interactive "P")
119 (calc-wrapper
120 (calc-graph-init)
121 (cond ((null many)
122 (calc-graph-add-curve (calc-graph-lookup (calc-top-n 2))
123 (calc-graph-lookup (calc-top-n 1))))
124 ((or (consp many) (eq many 0))
125 (let ((xdata (calc-graph-lookup (calc-top-n 2)))
126 (ylist (calc-top-n 1)))
127 (or (eq (car-safe ylist) 'vec)
128 (error "Y argument must be a vector"))
129 (while (setq ylist (cdr ylist))
130 (calc-graph-add-curve xdata (calc-graph-lookup (car ylist))))))
131 ((> (setq many (prefix-numeric-value many)) 0)
132 (let ((xdata (calc-graph-lookup (calc-top-n (1+ many)))))
133 (while (> many 0)
134 (calc-graph-add-curve xdata
135 (calc-graph-lookup (calc-top-n many)))
136 (setq many (1- many)))))
137 (t
138 (let (pair)
139 (setq many (- many))
140 (while (> many 0)
141 (setq pair (calc-top-n many))
142 (or (and (eq (car-safe pair) 'vec)
143 (= (length pair) 3))
144 (error "Argument must be an [x,y] vector"))
145 (calc-graph-add-curve (calc-graph-lookup (nth 1 pair))
146 (calc-graph-lookup (nth 2 pair)))
147 (setq many (1- many))))))
bf77c646 148 (calc-graph-view-commands)))
136211a9
EZ
149
150(defun calc-graph-add-3d (many)
151 (interactive "P")
152 (calc-wrapper
153 (calc-graph-init)
154 (cond ((null many)
155 (calc-graph-add-curve (calc-graph-lookup (calc-top-n 3))
156 (calc-graph-lookup (calc-top-n 2))
157 (calc-graph-lookup (calc-top-n 1))))
158 ((or (consp many) (eq many 0))
159 (let ((xdata (calc-graph-lookup (calc-top-n 3)))
160 (ydata (calc-graph-lookup (calc-top-n 2)))
161 (zlist (calc-top-n 1)))
162 (or (eq (car-safe zlist) 'vec)
163 (error "Z argument must be a vector"))
164 (while (setq zlist (cdr zlist))
165 (calc-graph-add-curve xdata ydata
166 (calc-graph-lookup (car zlist))))))
167 ((> (setq many (prefix-numeric-value many)) 0)
168 (let ((xdata (calc-graph-lookup (calc-top-n (+ many 2))))
169 (ydata (calc-graph-lookup (calc-top-n (+ many 1)))))
170 (while (> many 0)
171 (calc-graph-add-curve xdata ydata
172 (calc-graph-lookup (calc-top-n many)))
173 (setq many (1- many)))))
174 (t
175 (let (curve)
176 (setq many (- many))
177 (while (> many 0)
178 (setq curve (calc-top-n many))
179 (or (and (eq (car-safe curve) 'vec)
180 (= (length curve) 4))
181 (error "Argument must be an [x,y,z] vector"))
182 (calc-graph-add-curve (calc-graph-lookup (nth 1 curve))
183 (calc-graph-lookup (nth 2 curve))
184 (calc-graph-lookup (nth 3 curve)))
185 (setq many (1- many))))))
bf77c646 186 (calc-graph-view-commands)))
136211a9
EZ
187
188(defun calc-graph-add-curve (xdata ydata &optional zdata)
189 (let ((num (calc-graph-count-curves))
190 (pstyle (calc-var-value 'var-PointStyles))
191 (lstyle (calc-var-value 'var-LineStyles)))
192 (save-excursion
193 (set-buffer calc-gnuplot-input)
194 (goto-char (point-min))
195 (if (re-search-forward (if zdata "^plot[ \t]" "^splot[ \t]")
196 nil t)
197 (error "Can't mix 2d and 3d curves on one graph"))
198 (if (re-search-forward "^s?plot[ \t]" nil t)
199 (progn
200 (end-of-line)
201 (insert ", "))
202 (goto-char (point-max))
203 (or (eq (preceding-char) ?\n)
204 (insert "\n"))
205 (insert (if zdata "splot" "plot") " \n")
206 (forward-char -1))
207 (insert "{" (symbol-name (nth 1 xdata))
208 ":" (symbol-name (nth 1 ydata)))
209 (if zdata
210 (insert ":" (symbol-name (nth 1 zdata))))
211 (insert "} "
212 "title \"" (symbol-name (nth 1 ydata)) "\" "
213 "with dots")
214 (setq pstyle (and (eq (car-safe pstyle) 'vec) (nth (1+ num) pstyle)))
b8819825
JB
215 (setq lstyle (and (eq (car-safe lstyle) 'vec) (nth (1+ num) lstyle))))
216 (calc-graph-set-styles
217 (or (and (Math-num-integerp lstyle) (math-trunc lstyle))
218 0)
219 (or (and (Math-num-integerp pstyle) (math-trunc pstyle))
220 (if (eq (car-safe (calc-var-value (nth 2 ydata))) 'vec)
221 0 -1)))))
136211a9
EZ
222
223(defun calc-graph-lookup (thing)
224 (if (and (eq (car-safe thing) 'var)
225 (calc-var-value (nth 2 thing)))
226 thing
227 (let ((found (assoc thing calc-graph-var-cache)))
228 (or found
68d1b30d
JB
229 (let ((varname (concat "PlotData"
230 (int-to-string
231 (1+ (length calc-graph-var-cache))))))
232 (setq var (list 'var (intern varname)
136211a9
EZ
233 (intern (concat "var-" varname)))
234 found (cons thing var)
235 calc-graph-var-cache (cons found calc-graph-var-cache))
236 (set (nth 2 var) thing)))
bf77c646 237 (cdr found))))
136211a9
EZ
238
239(defun calc-graph-juggle (arg)
240 (interactive "p")
241 (calc-graph-init)
242 (save-excursion
243 (set-buffer calc-gnuplot-input)
244 (if (< arg 0)
245 (let ((num (calc-graph-count-curves)))
246 (if (> num 0)
247 (while (< arg 0)
248 (setq arg (+ arg num))))))
249 (while (>= (setq arg (1- arg)) 0)
bf77c646 250 (calc-graph-do-juggle))))
136211a9
EZ
251
252(defun calc-graph-count-curves ()
253 (save-excursion
254 (set-buffer calc-gnuplot-input)
255 (if (re-search-forward "^s?plot[ \t]" nil t)
256 (let ((num 1))
257 (goto-char (point-min))
258 (while (search-forward "," nil t)
259 (setq num (1+ num)))
260 num)
bf77c646 261 0)))
136211a9
EZ
262
263(defun calc-graph-do-juggle ()
264 (let (base)
265 (and (calc-graph-find-plot t t)
266 (progn
267 (setq base (point))
268 (calc-graph-find-plot t nil)
269 (or (eq base (point))
270 (let ((str (buffer-substring (+ (point) 2) (1- (point-max)))))
271 (delete-region (point) (1- (point-max)))
272 (goto-char (+ base 5))
bf77c646 273 (insert str ", ")))))))
136211a9
EZ
274
275(defun calc-graph-print (flag)
276 (interactive "P")
bf77c646 277 (calc-graph-plot flag t))
136211a9 278
68d1b30d
JB
279(defvar var-DUMMY)
280(defvar var-DUMMY2)
281(defvar var-PlotRejects)
282
283;; The following variables are local to calc-graph-plot, but are
284;; used in the functions calc-graph-compute-2d, calc-graph-refine-2d,
285;; calc-graph-recompute-2d, calc-graph-compute-3d and
286;; calc-graph-format-data, which are called by calc-graph-plot.
287(defvar calc-graph-yvalue)
288(defvar calc-graph-yvec)
289(defvar calc-graph-numsteps)
290(defvar calc-graph-numsteps3)
291(defvar calc-graph-xvalue)
292(defvar calc-graph-xvec)
293(defvar calc-graph-xname)
294(defvar calc-graph-yname)
295(defvar calc-graph-xstep)
296(defvar calc-graph-ycache)
297(defvar calc-graph-ycacheptr)
298(defvar calc-graph-refine)
299(defvar calc-graph-keep-file)
300(defvar calc-graph-xval)
301(defvar calc-graph-xlow)
302(defvar calc-graph-xhigh)
303(defvar calc-graph-yval)
304(defvar calc-graph-yp)
305(defvar calc-graph-xp)
306(defvar calc-graph-zp)
307(defvar calc-graph-yvector)
308(defvar calc-graph-resolution)
309(defvar calc-graph-y3value)
310(defvar calc-graph-y3name)
311(defvar calc-graph-y3step)
312(defvar calc-graph-zval)
313(defvar calc-graph-stepcount)
314(defvar calc-graph-is-splot)
315(defvar calc-graph-surprise-splot)
316(defvar calc-graph-blank)
317(defvar calc-graph-non-blank)
318(defvar calc-graph-curve-num)
319
136211a9
EZ
320(defun calc-graph-plot (flag &optional printing)
321 (interactive "P")
322 (calc-slow-wrapper
323 (let ((calcbuf (current-buffer))
324 (tempbuf (get-buffer-create "*Gnuplot Temp-2*"))
325 (tempbuftop 1)
326 (tempoutfile nil)
68d1b30d
JB
327 (calc-graph-curve-num 0)
328 (calc-graph-refine (and flag (> (prefix-numeric-value flag) 0)))
136211a9 329 (recompute (and flag (< (prefix-numeric-value flag) 0)))
68d1b30d 330 (calc-graph-surprise-splot nil)
136211a9 331 (tty-output nil)
68d1b30d
JB
332 cache-env calc-graph-is-splot device output calc-graph-resolution precision samples-pos)
333 (add-hook 'kill-emacs-hook 'calc-graph-kill-hook)
136211a9
EZ
334 (save-excursion
335 (calc-graph-init)
336 (set-buffer tempbuf)
337 (erase-buffer)
338 (set-buffer calc-gnuplot-input)
339 (goto-char (point-min))
68d1b30d 340 (setq calc-graph-is-splot (re-search-forward "^splot[ \t]" nil t))
136211a9
EZ
341 (let ((str (buffer-string))
342 (ver calc-gnuplot-version))
343 (set-buffer (get-buffer-create "*Gnuplot Temp*"))
344 (erase-buffer)
345 (insert "# (Note: This is a temporary copy---do not edit!)\n")
346 (if (>= ver 2)
347 (insert "set noarrow\nset nolabel\n"
348 "set autoscale xy\nset nologscale xy\n"
349 "set xlabel\nset ylabel\nset title\n"
350 "set noclip points\nset clip one\nset clip two\n"
351 "set format \"%g\"\nset tics\nset xtics\nset ytics\n"
352 "set data style linespoints\n"
353 "set nogrid\nset nokey\nset nopolar\n"))
354 (if (>= ver 3)
355 (insert "set surface\nset nocontour\n"
68d1b30d 356 "set " (if calc-graph-is-splot "" "no") "parametric\n"
136211a9
EZ
357 "set notime\nset border\nset ztics\nset zeroaxis\n"
358 "set view 60,30,1,1\nset offsets 0,0,0,0\n"))
359 (setq samples-pos (point))
360 (insert "\n\n" str))
361 (goto-char (point-min))
68d1b30d
JB
362 (if calc-graph-is-splot
363 (if calc-graph-refine
136211a9
EZ
364 (error "This option works only for 2d plots")
365 (setq recompute t)))
366 (let ((calc-gnuplot-input (current-buffer))
367 (calc-graph-no-auto-view t))
368 (if printing
369 (setq device calc-gnuplot-print-device
370 output calc-gnuplot-print-output)
371 (setq device (calc-graph-find-command "terminal")
372 output (calc-graph-find-command "output"))
373 (or device
374 (setq device calc-gnuplot-default-device))
375 (if output
376 (setq output (car (read-from-string output)))
377 (setq output calc-gnuplot-default-output)))
378 (if (or (equal device "") (equal device "default"))
379 (setq device (if printing
380 "postscript"
381 (if (or (eq window-system 'x) (getenv "DISPLAY"))
382 "x11"
383 (if (>= calc-gnuplot-version 3)
384 "dumb" "postscript")))))
385 (if (equal device "dumb")
386 (setq device (format "dumb %d %d"
8f66f479 387 (1- (frame-width)) (1- (frame-height)))))
136211a9
EZ
388 (if (equal device "big")
389 (setq device (format "dumb %d %d"
8f66f479
EZ
390 (* 4 (- (frame-width) 3))
391 (* 4 (- (frame-height) 3)))))
136211a9
EZ
392 (if (stringp output)
393 (if (or (equal output "auto")
394 (and (equal output "tty") (setq tty-output t)))
395 (setq tempoutfile (calc-temp-file-name -1)
396 output tempoutfile))
397 (setq output (eval output)))
398 (or (equal device calc-graph-last-device)
399 (progn
400 (setq calc-graph-last-device device)
401 (calc-gnuplot-command "set terminal" device)))
402 (or (equal output calc-graph-last-output)
403 (progn
404 (setq calc-graph-last-output output)
405 (calc-gnuplot-command "set output"
406 (if (equal output "STDOUT")
407 ""
408 (prin1-to-string output)))))
68d1b30d
JB
409 (setq calc-graph-resolution (calc-graph-find-command "samples"))
410 (if calc-graph-resolution
723c2377 411 (setq calc-graph-resolution (string-to-number calc-graph-resolution))
68d1b30d 412 (setq calc-graph-resolution (if calc-graph-is-splot
136211a9
EZ
413 calc-graph-default-resolution-3d
414 calc-graph-default-resolution)))
415 (setq precision (calc-graph-find-command "precision"))
416 (if precision
723c2377 417 (setq precision (string-to-number precision))
136211a9
EZ
418 (setq precision calc-graph-default-precision))
419 (calc-graph-set-command "terminal")
420 (calc-graph-set-command "output")
421 (calc-graph-set-command "samples")
422 (calc-graph-set-command "precision"))
423 (goto-char samples-pos)
68d1b30d
JB
424 (insert "set samples " (int-to-string (max (if calc-graph-is-splot 20 200)
425 (+ 5 calc-graph-resolution))) "\n")
136211a9
EZ
426 (while (re-search-forward "{\\*[^}]+}[^,\n]*" nil t)
427 (delete-region (match-beginning 0) (match-end 0))
428 (if (looking-at ",")
429 (delete-char 1)
9b80830c 430 (while (memq (preceding-char) '(?\s ?\t))
136211a9
EZ
431 (forward-char -1))
432 (if (eq (preceding-char) ?\,)
433 (delete-backward-char 1))))
434 (save-excursion
435 (set-buffer calcbuf)
436 (setq cache-env (list calc-angle-mode
437 calc-complex-mode
438 calc-simplify-mode
439 calc-infinite-mode
440 calc-word-size
68d1b30d 441 precision calc-graph-is-splot))
136211a9
EZ
442 (if (and (not recompute)
443 (equal (cdr (car calc-graph-data-cache)) cache-env))
444 (while (> (length calc-graph-data-cache)
445 calc-graph-data-cache-limit)
446 (setcdr calc-graph-data-cache
447 (cdr (cdr calc-graph-data-cache))))
448 (setq calc-graph-data-cache (list (cons nil cache-env)))))
449 (calc-graph-find-plot t t)
450 (while (re-search-forward
68d1b30d 451 (if calc-graph-is-splot
136211a9
EZ
452 "{\\([^{}:\n]+\\):\\([^{}:\n]+\\):\\([^{}:\n]+\\)}"
453 "{\\([^{}:\n]+\\)\\(:\\)\\([^{}:\n]+\\)}")
454 nil t)
68d1b30d
JB
455 (setq calc-graph-curve-num (1+ calc-graph-curve-num))
456 (let* ((calc-graph-xname (buffer-substring (match-beginning 1) (match-end 1)))
457 (xvar (intern (concat "var-" calc-graph-xname)))
458 (calc-graph-xvalue (math-evaluate-expr (calc-var-value xvar)))
459 (calc-graph-y3name (and calc-graph-is-splot
136211a9
EZ
460 (buffer-substring (match-beginning 2)
461 (match-end 2))))
68d1b30d
JB
462 (y3var (and calc-graph-is-splot (intern (concat "var-" calc-graph-y3name))))
463 (calc-graph-y3value (and calc-graph-is-splot (calc-var-value y3var)))
464 (calc-graph-yname (buffer-substring (match-beginning 3) (match-end 3)))
465 (yvar (intern (concat "var-" calc-graph-yname)))
466 (calc-graph-yvalue (calc-var-value yvar))
136211a9
EZ
467 filename)
468 (delete-region (match-beginning 0) (match-end 0))
68d1b30d 469 (setq filename (calc-temp-file-name calc-graph-curve-num))
136211a9
EZ
470 (save-excursion
471 (set-buffer calcbuf)
472 (let (tempbuftop
68d1b30d
JB
473 (calc-graph-xp calc-graph-xvalue)
474 (calc-graph-yp calc-graph-yvalue)
475 (calc-graph-zp nil)
476 (calc-graph-xlow nil) (calc-graph-xhigh nil) (y3low nil) (y3high nil)
477 calc-graph-xvec calc-graph-xval calc-graph-xstep var-DUMMY
478 y3val calc-graph-y3step var-DUMMY2 (calc-graph-zval nil)
479 calc-graph-yvec calc-graph-yval calc-graph-ycache calc-graph-ycacheptr calc-graph-yvector
480 calc-graph-numsteps calc-graph-numsteps3
481 (calc-graph-keep-file (and (not calc-graph-is-splot) (file-exists-p filename)))
482 (calc-graph-stepcount 0)
136211a9
EZ
483 (calc-symbolic-mode nil)
484 (calc-prefer-frac nil)
485 (calc-internal-prec (max 3 precision))
486 (calc-simplify-mode (and (not (memq calc-simplify-mode
487 '(none num)))
488 calc-simplify-mode))
68d1b30d
JB
489 (calc-graph-blank t)
490 (calc-graph-non-blank nil)
136211a9
EZ
491 (math-working-step 0)
492 (math-working-step-2 nil))
493 (save-excursion
68d1b30d 494 (if calc-graph-is-splot
136211a9
EZ
495 (calc-graph-compute-3d)
496 (calc-graph-compute-2d))
497 (set-buffer tempbuf)
498 (goto-char (point-max))
68d1b30d
JB
499 (insert "\n" calc-graph-xname)
500 (if calc-graph-is-splot
501 (insert ":" calc-graph-y3name))
502 (insert ":" calc-graph-yname "\n\n")
136211a9
EZ
503 (setq tempbuftop (point))
504 (let ((calc-group-digits nil)
505 (calc-leading-zeros nil)
506 (calc-number-radix 10)
68d1b30d
JB
507 (entry (and (not calc-graph-is-splot)
508 (list calc-graph-xp calc-graph-yp calc-graph-xhigh calc-graph-numsteps))))
136211a9 509 (or (equal entry
68d1b30d 510 (nth 1 (nth (1+ calc-graph-curve-num)
136211a9 511 calc-graph-file-cache)))
68d1b30d
JB
512 (setq calc-graph-keep-file nil))
513 (setcar (cdr (nth (1+ calc-graph-curve-num) calc-graph-file-cache))
136211a9 514 entry)
68d1b30d 515 (or calc-graph-keep-file
136211a9 516 (calc-graph-format-data)))
68d1b30d 517 (or calc-graph-keep-file
136211a9 518 (progn
68d1b30d 519 (or calc-graph-non-blank
136211a9 520 (error "No valid data points for %s:%s"
68d1b30d 521 calc-graph-xname calc-graph-yname))
136211a9
EZ
522 (write-region tempbuftop (point-max) filename
523 nil 'quiet))))))
524 (insert (prin1-to-string filename))))
68d1b30d 525 (if calc-graph-surprise-splot
136211a9 526 (setcdr cache-env nil))
68d1b30d 527 (if (= calc-graph-curve-num 0)
136211a9
EZ
528 (progn
529 (calc-gnuplot-command "clear")
530 (calc-clear-command-flag 'clear-message)
531 (message "No data to plot!"))
68d1b30d 532 (setq calc-graph-data-cache-limit (max calc-graph-curve-num
136211a9
EZ
533 calc-graph-data-cache-limit)
534 filename (calc-temp-file-name 0))
535 (write-region (point-min) (point-max) filename nil 'quiet)
536 (calc-gnuplot-command "load" (prin1-to-string filename))
537 (or (equal output "STDOUT")
538 calc-gnuplot-keep-outfile
539 (progn ; need to close the output file before printing/plotting
540 (setq calc-graph-last-output "STDOUT")
541 (calc-gnuplot-command "set output")))
542 (let ((command (if printing
543 calc-gnuplot-print-command
544 (or calc-gnuplot-plot-command
545 (and (string-match "^dumb" device)
546 'calc-graph-show-dumb)
547 (and tty-output
548 'calc-graph-show-tty)))))
549 (if command
550 (if (stringp command)
551 (calc-gnuplot-command
552 "!" (format command
553 (or tempoutfile
554 calc-gnuplot-print-output)))
555 (if (symbolp command)
556 (funcall command output)
bf77c646 557 (eval command))))))))))
136211a9
EZ
558
559(defun calc-graph-compute-2d ()
68d1b30d
JB
560 (if (setq calc-graph-yvec (eq (car-safe calc-graph-yvalue) 'vec))
561 (if (= (setq calc-graph-numsteps (1- (length calc-graph-yvalue))) 0)
136211a9 562 (error "Can't plot an empty vector")
68d1b30d
JB
563 (if (setq calc-graph-xvec (eq (car-safe calc-graph-xvalue) 'vec))
564 (or (= (1- (length calc-graph-xvalue)) calc-graph-numsteps)
565 (error "%s and %s have different lengths" calc-graph-xname calc-graph-yname))
566 (if (and (eq (car-safe calc-graph-xvalue) 'intv)
567 (math-constp calc-graph-xvalue))
568 (setq calc-graph-xstep (math-div (math-sub (nth 3 calc-graph-xvalue)
569 (nth 2 calc-graph-xvalue))
570 (1- calc-graph-numsteps))
571 calc-graph-xvalue (nth 2 calc-graph-xvalue))
572 (if (math-realp calc-graph-xvalue)
573 (setq calc-graph-xstep 1)
574 (error "%s is not a suitable basis for %s" calc-graph-xname calc-graph-yname)))))
575 (or (math-realp calc-graph-yvalue)
136211a9 576 (let ((arglist nil))
68d1b30d
JB
577 (setq calc-graph-yvalue (math-evaluate-expr calc-graph-yvalue))
578 (calc-default-formula-arglist calc-graph-yvalue)
136211a9 579 (or arglist
68d1b30d 580 (error "%s does not contain any unassigned variables" calc-graph-yname))
136211a9
EZ
581 (and (cdr arglist)
582 (error "%s contains more than one variable: %s"
68d1b30d
JB
583 calc-graph-yname arglist))
584 (setq calc-graph-yvalue (math-expr-subst calc-graph-yvalue
136211a9
EZ
585 (math-build-var-name (car arglist))
586 '(var DUMMY var-DUMMY)))))
68d1b30d
JB
587 (setq calc-graph-ycache (assoc calc-graph-yvalue calc-graph-data-cache))
588 (delq calc-graph-ycache calc-graph-data-cache)
136211a9 589 (nconc calc-graph-data-cache
68d1b30d
JB
590 (list (or calc-graph-ycache (setq calc-graph-ycache (list calc-graph-yvalue)))))
591 (if (and (not (setq calc-graph-xvec (eq (car-safe calc-graph-xvalue) 'vec)))
592 calc-graph-refine (cdr (cdr calc-graph-ycache)))
136211a9 593 (calc-graph-refine-2d)
bf77c646 594 (calc-graph-recompute-2d))))
136211a9
EZ
595
596(defun calc-graph-refine-2d ()
68d1b30d
JB
597 (setq calc-graph-keep-file nil
598 calc-graph-ycacheptr (cdr calc-graph-ycache))
599 (if (and (setq calc-graph-xval (calc-graph-find-command "xrange"))
136211a9 600 (string-match "\\`\\[\\([0-9.eE+-]*\\):\\([0-9.eE+-]*\\)\\]\\'"
68d1b30d 601 calc-graph-xval))
136211a9
EZ
602 (let ((b2 (match-beginning 2))
603 (e2 (match-end 2)))
68d1b30d 604 (setq calc-graph-xlow (math-read-number (substring calc-graph-xval
136211a9
EZ
605 (match-beginning 1)
606 (match-end 1)))
68d1b30d
JB
607 calc-graph-xhigh (math-read-number (substring calc-graph-xval b2 e2))))
608 (if calc-graph-xlow
609 (while (and (cdr calc-graph-ycacheptr)
610 (Math-lessp (car (nth 1 calc-graph-ycacheptr)) calc-graph-xlow))
611 (setq calc-graph-ycacheptr (cdr calc-graph-ycacheptr)))))
612 (setq math-working-step-2 (1- (length calc-graph-ycacheptr)))
613 (while (and (cdr calc-graph-ycacheptr)
614 (or (not calc-graph-xhigh)
615 (Math-lessp (car (car calc-graph-ycacheptr)) calc-graph-xhigh)))
616 (setq var-DUMMY (math-div (math-add (car (car calc-graph-ycacheptr))
617 (car (nth 1 calc-graph-ycacheptr)))
136211a9
EZ
618 2)
619 math-working-step (1+ math-working-step)
68d1b30d
JB
620 calc-graph-yval (math-evaluate-expr calc-graph-yvalue))
621 (setcdr calc-graph-ycacheptr (cons (cons var-DUMMY calc-graph-yval)
622 (cdr calc-graph-ycacheptr)))
623 (setq calc-graph-ycacheptr (cdr (cdr calc-graph-ycacheptr))))
624 (setq calc-graph-yp calc-graph-ycache
625 calc-graph-numsteps 1000000))
136211a9
EZ
626
627(defun calc-graph-recompute-2d ()
68d1b30d
JB
628 (setq calc-graph-ycacheptr calc-graph-ycache)
629 (if calc-graph-xvec
630 (setq calc-graph-numsteps (1- (length calc-graph-xvalue))
631 calc-graph-yvector nil)
632 (if (and (eq (car-safe calc-graph-xvalue) 'intv)
633 (math-constp calc-graph-xvalue))
634 (setq calc-graph-numsteps calc-graph-resolution
635 calc-graph-yp nil
636 calc-graph-xlow (nth 2 calc-graph-xvalue)
637 calc-graph-xhigh (nth 3 calc-graph-xvalue)
638 calc-graph-xstep (math-div (math-sub calc-graph-xhigh calc-graph-xlow)
639 (1- calc-graph-numsteps))
640 calc-graph-xvalue (nth 2 calc-graph-xvalue))
136211a9 641 (error "%s is not a suitable basis for %s"
68d1b30d
JB
642 calc-graph-xname calc-graph-yname)))
643 (setq math-working-step-2 calc-graph-numsteps)
644 (while (>= (setq calc-graph-numsteps (1- calc-graph-numsteps)) 0)
136211a9 645 (setq math-working-step (1+ math-working-step))
68d1b30d 646 (if calc-graph-xvec
136211a9 647 (progn
68d1b30d
JB
648 (setq calc-graph-xp (cdr calc-graph-xp)
649 calc-graph-xval (car calc-graph-xp))
650 (and (not (eq calc-graph-ycacheptr calc-graph-ycache))
651 (consp (car calc-graph-ycacheptr))
652 (not (Math-lessp (car (car calc-graph-ycacheptr)) calc-graph-xval))
653 (setq calc-graph-ycacheptr calc-graph-ycache)))
654 (if (= calc-graph-numsteps 0)
655 (setq calc-graph-xval calc-graph-xhigh) ; avoid cumulative roundoff
656 (setq calc-graph-xval calc-graph-xvalue
657 calc-graph-xvalue (math-add calc-graph-xvalue calc-graph-xstep))))
658 (while (and (cdr calc-graph-ycacheptr)
659 (Math-lessp (car (nth 1 calc-graph-ycacheptr)) calc-graph-xval))
660 (setq calc-graph-ycacheptr (cdr calc-graph-ycacheptr)))
661 (or (and (cdr calc-graph-ycacheptr)
662 (Math-equal (car (nth 1 calc-graph-ycacheptr)) calc-graph-xval))
136211a9 663 (progn
68d1b30d
JB
664 (setq calc-graph-keep-file nil
665 var-DUMMY calc-graph-xval)
666 (setcdr calc-graph-ycacheptr (cons (cons calc-graph-xval (math-evaluate-expr calc-graph-yvalue))
667 (cdr calc-graph-ycacheptr)))))
668 (setq calc-graph-ycacheptr (cdr calc-graph-ycacheptr))
669 (if calc-graph-xvec
670 (setq calc-graph-yvector (cons (cdr (car calc-graph-ycacheptr)) calc-graph-yvector))
671 (or calc-graph-yp (setq calc-graph-yp calc-graph-ycacheptr))))
672 (if calc-graph-xvec
673 (setq calc-graph-xp calc-graph-xvalue
674 calc-graph-yvec t
675 calc-graph-yp (cons 'vec (nreverse calc-graph-yvector))
676 calc-graph-numsteps (1- (length calc-graph-xp)))
677 (setq calc-graph-numsteps 1000000)))
136211a9
EZ
678
679(defun calc-graph-compute-3d ()
68d1b30d
JB
680 (if (setq calc-graph-yvec (eq (car-safe calc-graph-yvalue) 'vec))
681 (if (math-matrixp calc-graph-yvalue)
136211a9 682 (progn
68d1b30d
JB
683 (setq calc-graph-numsteps (1- (length calc-graph-yvalue))
684 calc-graph-numsteps3 (1- (length (nth 1 calc-graph-yvalue))))
685 (if (eq (car-safe calc-graph-xvalue) 'vec)
686 (or (= (1- (length calc-graph-xvalue)) calc-graph-numsteps)
687 (error "%s has wrong length" calc-graph-xname))
688 (if (and (eq (car-safe calc-graph-xvalue) 'intv)
689 (math-constp calc-graph-xvalue))
690 (setq calc-graph-xvalue (calcFunc-index calc-graph-numsteps
691 (nth 2 calc-graph-xvalue)
136211a9 692 (math-div
68d1b30d
JB
693 (math-sub (nth 3 calc-graph-xvalue)
694 (nth 2 calc-graph-xvalue))
695 (1- calc-graph-numsteps))))
696 (if (math-realp calc-graph-xvalue)
697 (setq calc-graph-xvalue (calcFunc-index calc-graph-numsteps calc-graph-xvalue 1))
698 (error "%s is not a suitable basis for %s" calc-graph-xname calc-graph-yname))))
699 (if (eq (car-safe calc-graph-y3value) 'vec)
700 (or (= (1- (length calc-graph-y3value)) calc-graph-numsteps3)
701 (error "%s has wrong length" calc-graph-y3name))
702 (if (and (eq (car-safe calc-graph-y3value) 'intv)
703 (math-constp calc-graph-y3value))
704 (setq calc-graph-y3value (calcFunc-index calc-graph-numsteps3
705 (nth 2 calc-graph-y3value)
136211a9 706 (math-div
68d1b30d
JB
707 (math-sub (nth 3 calc-graph-y3value)
708 (nth 2 calc-graph-y3value))
709 (1- calc-graph-numsteps3))))
710 (if (math-realp calc-graph-y3value)
711 (setq calc-graph-y3value (calcFunc-index calc-graph-numsteps3 calc-graph-y3value 1))
712 (error "%s is not a suitable basis for %s" calc-graph-y3name calc-graph-yname))))
713 (setq calc-graph-xp nil
714 calc-graph-yp nil
715 calc-graph-zp nil
716 calc-graph-xvec t)
717 (while (setq calc-graph-xvalue (cdr calc-graph-xvalue) calc-graph-yvalue (cdr calc-graph-yvalue))
718 (setq calc-graph-xp (nconc calc-graph-xp (make-list (1+ calc-graph-numsteps3) (car calc-graph-xvalue)))
719 calc-graph-yp (nconc calc-graph-yp (cons 0 (copy-sequence (cdr calc-graph-y3value))))
720 calc-graph-zp (nconc calc-graph-zp (cons '(skip)
721 (copy-sequence (cdr (car calc-graph-yvalue)))))))
722 (setq calc-graph-numsteps (1- (* calc-graph-numsteps
723 (1+ calc-graph-numsteps3)))))
724 (if (= (setq calc-graph-numsteps (1- (length calc-graph-yvalue))) 0)
136211a9 725 (error "Can't plot an empty vector"))
68d1b30d
JB
726 (or (and (eq (car-safe calc-graph-xvalue) 'vec)
727 (= (1- (length calc-graph-xvalue)) calc-graph-numsteps))
728 (error "%s is not a suitable basis for %s" calc-graph-xname calc-graph-yname))
729 (or (and (eq (car-safe calc-graph-y3value) 'vec)
730 (= (1- (length calc-graph-y3value)) calc-graph-numsteps))
731 (error "%s is not a suitable basis for %s" calc-graph-y3name calc-graph-yname))
732 (setq calc-graph-xp calc-graph-xvalue
733 calc-graph-yp calc-graph-y3value
734 calc-graph-zp calc-graph-yvalue
735 calc-graph-xvec t))
736 (or (math-realp calc-graph-yvalue)
136211a9 737 (let ((arglist nil))
68d1b30d
JB
738 (setq calc-graph-yvalue (math-evaluate-expr calc-graph-yvalue))
739 (calc-default-formula-arglist calc-graph-yvalue)
136211a9
EZ
740 (setq arglist (sort arglist 'string-lessp))
741 (or (cdr arglist)
68d1b30d 742 (error "%s does not contain enough unassigned variables" calc-graph-yname))
136211a9 743 (and (cdr (cdr arglist))
68d1b30d
JB
744 (error "%s contains too many variables: %s" calc-graph-yname arglist))
745 (setq calc-graph-yvalue (math-multi-subst calc-graph-yvalue
136211a9
EZ
746 (mapcar 'math-build-var-name
747 arglist)
748 '((var DUMMY var-DUMMY)
749 (var DUMMY2 var-DUMMY2))))))
68d1b30d
JB
750 (if (setq calc-graph-xvec (eq (car-safe calc-graph-xvalue) 'vec))
751 (setq calc-graph-numsteps (1- (length calc-graph-xvalue)))
752 (if (and (eq (car-safe calc-graph-xvalue) 'intv)
753 (math-constp calc-graph-xvalue))
754 (setq calc-graph-numsteps calc-graph-resolution
755 calc-graph-xvalue (calcFunc-index calc-graph-numsteps
756 (nth 2 calc-graph-xvalue)
757 (math-div (math-sub (nth 3 calc-graph-xvalue)
758 (nth 2 calc-graph-xvalue))
759 (1- calc-graph-numsteps))))
136211a9 760 (error "%s is not a suitable basis for %s"
68d1b30d
JB
761 calc-graph-xname calc-graph-yname)))
762 (if (eq (car-safe calc-graph-y3value) 'vec)
763 (setq calc-graph-numsteps3 (1- (length calc-graph-y3value)))
764 (if (and (eq (car-safe calc-graph-y3value) 'intv)
765 (math-constp calc-graph-y3value))
766 (setq calc-graph-numsteps3 calc-graph-resolution
767 calc-graph-y3value (calcFunc-index calc-graph-numsteps3
768 (nth 2 calc-graph-y3value)
769 (math-div (math-sub (nth 3 calc-graph-y3value)
770 (nth 2 calc-graph-y3value))
771 (1- calc-graph-numsteps3))))
136211a9 772 (error "%s is not a suitable basis for %s"
68d1b30d
JB
773 calc-graph-y3name calc-graph-yname)))
774 (setq calc-graph-xp nil
775 calc-graph-yp nil
776 calc-graph-zp nil
777 calc-graph-xvec t)
136211a9 778 (setq math-working-step 0)
68d1b30d
JB
779 (while (setq calc-graph-xvalue (cdr calc-graph-xvalue))
780 (setq calc-graph-xp (nconc calc-graph-xp (make-list (1+ calc-graph-numsteps3) (car calc-graph-xvalue)))
781 calc-graph-yp (nconc calc-graph-yp (cons 0 (copy-sequence (cdr calc-graph-y3value))))
782 calc-graph-zp (cons '(skip) calc-graph-zp)
783 calc-graph-y3step calc-graph-y3value
784 var-DUMMY (car calc-graph-xvalue)
136211a9
EZ
785 math-working-step-2 0
786 math-working-step (1+ math-working-step))
68d1b30d 787 (while (setq calc-graph-y3step (cdr calc-graph-y3step))
136211a9 788 (setq math-working-step-2 (1+ math-working-step-2)
68d1b30d
JB
789 var-DUMMY2 (car calc-graph-y3step)
790 calc-graph-zp (cons (math-evaluate-expr calc-graph-yvalue) calc-graph-zp))))
791 (setq calc-graph-zp (nreverse calc-graph-zp)
792 calc-graph-numsteps (1- (* calc-graph-numsteps (1+ calc-graph-numsteps3))))))
136211a9
EZ
793
794(defun calc-graph-format-data ()
68d1b30d
JB
795 (while (<= (setq calc-graph-stepcount (1+ calc-graph-stepcount)) calc-graph-numsteps)
796 (if calc-graph-xvec
797 (setq calc-graph-xp (cdr calc-graph-xp)
798 calc-graph-xval (car calc-graph-xp)
799 calc-graph-yp (cdr calc-graph-yp)
800 calc-graph-yval (car calc-graph-yp)
801 calc-graph-zp (cdr calc-graph-zp)
802 calc-graph-zval (car calc-graph-zp))
803 (if calc-graph-yvec
804 (setq calc-graph-xval calc-graph-xvalue
805 calc-graph-xvalue (math-add calc-graph-xvalue calc-graph-xstep)
806 calc-graph-yp (cdr calc-graph-yp)
807 calc-graph-yval (car calc-graph-yp))
808 (setq calc-graph-xval (car (car calc-graph-yp))
809 calc-graph-yval (cdr (car calc-graph-yp))
810 calc-graph-yp (cdr calc-graph-yp))
811 (if (or (not calc-graph-yp)
812 (and calc-graph-xhigh (equal calc-graph-xval calc-graph-xhigh)))
813 (setq calc-graph-numsteps 0))))
814 (if calc-graph-is-splot
815 (if (and (eq (car-safe calc-graph-zval) 'calcFunc-xyz)
816 (= (length calc-graph-zval) 4))
817 (setq calc-graph-xval (nth 1 calc-graph-zval)
818 calc-graph-yval (nth 2 calc-graph-zval)
819 calc-graph-zval (nth 3 calc-graph-zval)))
820 (if (and (eq (car-safe calc-graph-yval) 'calcFunc-xyz)
821 (= (length calc-graph-yval) 4))
136211a9 822 (progn
68d1b30d 823 (or calc-graph-surprise-splot
136211a9
EZ
824 (save-excursion
825 (set-buffer (get-buffer-create "*Gnuplot Temp*"))
826 (save-excursion
827 (goto-char (point-max))
828 (re-search-backward "^plot[ \t]")
829 (insert "set parametric\ns")
68d1b30d
JB
830 (setq calc-graph-surprise-splot t))))
831 (setq calc-graph-xval (nth 1 calc-graph-yval)
832 calc-graph-zval (nth 3 calc-graph-yval)
833 calc-graph-yval (nth 2 calc-graph-yval)))
834 (if (and (eq (car-safe calc-graph-yval) 'calcFunc-xy)
835 (= (length calc-graph-yval) 3))
836 (setq calc-graph-xval (nth 1 calc-graph-yval)
837 calc-graph-yval (nth 2 calc-graph-yval)))))
838 (if (and (Math-realp calc-graph-xval)
839 (Math-realp calc-graph-yval)
840 (or (not calc-graph-zval) (Math-realp calc-graph-zval)))
136211a9 841 (progn
68d1b30d
JB
842 (setq calc-graph-blank nil
843 calc-graph-non-blank t)
844 (if (Math-integerp calc-graph-xval)
845 (insert (math-format-number calc-graph-xval))
846 (if (eq (car calc-graph-xval) 'frac)
847 (setq calc-graph-xval (math-float calc-graph-xval)))
848 (insert (math-format-number (nth 1 calc-graph-xval))
849 "e" (int-to-string (nth 2 calc-graph-xval))))
136211a9 850 (insert " ")
68d1b30d
JB
851 (if (Math-integerp calc-graph-yval)
852 (insert (math-format-number calc-graph-yval))
853 (if (eq (car calc-graph-yval) 'frac)
854 (setq calc-graph-yval (math-float calc-graph-yval)))
855 (insert (math-format-number (nth 1 calc-graph-yval))
856 "e" (int-to-string (nth 2 calc-graph-yval))))
857 (if calc-graph-zval
136211a9
EZ
858 (progn
859 (insert " ")
68d1b30d
JB
860 (if (Math-integerp calc-graph-zval)
861 (insert (math-format-number calc-graph-zval))
862 (if (eq (car calc-graph-zval) 'frac)
863 (setq calc-graph-zval (math-float calc-graph-zval)))
864 (insert (math-format-number (nth 1 calc-graph-zval))
865 "e" (int-to-string (nth 2 calc-graph-zval))))))
136211a9 866 (insert "\n"))
68d1b30d 867 (and (not (equal calc-graph-zval '(skip)))
be625312 868 (boundp 'var-PlotRejects)
136211a9
EZ
869 (eq (car-safe var-PlotRejects) 'vec)
870 (nconc var-PlotRejects
871 (list (list 'vec
68d1b30d
JB
872 calc-graph-curve-num
873 calc-graph-stepcount
874 calc-graph-xval calc-graph-yval)))
136211a9 875 (calc-refresh-evaltos 'var-PlotRejects))
68d1b30d 876 (or calc-graph-blank
136211a9
EZ
877 (progn
878 (insert "\n")
68d1b30d 879 (setq calc-graph-blank t))))))
136211a9
EZ
880
881(defun calc-temp-file-name (num)
882 (while (<= (length calc-graph-file-cache) (1+ num))
883 (setq calc-graph-file-cache (nconc calc-graph-file-cache (list nil))))
884 (car (or (nth (1+ num) calc-graph-file-cache)
885 (setcar (nthcdr (1+ num) calc-graph-file-cache)
2c37c14b 886 (list (make-temp-file
136211a9
EZ
887 (concat calc-gnuplot-tempfile
888 (if (<= num 0)
889 (char-to-string (- ?A num))
890 (int-to-string num))))
bf77c646 891 nil)))))
136211a9
EZ
892
893(defun calc-graph-delete-temps ()
894 (while calc-graph-file-cache
895 (and (car calc-graph-file-cache)
896 (file-exists-p (car (car calc-graph-file-cache)))
897 (condition-case err
898 (delete-file (car (car calc-graph-file-cache)))
899 (error nil)))
bf77c646 900 (setq calc-graph-file-cache (cdr calc-graph-file-cache))))
136211a9
EZ
901
902(defun calc-graph-kill-hook ()
68d1b30d 903 (calc-graph-delete-temps))
136211a9
EZ
904
905(defun calc-graph-show-tty (output)
906 "Default calc-gnuplot-plot-command for \"tty\" output mode.
907This is useful for tek40xx and other graphics-terminal types."
908 (call-process-region 1 1 shell-file-name
909 nil calc-gnuplot-buffer nil
bf77c646 910 "-c" (format "cat %s >/dev/tty; rm %s" output output)))
136211a9 911
68d1b30d
JB
912(defvar calc-dumb-map nil
913 "The keymap for the \"dumb\" terminal plot.")
914
136211a9
EZ
915(defun calc-graph-show-dumb (&optional output)
916 "Default calc-gnuplot-plot-command for Pinard's \"dumb\" terminal type.
917This \"dumb\" driver will be present in Gnuplot 3.0."
918 (interactive)
919 (save-window-excursion
920 (switch-to-buffer calc-gnuplot-buffer)
921 (delete-other-windows)
922 (goto-char calc-gnuplot-trail-mark)
923 (or (search-forward "\f" nil t)
924 (sleep-for 1))
925 (goto-char (point-max))
926 (re-search-backward "\f\\|^[ \t]+\\^$\\|G N U P L O T")
136211a9
EZ
927 (if (looking-at "\f")
928 (progn
929 (forward-char 1)
930 (if (eolp) (forward-line 1))
931 (or (calc-graph-find-command "time")
932 (calc-graph-find-command "title")
933 (calc-graph-find-command "ylabel")
934 (let ((pt (point)))
935 (insert-before-markers (format "(%s)" (current-time-string)))
936 (goto-char pt)))
937 (set-window-start (selected-window) (point))
938 (goto-char (point-max)))
939 (end-of-line)
940 (backward-char 1)
941 (recenter '(4)))
68d1b30d 942 (or calc-dumb-map
136211a9
EZ
943 (progn
944 (setq calc-dumb-map (make-sparse-keymap))
945 (define-key calc-dumb-map "\n" 'scroll-up)
946 (define-key calc-dumb-map " " 'scroll-up)
947 (define-key calc-dumb-map "\177" 'scroll-down)
948 (define-key calc-dumb-map "<" 'scroll-left)
949 (define-key calc-dumb-map ">" 'scroll-right)
950 (define-key calc-dumb-map "{" 'scroll-down)
951 (define-key calc-dumb-map "}" 'scroll-up)
952 (define-key calc-dumb-map "q" 'exit-recursive-edit)
953 (define-key calc-dumb-map "\C-c\C-c" 'exit-recursive-edit)))
954 (use-local-map calc-dumb-map)
955 (setq truncate-lines t)
7c31514a 956 (message "Type `q' or `C-c C-c' to return to Calc")
136211a9 957 (recursive-edit)
bf77c646 958 (bury-buffer "*Gnuplot Trail*")))
136211a9
EZ
959
960(defun calc-graph-clear ()
961 (interactive)
962 (if calc-graph-last-device
963 (if (or (equal calc-graph-last-device "x11")
964 (equal calc-graph-last-device "X11"))
965 (calc-gnuplot-command "set output"
966 (if (equal calc-graph-last-output "STDOUT")
967 ""
968 (prin1-to-string calc-graph-last-output)))
bf77c646 969 (calc-gnuplot-command "clear"))))
136211a9
EZ
970
971(defun calc-graph-title-x (title)
972 (interactive "sX axis title: ")
973 (calc-graph-set-command "xlabel" (if (not (equal title ""))
bf77c646 974 (prin1-to-string title))))
136211a9
EZ
975
976(defun calc-graph-title-y (title)
977 (interactive "sY axis title: ")
978 (calc-graph-set-command "ylabel" (if (not (equal title ""))
bf77c646 979 (prin1-to-string title))))
136211a9
EZ
980
981(defun calc-graph-title-z (title)
982 (interactive "sZ axis title: ")
983 (calc-graph-set-command "zlabel" (if (not (equal title ""))
bf77c646 984 (prin1-to-string title))))
136211a9
EZ
985
986(defun calc-graph-range-x (range)
987 (interactive "sX axis range: ")
bf77c646 988 (calc-graph-set-range "xrange" range))
136211a9
EZ
989
990(defun calc-graph-range-y (range)
991 (interactive "sY axis range: ")
bf77c646 992 (calc-graph-set-range "yrange" range))
136211a9
EZ
993
994(defun calc-graph-range-z (range)
995 (interactive "sZ axis range: ")
bf77c646 996 (calc-graph-set-range "zrange" range))
136211a9
EZ
997
998(defun calc-graph-set-range (cmd range)
999 (if (equal range "$")
1000 (calc-wrapper
1001 (let ((val (calc-top-n 1)))
1002 (if (and (eq (car-safe val) 'intv) (math-constp val))
1003 (setq range (concat
1004 (math-format-number (math-float (nth 2 val))) ":"
1005 (math-format-number (math-float (nth 3 val)))))
1006 (if (and (eq (car-safe val) 'vec)
1007 (= (length val) 3))
1008 (setq range (concat
1009 (math-format-number (math-float (nth 1 val))) ":"
1010 (math-format-number (math-float (nth 2 val)))))
1011 (error "Range specification must be an interval or 2-vector")))
1012 (calc-pop-stack 1))))
1013 (if (string-match "\\[.+\\]" range)
1014 (setq range (substring range 1 -1)))
1015 (if (and (not (string-match ":" range))
1016 (or (string-match "," range)
1017 (string-match " " range)))
1018 (aset range (match-beginning 0) ?\:))
1019 (calc-graph-set-command cmd (if (not (equal range ""))
bf77c646 1020 (concat "[" range "]"))))
136211a9
EZ
1021
1022(defun calc-graph-log-x (flag)
1023 (interactive "P")
bf77c646 1024 (calc-graph-set-log flag 0 0))
136211a9
EZ
1025
1026(defun calc-graph-log-y (flag)
1027 (interactive "P")
bf77c646 1028 (calc-graph-set-log 0 flag 0))
136211a9
EZ
1029
1030(defun calc-graph-log-z (flag)
1031 (interactive "P")
bf77c646 1032 (calc-graph-set-log 0 0 flag))
136211a9
EZ
1033
1034(defun calc-graph-set-log (xflag yflag zflag)
1035 (let* ((old (or (calc-graph-find-command "logscale") ""))
1036 (xold (string-match "x" old))
1037 (yold (string-match "y" old))
1038 (zold (string-match "z" old))
1039 str)
1040 (setq str (concat (if (if xflag
1041 (if (eq xflag 0) xold
1042 (> (prefix-numeric-value xflag) 0))
1043 (not xold)) "x" "")
1044 (if (if yflag
1045 (if (eq yflag 0) yold
1046 (> (prefix-numeric-value yflag) 0))
1047 (not yold)) "y" "")
1048 (if (if zflag
1049 (if (eq zflag 0) zold
1050 (> (prefix-numeric-value zflag) 0))
1051 (not zold)) "z" "")))
bf77c646 1052 (calc-graph-set-command "logscale" (if (not (equal str "")) str))))
136211a9
EZ
1053
1054(defun calc-graph-line-style (style)
1055 (interactive "P")
bf77c646 1056 (calc-graph-set-styles (and style (prefix-numeric-value style)) t))
136211a9
EZ
1057
1058(defun calc-graph-point-style (style)
1059 (interactive "P")
bf77c646 1060 (calc-graph-set-styles t (and style (prefix-numeric-value style))))
136211a9
EZ
1061
1062(defun calc-graph-set-styles (lines points)
1063 (calc-graph-init)
1064 (save-excursion
1065 (set-buffer calc-gnuplot-input)
1066 (or (calc-graph-find-plot nil nil)
1067 (error "No data points have been set!"))
1068 (let ((base (point))
1069 (mode nil) (lstyle nil) (pstyle nil)
1070 start end lenbl penbl)
1071 (re-search-forward "[,\n]")
1072 (forward-char -1)
1073 (setq end (point) start end)
1074 (goto-char base)
1075 (if (looking-at "[^,\n]*[^,\n \t]\\([ \t]+with\\)")
1076 (progn
1077 (setq start (match-beginning 1))
1078 (goto-char (match-end 0))
1079 (if (looking-at "[ \t]+\\([a-z]+\\)")
1080 (setq mode (buffer-substring (match-beginning 1)
1081 (match-end 1))))
1082 (if (looking-at "[ \ta-z]+\\([0-9]+\\)")
723c2377 1083 (setq lstyle (string-to-number
136211a9
EZ
1084 (buffer-substring (match-beginning 1)
1085 (match-end 1)))))
1086 (if (looking-at "[ \ta-z]+[0-9]+[ \t]+\\([0-9]+\\)")
723c2377 1087 (setq pstyle (string-to-number
136211a9
EZ
1088 (buffer-substring (match-beginning 1)
1089 (match-end 1)))))))
1090 (setq lenbl (or (equal mode "lines") (equal mode "linespoints"))
1091 penbl (or (equal mode "points") (equal mode "linespoints")))
1092 (if lines
1093 (or (eq lines t)
1094 (setq lstyle lines
1095 lenbl (>= lines 0)))
1096 (setq lenbl (not lenbl)))
1097 (if points
1098 (or (eq points t)
1099 (setq pstyle points
1100 penbl (>= points 0)))
1101 (setq penbl (not penbl)))
1102 (delete-region start end)
1103 (goto-char start)
1104 (insert " with "
1105 (if lenbl
1106 (if penbl "linespoints" "lines")
1107 (if penbl "points" "dots")))
1108 (if (and pstyle (> pstyle 0))
1109 (insert " " (if (and lstyle (> lstyle 0)) (int-to-string lstyle) "1")
1110 " " (int-to-string pstyle))
1111 (if (and lstyle (> lstyle 0))
1112 (insert " " (int-to-string lstyle))))))
bf77c646 1113 (calc-graph-view-commands))
136211a9
EZ
1114
1115(defun calc-graph-zero-x (flag)
1116 (interactive "P")
1117 (calc-graph-set-command "noxzeroaxis"
1118 (and (if flag
1119 (<= (prefix-numeric-value flag) 0)
1120 (not (calc-graph-find-command "noxzeroaxis")))
bf77c646 1121 " ")))
136211a9
EZ
1122
1123(defun calc-graph-zero-y (flag)
1124 (interactive "P")
1125 (calc-graph-set-command "noyzeroaxis"
1126 (and (if flag
1127 (<= (prefix-numeric-value flag) 0)
1128 (not (calc-graph-find-command "noyzeroaxis")))
bf77c646 1129 " ")))
136211a9
EZ
1130
1131(defun calc-graph-name (name)
1132 (interactive "sTitle for current curve: ")
1133 (calc-graph-init)
1134 (save-excursion
1135 (set-buffer calc-gnuplot-input)
1136 (or (calc-graph-find-plot nil nil)
1137 (error "No data points have been set!"))
1138 (let ((base (point))
68d1b30d
JB
1139 start
1140 end)
136211a9
EZ
1141 (re-search-forward "[,\n]\\|[ \t]+with")
1142 (setq end (match-beginning 0))
1143 (goto-char base)
1144 (if (looking-at "[^,\n]*[^,\n \t]\\([ \t]+title\\)")
1145 (progn
1146 (goto-char (match-beginning 1))
1147 (delete-region (point) end))
1148 (goto-char end))
1149 (insert " title " (prin1-to-string name))))
bf77c646 1150 (calc-graph-view-commands))
136211a9
EZ
1151
1152(defun calc-graph-hide (flag)
1153 (interactive "P")
1154 (calc-graph-init)
1155 (and (calc-graph-find-plot nil nil)
1156 (progn
1157 (or (looking-at "{")
1158 (error "Can't hide this curve (wrong format)"))
1159 (forward-char 1)
1160 (if (looking-at "*")
1161 (if (or (null flag) (<= (prefix-numeric-value flag) 0))
1162 (delete-char 1))
1163 (if (or (null flag) (> (prefix-numeric-value flag) 0))
bf77c646 1164 (insert "*"))))))
136211a9
EZ
1165
1166(defun calc-graph-header (title)
1167 (interactive "sTitle for entire graph: ")
1168 (calc-graph-set-command "title" (if (not (equal title ""))
bf77c646 1169 (prin1-to-string title))))
136211a9
EZ
1170
1171(defun calc-graph-border (flag)
1172 (interactive "P")
1173 (calc-graph-set-command "noborder"
1174 (and (if flag
1175 (<= (prefix-numeric-value flag) 0)
1176 (not (calc-graph-find-command "noborder")))
bf77c646 1177 " ")))
136211a9
EZ
1178
1179(defun calc-graph-grid (flag)
1180 (interactive "P")
1181 (calc-graph-set-command "grid" (and (if flag
1182 (> (prefix-numeric-value flag) 0)
1183 (not (calc-graph-find-command "grid")))
bf77c646 1184 " ")))
136211a9
EZ
1185
1186(defun calc-graph-key (flag)
1187 (interactive "P")
1188 (calc-graph-set-command "key" (and (if flag
1189 (> (prefix-numeric-value flag) 0)
1190 (not (calc-graph-find-command "key")))
bf77c646 1191 " ")))
136211a9
EZ
1192
1193(defun calc-graph-num-points (res flag)
1194 (interactive "sNumber of data points: \nP")
1195 (if flag
1196 (if (> (prefix-numeric-value flag) 0)
1197 (if (equal res "")
3132f345 1198 (message "Default resolution is %d"
136211a9 1199 calc-graph-default-resolution)
723c2377 1200 (setq calc-graph-default-resolution (string-to-number res)))
136211a9 1201 (if (equal res "")
3132f345 1202 (message "Default 3D resolution is %d"
136211a9 1203 calc-graph-default-resolution-3d)
723c2377 1204 (setq calc-graph-default-resolution-3d (string-to-number res))))
bf77c646 1205 (calc-graph-set-command "samples" (if (not (equal res "")) res))))
136211a9
EZ
1206
1207(defun calc-graph-device (name flag)
1208 (interactive "sDevice name: \nP")
1209 (if (equal name "?")
1210 (progn
1211 (calc-gnuplot-command "set terminal")
1212 (calc-graph-view-trail))
1213 (if flag
1214 (if (> (prefix-numeric-value flag) 0)
1215 (if (equal name "")
3132f345 1216 (message "Default GNUPLOT device is \"%s\""
136211a9
EZ
1217 calc-gnuplot-default-device)
1218 (setq calc-gnuplot-default-device name))
1219 (if (equal name "")
3132f345 1220 (message "GNUPLOT device for Print command is \"%s\""
136211a9
EZ
1221 calc-gnuplot-print-device)
1222 (setq calc-gnuplot-print-device name)))
1223 (calc-graph-set-command "terminal" (if (not (equal name ""))
bf77c646 1224 name)))))
136211a9
EZ
1225
1226(defun calc-graph-output (name flag)
1227 (interactive "FOutput file name: \np")
1228 (cond ((string-match "\\<[aA][uU][tT][oO]$" name)
1229 (setq name "auto"))
1230 ((string-match "\\<[tT][tT][yY]$" name)
1231 (setq name "tty"))
1232 ((string-match "\\<[sS][tT][dD][oO][uU][tT]$" name)
1233 (setq name "STDOUT"))
1234 ((equal (file-name-nondirectory name) "")
1235 (setq name ""))
1236 (t (setq name (expand-file-name name))))
1237 (if flag
1238 (if (> (prefix-numeric-value flag) 0)
1239 (if (equal name "")
3132f345 1240 (message "Default GNUPLOT output file is \"%s\""
136211a9
EZ
1241 calc-gnuplot-default-output)
1242 (setq calc-gnuplot-default-output name))
1243 (if (equal name "")
3132f345 1244 (message "GNUPLOT output file for Print command is \"%s\""
136211a9
EZ
1245 calc-gnuplot-print-output)
1246 (setq calc-gnuplot-print-output name)))
1247 (calc-graph-set-command "output" (if (not (equal name ""))
bf77c646 1248 (prin1-to-string name)))))
136211a9
EZ
1249
1250(defun calc-graph-display (name)
1251 (interactive "sX display name: ")
1252 (if (equal name "")
3132f345 1253 (message "Current X display is \"%s\""
136211a9
EZ
1254 (or calc-gnuplot-display "<none>"))
1255 (setq calc-gnuplot-display name)
1256 (if (calc-gnuplot-alive)
bf77c646 1257 (calc-gnuplot-command "exit"))))
136211a9
EZ
1258
1259(defun calc-graph-geometry (name)
1260 (interactive "sX geometry spec (or \"default\"): ")
1261 (if (equal name "")
3132f345 1262 (message "Current X geometry is \"%s\""
136211a9
EZ
1263 (or calc-gnuplot-geometry "default"))
1264 (setq calc-gnuplot-geometry (and (not (equal name "default")) name))
1265 (if (calc-gnuplot-alive)
bf77c646 1266 (calc-gnuplot-command "exit"))))
136211a9
EZ
1267
1268(defun calc-graph-find-command (cmd)
1269 (calc-graph-init)
1270 (save-excursion
1271 (set-buffer calc-gnuplot-input)
1272 (goto-char (point-min))
1273 (if (re-search-forward (concat "^set[ \t]+" cmd "[ \t]*\\(.*\\)$") nil t)
bf77c646 1274 (buffer-substring (match-beginning 1) (match-end 1)))))
136211a9
EZ
1275
1276(defun calc-graph-set-command (cmd &rest args)
1277 (calc-graph-init)
1278 (save-excursion
1279 (set-buffer calc-gnuplot-input)
1280 (goto-char (point-min))
1281 (if (re-search-forward (concat "^set[ \t]+" cmd "[ \t\n]") nil t)
1282 (progn
1283 (forward-char -1)
1284 (end-of-line)
1285 (let ((end (point)))
1286 (beginning-of-line)
1287 (delete-region (point) (1+ end))))
1288 (if (calc-graph-find-plot t t)
1289 (if (eq (preceding-char) ?\n)
1290 (forward-char -1))
1291 (goto-char (1- (point-max)))))
1292 (if (and args (car args))
1293 (progn
1294 (or (bolp)
1295 (insert "\n"))
1296 (insert "set " (mapconcat 'identity (cons cmd args) " ") "\n"))))
bf77c646 1297 (calc-graph-view-commands))
136211a9
EZ
1298
1299(defun calc-graph-command (cmd)
1300 (interactive "sGNUPLOT command: ")
1301 (calc-wrapper
1302 (calc-graph-init)
1303 (calc-graph-view-trail)
1304 (calc-gnuplot-command cmd)
1305 (accept-process-output)
bf77c646 1306 (calc-graph-view-trail)))
136211a9
EZ
1307
1308(defun calc-graph-kill (&optional no-view)
1309 (interactive)
1310 (calc-graph-delete-temps)
1311 (if (calc-gnuplot-alive)
1312 (calc-wrapper
1313 (or no-view (calc-graph-view-trail))
1314 (let ((calc-graph-no-wait t))
1315 (calc-gnuplot-command "exit"))
1316 (sit-for 1)
1317 (if (process-status calc-gnuplot-process)
1318 (delete-process calc-gnuplot-process))
bf77c646 1319 (setq calc-gnuplot-process nil))))
136211a9
EZ
1320
1321(defun calc-graph-quit ()
1322 (interactive)
1323 (if (get-buffer-window calc-gnuplot-input)
1324 (calc-graph-view-commands t))
1325 (if (get-buffer-window calc-gnuplot-buffer)
1326 (calc-graph-view-trail t))
bf77c646 1327 (calc-graph-kill t))
136211a9
EZ
1328
1329(defun calc-graph-view-commands (&optional no-need)
1330 (interactive "p")
1331 (or calc-graph-no-auto-view (calc-graph-init-buffers))
bf77c646 1332 (calc-graph-view calc-gnuplot-input calc-gnuplot-buffer (null no-need)))
136211a9
EZ
1333
1334(defun calc-graph-view-trail (&optional no-need)
1335 (interactive "p")
1336 (or calc-graph-no-auto-view (calc-graph-init-buffers))
bf77c646 1337 (calc-graph-view calc-gnuplot-buffer calc-gnuplot-input (null no-need)))
136211a9
EZ
1338
1339(defun calc-graph-view (buf other-buf need)
1340 (let (win)
1341 (or calc-graph-no-auto-view
1342 (if (setq win (get-buffer-window buf))
1343 (or need
1344 (and (eq buf calc-gnuplot-buffer)
1345 (save-excursion
1346 (set-buffer buf)
1347 (not (pos-visible-in-window-p (point-max) win))))
1348 (progn
1349 (bury-buffer buf)
1350 (bury-buffer other-buf)
1351 (let ((curwin (selected-window)))
1352 (select-window win)
1353 (switch-to-buffer nil)
1354 (select-window curwin))))
1355 (if (setq win (get-buffer-window other-buf))
1356 (set-window-buffer win buf)
1357 (if (eq major-mode 'calc-mode)
1358 (if (or need
8f66f479 1359 (< (window-height) (1- (frame-height))))
136211a9
EZ
1360 (display-buffer buf))
1361 (switch-to-buffer buf)))))
1362 (save-excursion
1363 (set-buffer buf)
1364 (if (and (eq buf calc-gnuplot-buffer)
1365 (setq win (get-buffer-window buf))
1366 (not (pos-visible-in-window-p (point-max) win)))
1367 (progn
1368 (goto-char (point-max))
1369 (vertical-motion (- 6 (window-height win)))
1370 (set-window-start win (point))
1371 (goto-char (point-max)))))
bf77c646 1372 (or calc-graph-no-auto-view (sit-for 0))))
136211a9
EZ
1373
1374(defun calc-gnuplot-check-for-errors ()
1375 (if (save-excursion
1376 (prog2
1377 (progn
1378 (set-buffer calc-gnuplot-buffer)
1379 (goto-char calc-gnuplot-last-error-pos))
1380 (re-search-forward "^[ \t]+\\^$" nil t)
1381 (goto-char (point-max))
1382 (setq calc-gnuplot-last-error-pos (point-max))))
bf77c646 1383 (calc-graph-view-trail)))
136211a9
EZ
1384
1385(defun calc-gnuplot-command (&rest args)
1386 (calc-graph-init)
1387 (let ((cmd (concat (mapconcat 'identity args " ") "\n")))
1388 (accept-process-output)
1389 (save-excursion
1390 (set-buffer calc-gnuplot-buffer)
1391 (calc-gnuplot-check-for-errors)
1392 (goto-char (point-max))
1393 (setq calc-gnuplot-trail-mark (point))
1394 (or (>= calc-gnuplot-version 3)
1395 (insert cmd))
1396 (set-marker (process-mark calc-gnuplot-process) (point))
1397 (process-send-string calc-gnuplot-process cmd)
1398 (if (get-buffer-window calc-gnuplot-buffer)
1399 (calc-graph-view-trail))
1400 (accept-process-output (and (not calc-graph-no-wait)
1401 calc-gnuplot-process))
1402 (calc-gnuplot-check-for-errors)
1403 (if (get-buffer-window calc-gnuplot-buffer)
bf77c646 1404 (calc-graph-view-trail)))))
136211a9
EZ
1405
1406(defun calc-graph-init-buffers ()
1407 (or (and calc-gnuplot-buffer
1408 (buffer-name calc-gnuplot-buffer))
1409 (setq calc-gnuplot-buffer (get-buffer-create "*Gnuplot Trail*")))
1410 (or (and calc-gnuplot-input
1411 (buffer-name calc-gnuplot-input))
bf77c646 1412 (setq calc-gnuplot-input (get-buffer-create "*Gnuplot Commands*"))))
136211a9
EZ
1413
1414(defun calc-graph-init ()
1415 (or (calc-gnuplot-alive)
1416 (let ((process-connection-type t)
1417 origin)
1418 (if calc-gnuplot-process
1419 (progn
1420 (delete-process calc-gnuplot-process)
1421 (setq calc-gnuplot-process nil)))
1422 (calc-graph-init-buffers)
1423 (save-excursion
1424 (set-buffer calc-gnuplot-buffer)
1425 (insert "\nStarting gnuplot...\n")
1426 (setq origin (point)))
1427 (setq calc-graph-last-device nil)
1428 (setq calc-graph-last-output nil)
1429 (condition-case err
1430 (let ((args (append (and calc-gnuplot-display
1431 (not (equal calc-gnuplot-display
1432 (getenv "DISPLAY")))
1433 (list "-display"
1434 calc-gnuplot-display))
1435 (and calc-gnuplot-geometry
1436 (list "-geometry"
1437 calc-gnuplot-geometry)))))
a1506d29 1438 (setq calc-gnuplot-process
136211a9
EZ
1439 (apply 'start-process
1440 "gnuplot"
1441 calc-gnuplot-buffer
1442 calc-gnuplot-name
1443 args))
6e237e72 1444 (set-process-query-on-exit-flag calc-gnuplot-process nil))
136211a9 1445 (file-error
3132f345 1446 (error "Sorry, can't find \"%s\" on your system"
136211a9
EZ
1447 calc-gnuplot-name)))
1448 (save-excursion
1449 (set-buffer calc-gnuplot-buffer)
1450 (while (and (not (save-excursion
1451 (goto-char origin)
1452 (search-forward "gnuplot> " nil t)))
1453 (memq (process-status calc-gnuplot-process) '(run stop)))
1454 (accept-process-output calc-gnuplot-process))
1455 (or (memq (process-status calc-gnuplot-process) '(run stop))
3132f345 1456 (error "Unable to start GNUPLOT process"))
136211a9
EZ
1457 (if (save-excursion
1458 (goto-char origin)
1459 (re-search-forward
1460 "G N U P L O T.*\n.*version \\([0-9]+\\)\\." nil t))
723c2377 1461 (setq calc-gnuplot-version (string-to-number (buffer-substring
136211a9
EZ
1462 (match-beginning 1)
1463 (match-end 1))))
1464 (setq calc-gnuplot-version 1))
1465 (goto-char (point-max)))))
1466 (save-excursion
1467 (set-buffer calc-gnuplot-input)
1468 (if (= (buffer-size) 0)
1469 (insert "# Commands for running gnuplot\n\n\n")
1470 (or calc-graph-no-auto-view
1471 (eq (char-after (1- (point-max))) ?\n)
1472 (progn
1473 (goto-char (point-max))
bf77c646 1474 (insert "\n"))))))
136211a9 1475
808cd573
JB
1476(provide 'calc-graph)
1477
ab5796a9 1478;;; arch-tag: e4b06a52-c386-4d54-a2bb-7c0a0ef533c2
bf77c646 1479;;; calc-graph.el ends here