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