calc-graph.el 52.6 KB
Newer Older
1 2
;;; calc-graph.el --- graph output functions for Calc

Jay Belanger's avatar
Jay Belanger committed
3
;; Copyright (C) 1990, 1991, 1992, 1993, 2001, 2002, 2003, 2004,
Glenn Morris's avatar
Glenn Morris committed
4
;;   2005, 2006, 2007 Free Software Foundation, Inc.
5 6

;; Author: David Gillespie <daveg@synaptics.com>
Jay Belanger's avatar
Jay Belanger committed
7
;; Maintainer: Jay Belanger <jay.p.belanger@gmail.com>
Eli Zaretskii's avatar
Eli Zaretskii committed
8 9 10

;; This file is part of GNU Emacs.

11 12 13 14 15
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

Eli Zaretskii's avatar
Eli Zaretskii committed
16
;; GNU Emacs is distributed in the hope that it will be useful,
17 18 19 20 21 22 23 24
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
Eli Zaretskii's avatar
Eli Zaretskii committed
25

26
;;; Commentary:
Eli Zaretskii's avatar
Eli Zaretskii committed
27

28
;;; Code:
Eli Zaretskii's avatar
Eli Zaretskii committed
29 30 31

;; This file is autoloaded from calc-ext.el.

Jay Belanger's avatar
Jay Belanger committed
32
(require 'calc-ext)
Eli Zaretskii's avatar
Eli Zaretskii committed
33 34
(require 'calc-macs)

Jay Belanger's avatar
Jay Belanger committed
35 36
;;; Graphics

Jay Belanger's avatar
Jay Belanger committed
37 38 39 40
;; The following three variables are customizable and defined in calc.el.
(defvar calc-gnuplot-name)
(defvar calc-gnuplot-plot-command)
(defvar calc-gnuplot-print-command)
Eli Zaretskii's avatar
Eli Zaretskii committed
41

42
(defvar calc-gnuplot-tempfile "calc")
Eli Zaretskii's avatar
Eli Zaretskii committed
43

44 45 46 47
(defvar calc-gnuplot-default-device)
(defvar calc-gnuplot-default-output)
(defvar calc-gnuplot-print-device)
(defvar calc-gnuplot-print-output)
Eli Zaretskii's avatar
Eli Zaretskii committed
48 49 50 51
(defvar calc-gnuplot-keep-outfile nil)
(defvar calc-gnuplot-version nil)

(defvar calc-gnuplot-display (getenv "DISPLAY"))
52
(defvar calc-gnuplot-geometry)
Eli Zaretskii's avatar
Eli Zaretskii committed
53

54 55
(defvar calc-graph-default-resolution)
(defvar calc-graph-default-resolution-3d)
Eli Zaretskii's avatar
Eli Zaretskii committed
56 57 58 59 60 61 62 63 64 65 66 67
(defvar calc-graph-default-precision 5)

(defvar calc-gnuplot-buffer nil)
(defvar calc-gnuplot-input nil)

(defvar calc-gnuplot-last-error-pos 1)
(defvar calc-graph-last-device nil)
(defvar calc-graph-last-output nil)
(defvar calc-graph-file-cache nil)
(defvar calc-graph-var-cache nil)
(defvar calc-graph-data-cache nil)
(defvar calc-graph-data-cache-limit 10)
68 69
(defvar calc-graph-no-auto-view nil)
(defvar calc-graph-no-wait nil)
Jay Belanger's avatar
Jay Belanger committed
70
(defvar calc-gnuplot-trail-mark)
Eli Zaretskii's avatar
Eli Zaretskii committed
71 72 73 74 75 76

(defun calc-graph-fast (many)
  (interactive "P")
  (let ((calc-graph-no-auto-view t))
    (calc-graph-delete t)
    (calc-graph-add many)
77
    (calc-graph-plot nil)))
Eli Zaretskii's avatar
Eli Zaretskii committed
78 79 80 81 82 83

(defun calc-graph-fast-3d (many)
  (interactive "P")
  (let ((calc-graph-no-auto-view t))
    (calc-graph-delete t)
    (calc-graph-add-3d many)
84
    (calc-graph-plot nil)))
Eli Zaretskii's avatar
Eli Zaretskii committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98

(defun calc-graph-delete (all)
  (interactive "P")
  (calc-wrapper
   (calc-graph-init)
   (save-excursion
     (set-buffer calc-gnuplot-input)
     (and (calc-graph-find-plot t all)
	  (progn
	    (if (looking-at "s?plot")
		(progn
		  (setq calc-graph-var-cache nil)
		  (delete-region (point) (point-max)))
	      (delete-region (point) (1- (point-max)))))))
99
   (calc-graph-view-commands)))
Eli Zaretskii's avatar
Eli Zaretskii committed
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

(defun calc-graph-find-plot (&optional before all)
  (goto-char (point-min))
  (and (re-search-forward "^s?plot[ \t]+" nil t)
       (let ((beg (point)))
	 (goto-char (point-max))
	 (if (or all
		 (not (search-backward "," nil t))
		 (< (point) beg))
	     (progn
	       (goto-char beg)
	       (if before
		   (beginning-of-line)))
	   (or before
	       (re-search-forward ",[ \t]+")))
115
	 t)))
Eli Zaretskii's avatar
Eli Zaretskii committed
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

(defun calc-graph-add (many)
  (interactive "P")
  (calc-wrapper
   (calc-graph-init)
   (cond ((null many)
	  (calc-graph-add-curve (calc-graph-lookup (calc-top-n 2))
				(calc-graph-lookup (calc-top-n 1))))
	 ((or (consp many) (eq many 0))
	  (let ((xdata (calc-graph-lookup (calc-top-n 2)))
		(ylist (calc-top-n 1)))
	    (or (eq (car-safe ylist) 'vec)
		(error "Y argument must be a vector"))
	    (while (setq ylist (cdr ylist))
	      (calc-graph-add-curve xdata (calc-graph-lookup (car ylist))))))
	 ((> (setq many (prefix-numeric-value many)) 0)
	  (let ((xdata (calc-graph-lookup (calc-top-n (1+ many)))))
	    (while (> many 0)
	      (calc-graph-add-curve xdata
				    (calc-graph-lookup (calc-top-n many)))
	      (setq many (1- many)))))
	 (t
	  (let (pair)
	    (setq many (- many))
	    (while (> many 0)
	      (setq pair (calc-top-n many))
	      (or (and (eq (car-safe pair) 'vec)
		       (= (length pair) 3))
		  (error "Argument must be an [x,y] vector"))
	      (calc-graph-add-curve (calc-graph-lookup (nth 1 pair))
				    (calc-graph-lookup (nth 2 pair)))
	      (setq many (1- many))))))
148
   (calc-graph-view-commands)))
Eli Zaretskii's avatar
Eli Zaretskii committed
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

(defun calc-graph-add-3d (many)
  (interactive "P")
  (calc-wrapper
   (calc-graph-init)
   (cond ((null many)
	  (calc-graph-add-curve (calc-graph-lookup (calc-top-n 3))
				(calc-graph-lookup (calc-top-n 2))
				(calc-graph-lookup (calc-top-n 1))))
	 ((or (consp many) (eq many 0))
	  (let ((xdata (calc-graph-lookup (calc-top-n 3)))
		(ydata (calc-graph-lookup (calc-top-n 2)))
		(zlist (calc-top-n 1)))
	    (or (eq (car-safe zlist) 'vec)
		(error "Z argument must be a vector"))
	    (while (setq zlist (cdr zlist))
	      (calc-graph-add-curve xdata ydata
				    (calc-graph-lookup (car zlist))))))
	 ((> (setq many (prefix-numeric-value many)) 0)
	  (let ((xdata (calc-graph-lookup (calc-top-n (+ many 2))))
		(ydata (calc-graph-lookup (calc-top-n (+ many 1)))))
	    (while (> many 0)
	      (calc-graph-add-curve xdata ydata
				    (calc-graph-lookup (calc-top-n many)))
	      (setq many (1- many)))))
	 (t
	  (let (curve)
	    (setq many (- many))
	    (while (> many 0)
	      (setq curve (calc-top-n many))
	      (or (and (eq (car-safe curve) 'vec)
		       (= (length curve) 4))
		  (error "Argument must be an [x,y,z] vector"))
	      (calc-graph-add-curve (calc-graph-lookup (nth 1 curve))
				    (calc-graph-lookup (nth 2 curve))
				    (calc-graph-lookup (nth 3 curve)))
	      (setq many (1- many))))))
186
   (calc-graph-view-commands)))
Eli Zaretskii's avatar
Eli Zaretskii committed
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214

(defun calc-graph-add-curve (xdata ydata &optional zdata)
  (let ((num (calc-graph-count-curves))
	(pstyle (calc-var-value 'var-PointStyles))
	(lstyle (calc-var-value 'var-LineStyles)))
    (save-excursion
      (set-buffer calc-gnuplot-input)
      (goto-char (point-min))
      (if (re-search-forward (if zdata "^plot[ \t]" "^splot[ \t]")
			     nil t)
	  (error "Can't mix 2d and 3d curves on one graph"))
      (if (re-search-forward "^s?plot[ \t]" nil t)
	  (progn
	    (end-of-line)
	    (insert ", "))
	(goto-char (point-max))
	(or (eq (preceding-char) ?\n)
	    (insert "\n"))
	(insert (if zdata "splot" "plot") " \n")
	(forward-char -1))
      (insert "{" (symbol-name (nth 1 xdata))
	      ":" (symbol-name (nth 1 ydata)))
      (if zdata
	  (insert ":" (symbol-name (nth 1 zdata))))
      (insert "} "
	      "title \"" (symbol-name (nth 1 ydata)) "\" "
	      "with dots")
      (setq pstyle (and (eq (car-safe pstyle) 'vec) (nth (1+ num) pstyle)))
215 216 217 218 219 220 221
      (setq lstyle (and (eq (car-safe lstyle) 'vec) (nth (1+ num) lstyle))))
    (calc-graph-set-styles
     (or (and (Math-num-integerp lstyle) (math-trunc lstyle))
         0)
     (or (and (Math-num-integerp pstyle) (math-trunc pstyle))
         (if (eq (car-safe (calc-var-value (nth 2 ydata))) 'vec)
             0 -1)))))
Eli Zaretskii's avatar
Eli Zaretskii committed
222 223 224 225 226 227 228

(defun calc-graph-lookup (thing)
  (if (and (eq (car-safe thing) 'var)
	   (calc-var-value (nth 2 thing)))
      thing
    (let ((found (assoc thing calc-graph-var-cache)))
      (or found
Jay Belanger's avatar
Jay Belanger committed
229 230 231 232
	  (let ((varname (concat "PlotData"
                                 (int-to-string
                                  (1+ (length calc-graph-var-cache))))))
            (setq var (list 'var (intern varname)
Eli Zaretskii's avatar
Eli Zaretskii committed
233 234 235 236
			    (intern (concat "var-" varname)))
		  found (cons thing var)
		  calc-graph-var-cache (cons found calc-graph-var-cache))
	    (set (nth 2 var) thing)))
237
      (cdr found))))
Eli Zaretskii's avatar
Eli Zaretskii committed
238 239 240 241 242 243 244 245 246 247 248 249

(defun calc-graph-juggle (arg)
  (interactive "p")
  (calc-graph-init)
  (save-excursion
    (set-buffer calc-gnuplot-input)
    (if (< arg 0)
	(let ((num (calc-graph-count-curves)))
	  (if (> num 0)
	      (while (< arg 0)
		(setq arg (+ arg num))))))
    (while (>= (setq arg (1- arg)) 0)
250
      (calc-graph-do-juggle))))
Eli Zaretskii's avatar
Eli Zaretskii committed
251 252 253 254 255 256 257 258 259 260

(defun calc-graph-count-curves ()
  (save-excursion
    (set-buffer calc-gnuplot-input)
    (if (re-search-forward "^s?plot[ \t]" nil t)
	(let ((num 1))
	  (goto-char (point-min))
	  (while (search-forward "," nil t)
	    (setq num (1+ num)))
	  num)
261
      0)))
Eli Zaretskii's avatar
Eli Zaretskii committed
262 263 264 265 266 267 268 269 270 271 272

(defun calc-graph-do-juggle ()
  (let (base)
    (and (calc-graph-find-plot t t)
	 (progn
	   (setq base (point))
	   (calc-graph-find-plot t nil)
	   (or (eq base (point))
	       (let ((str (buffer-substring (+ (point) 2) (1- (point-max)))))
		 (delete-region (point) (1- (point-max)))
		 (goto-char (+ base 5))
273
		 (insert str ", ")))))))
Eli Zaretskii's avatar
Eli Zaretskii committed
274 275 276

(defun calc-graph-print (flag)
  (interactive "P")
277
  (calc-graph-plot flag t))
Eli Zaretskii's avatar
Eli Zaretskii committed
278

Jay Belanger's avatar
Jay Belanger committed
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
(defvar var-DUMMY)
(defvar var-DUMMY2)
(defvar var-PlotRejects)

;; The following variables are local to calc-graph-plot, but are 
;; used in the functions calc-graph-compute-2d, calc-graph-refine-2d,
;; calc-graph-recompute-2d, calc-graph-compute-3d and 
;; calc-graph-format-data, which are called by calc-graph-plot.
(defvar calc-graph-yvalue)
(defvar calc-graph-yvec)
(defvar calc-graph-numsteps)
(defvar calc-graph-numsteps3)
(defvar calc-graph-xvalue)
(defvar calc-graph-xvec)
(defvar calc-graph-xname)
(defvar calc-graph-yname)
(defvar calc-graph-xstep)
(defvar calc-graph-ycache)
(defvar calc-graph-ycacheptr)
(defvar calc-graph-refine)
(defvar calc-graph-keep-file)
(defvar calc-graph-xval)
(defvar calc-graph-xlow)
(defvar calc-graph-xhigh)
(defvar calc-graph-yval)
(defvar calc-graph-yp)
(defvar calc-graph-xp)
(defvar calc-graph-zp)
(defvar calc-graph-yvector)
(defvar calc-graph-resolution)
(defvar calc-graph-y3value)
(defvar calc-graph-y3name)
(defvar calc-graph-y3step)
(defvar calc-graph-zval)
(defvar calc-graph-stepcount)
(defvar calc-graph-is-splot)
(defvar calc-graph-surprise-splot)
(defvar calc-graph-blank)
(defvar calc-graph-non-blank)
(defvar calc-graph-curve-num)

Eli Zaretskii's avatar
Eli Zaretskii committed
320 321 322 323 324 325 326
(defun calc-graph-plot (flag &optional printing)
  (interactive "P")
  (calc-slow-wrapper
   (let ((calcbuf (current-buffer))
	 (tempbuf (get-buffer-create "*Gnuplot Temp-2*"))
	 (tempbuftop 1)
	 (tempoutfile nil)
Jay Belanger's avatar
Jay Belanger committed
327 328
	 (calc-graph-curve-num 0)
	 (calc-graph-refine (and flag (> (prefix-numeric-value flag) 0)))
Eli Zaretskii's avatar
Eli Zaretskii committed
329
	 (recompute (and flag (< (prefix-numeric-value flag) 0)))
Jay Belanger's avatar
Jay Belanger committed
330
	 (calc-graph-surprise-splot nil)
Eli Zaretskii's avatar
Eli Zaretskii committed
331
	 (tty-output nil)
Jay Belanger's avatar
Jay Belanger committed
332 333
	 cache-env calc-graph-is-splot device output calc-graph-resolution precision samples-pos)
     (add-hook 'kill-emacs-hook 'calc-graph-kill-hook)
Eli Zaretskii's avatar
Eli Zaretskii committed
334 335 336 337 338 339
     (save-excursion
       (calc-graph-init)
       (set-buffer tempbuf)
       (erase-buffer)
       (set-buffer calc-gnuplot-input)
       (goto-char (point-min))
Jay Belanger's avatar
Jay Belanger committed
340
       (setq calc-graph-is-splot (re-search-forward "^splot[ \t]" nil t))
Eli Zaretskii's avatar
Eli Zaretskii committed
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
       (let ((str (buffer-string))
	     (ver calc-gnuplot-version))
	 (set-buffer (get-buffer-create "*Gnuplot Temp*"))
	 (erase-buffer)
	 (insert "# (Note: This is a temporary copy---do not edit!)\n")
	 (if (>= ver 2)
	     (insert "set noarrow\nset nolabel\n"
		     "set autoscale xy\nset nologscale xy\n"
		     "set xlabel\nset ylabel\nset title\n"
		     "set noclip points\nset clip one\nset clip two\n"
		     "set format \"%g\"\nset tics\nset xtics\nset ytics\n"
		     "set data style linespoints\n"
		     "set nogrid\nset nokey\nset nopolar\n"))
	 (if (>= ver 3)
	     (insert "set surface\nset nocontour\n"
Jay Belanger's avatar
Jay Belanger committed
356
		     "set " (if calc-graph-is-splot "" "no") "parametric\n"
Eli Zaretskii's avatar
Eli Zaretskii committed
357 358 359 360 361
		     "set notime\nset border\nset ztics\nset zeroaxis\n"
		     "set view 60,30,1,1\nset offsets 0,0,0,0\n"))
	 (setq samples-pos (point))
	 (insert "\n\n" str))
       (goto-char (point-min))
Jay Belanger's avatar
Jay Belanger committed
362 363
       (if calc-graph-is-splot
	   (if calc-graph-refine
Eli Zaretskii's avatar
Eli Zaretskii committed
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
	       (error "This option works only for 2d plots")
	     (setq recompute t)))
       (let ((calc-gnuplot-input (current-buffer))
	     (calc-graph-no-auto-view t))
	 (if printing
	     (setq device calc-gnuplot-print-device
		   output calc-gnuplot-print-output)
	   (setq device (calc-graph-find-command "terminal")
		 output (calc-graph-find-command "output"))
	   (or device
	       (setq device calc-gnuplot-default-device))
	   (if output
	       (setq output (car (read-from-string output)))
	     (setq output calc-gnuplot-default-output)))
	 (if (or (equal device "") (equal device "default"))
	     (setq device (if printing
			      "postscript"
			    (if (or (eq window-system 'x) (getenv "DISPLAY"))
				"x11"
			      (if (>= calc-gnuplot-version 3)
				  "dumb" "postscript")))))
	 (if (equal device "dumb")
	     (setq device (format "dumb %d %d"
387
				  (1- (frame-width)) (1- (frame-height)))))
Eli Zaretskii's avatar
Eli Zaretskii committed
388 389
	 (if (equal device "big")
	     (setq device (format "dumb %d %d"
390 391
				  (* 4 (- (frame-width) 3))
				  (* 4 (- (frame-height) 3)))))
Eli Zaretskii's avatar
Eli Zaretskii committed
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
	 (if (stringp output)
	     (if (or (equal output "auto")
		     (and (equal output "tty") (setq tty-output t)))
		 (setq tempoutfile (calc-temp-file-name -1)
		       output tempoutfile))
	   (setq output (eval output)))
	 (or (equal device calc-graph-last-device)
	     (progn
	       (setq calc-graph-last-device device)
	       (calc-gnuplot-command "set terminal" device)))
	 (or (equal output calc-graph-last-output)
	     (progn
	       (setq calc-graph-last-output output)
	       (calc-gnuplot-command "set output"
				     (if (equal output "STDOUT")
					 ""
				       (prin1-to-string output)))))
Jay Belanger's avatar
Jay Belanger committed
409 410
	 (setq calc-graph-resolution (calc-graph-find-command "samples"))
	 (if calc-graph-resolution
411
	     (setq calc-graph-resolution (string-to-number calc-graph-resolution))
Jay Belanger's avatar
Jay Belanger committed
412
	   (setq calc-graph-resolution (if calc-graph-is-splot
Eli Zaretskii's avatar
Eli Zaretskii committed
413 414 415 416
				calc-graph-default-resolution-3d
			      calc-graph-default-resolution)))
	 (setq precision (calc-graph-find-command "precision"))
	 (if precision
417
	     (setq precision (string-to-number precision))
Eli Zaretskii's avatar
Eli Zaretskii committed
418 419 420 421 422 423
	   (setq precision calc-graph-default-precision))
	 (calc-graph-set-command "terminal")
	 (calc-graph-set-command "output")
	 (calc-graph-set-command "samples")
	 (calc-graph-set-command "precision"))
       (goto-char samples-pos)
Jay Belanger's avatar
Jay Belanger committed
424 425
       (insert "set samples " (int-to-string (max (if calc-graph-is-splot 20 200)
						  (+ 5 calc-graph-resolution))) "\n")
Eli Zaretskii's avatar
Eli Zaretskii committed
426 427 428 429
       (while (re-search-forward "{\\*[^}]+}[^,\n]*" nil t)
	 (delete-region (match-beginning 0) (match-end 0))
	 (if (looking-at ",")
	     (delete-char 1)
430
	   (while (memq (preceding-char) '(?\s ?\t))
Eli Zaretskii's avatar
Eli Zaretskii committed
431 432 433 434 435 436 437 438 439 440
	     (forward-char -1))
	   (if (eq (preceding-char) ?\,)
	       (delete-backward-char 1))))
       (save-excursion
	 (set-buffer calcbuf)
	 (setq cache-env (list calc-angle-mode
			       calc-complex-mode
			       calc-simplify-mode
			       calc-infinite-mode
			       calc-word-size
Jay Belanger's avatar
Jay Belanger committed
441
			       precision calc-graph-is-splot))
Eli Zaretskii's avatar
Eli Zaretskii committed
442 443 444 445 446 447 448 449 450
	 (if (and (not recompute)
		  (equal (cdr (car calc-graph-data-cache)) cache-env))
	     (while (> (length calc-graph-data-cache)
		       calc-graph-data-cache-limit)
	       (setcdr calc-graph-data-cache
		       (cdr (cdr calc-graph-data-cache))))
	   (setq calc-graph-data-cache (list (cons nil cache-env)))))
       (calc-graph-find-plot t t)
       (while (re-search-forward
Jay Belanger's avatar
Jay Belanger committed
451
	       (if calc-graph-is-splot
Eli Zaretskii's avatar
Eli Zaretskii committed
452 453 454
		   "{\\([^{}:\n]+\\):\\([^{}:\n]+\\):\\([^{}:\n]+\\)}"
		 "{\\([^{}:\n]+\\)\\(:\\)\\([^{}:\n]+\\)}")
	       nil t)
Jay Belanger's avatar
Jay Belanger committed
455 456 457 458 459
	 (setq calc-graph-curve-num (1+ calc-graph-curve-num))
	 (let* ((calc-graph-xname (buffer-substring (match-beginning 1) (match-end 1)))
		(xvar (intern (concat "var-" calc-graph-xname)))
		(calc-graph-xvalue (math-evaluate-expr (calc-var-value xvar)))
		(calc-graph-y3name (and calc-graph-is-splot
Eli Zaretskii's avatar
Eli Zaretskii committed
460 461
			     (buffer-substring (match-beginning 2)
					       (match-end 2))))
Jay Belanger's avatar
Jay Belanger committed
462 463 464 465 466
		(y3var (and calc-graph-is-splot (intern (concat "var-" calc-graph-y3name))))
		(calc-graph-y3value (and calc-graph-is-splot (calc-var-value y3var)))
		(calc-graph-yname (buffer-substring (match-beginning 3) (match-end 3)))
		(yvar (intern (concat "var-" calc-graph-yname)))
		(calc-graph-yvalue (calc-var-value yvar))
Eli Zaretskii's avatar
Eli Zaretskii committed
467 468
		filename)
	   (delete-region (match-beginning 0) (match-end 0))
Jay Belanger's avatar
Jay Belanger committed
469
	   (setq filename (calc-temp-file-name calc-graph-curve-num))
Eli Zaretskii's avatar
Eli Zaretskii committed
470 471 472
	   (save-excursion
	     (set-buffer calcbuf)
	     (let (tempbuftop
Jay Belanger's avatar
Jay Belanger committed
473 474 475 476 477 478 479 480 481 482
		   (calc-graph-xp calc-graph-xvalue)
		   (calc-graph-yp calc-graph-yvalue)
		   (calc-graph-zp nil)
		   (calc-graph-xlow nil) (calc-graph-xhigh nil) (y3low nil) (y3high nil)
		   calc-graph-xvec calc-graph-xval calc-graph-xstep var-DUMMY
		   y3val calc-graph-y3step var-DUMMY2 (calc-graph-zval nil)
		   calc-graph-yvec calc-graph-yval calc-graph-ycache calc-graph-ycacheptr calc-graph-yvector
		   calc-graph-numsteps calc-graph-numsteps3
		   (calc-graph-keep-file (and (not calc-graph-is-splot) (file-exists-p filename)))
		   (calc-graph-stepcount 0)
Eli Zaretskii's avatar
Eli Zaretskii committed
483 484 485 486 487 488
		   (calc-symbolic-mode nil)
		   (calc-prefer-frac nil)
		   (calc-internal-prec (max 3 precision))
		   (calc-simplify-mode (and (not (memq calc-simplify-mode
						       '(none num)))
					    calc-simplify-mode))
Jay Belanger's avatar
Jay Belanger committed
489 490
		   (calc-graph-blank t)
		   (calc-graph-non-blank nil)
Eli Zaretskii's avatar
Eli Zaretskii committed
491 492 493
		   (math-working-step 0)
		   (math-working-step-2 nil))
	       (save-excursion
Jay Belanger's avatar
Jay Belanger committed
494
		 (if calc-graph-is-splot
Eli Zaretskii's avatar
Eli Zaretskii committed
495 496 497 498
		     (calc-graph-compute-3d)
		   (calc-graph-compute-2d))
		 (set-buffer tempbuf)
		 (goto-char (point-max))
Jay Belanger's avatar
Jay Belanger committed
499 500 501 502
		 (insert "\n" calc-graph-xname)
		 (if calc-graph-is-splot
		     (insert ":" calc-graph-y3name))
		 (insert ":" calc-graph-yname "\n\n")
Eli Zaretskii's avatar
Eli Zaretskii committed
503 504 505 506
		 (setq tempbuftop (point))
		 (let ((calc-group-digits nil)
		       (calc-leading-zeros nil)
		       (calc-number-radix 10)
Jay Belanger's avatar
Jay Belanger committed
507 508
		       (entry (and (not calc-graph-is-splot)
				   (list calc-graph-xp calc-graph-yp calc-graph-xhigh calc-graph-numsteps))))
Eli Zaretskii's avatar
Eli Zaretskii committed
509
		   (or (equal entry
Jay Belanger's avatar
Jay Belanger committed
510
			      (nth 1 (nth (1+ calc-graph-curve-num)
Eli Zaretskii's avatar
Eli Zaretskii committed
511
					  calc-graph-file-cache)))
Jay Belanger's avatar
Jay Belanger committed
512 513
		       (setq calc-graph-keep-file nil))
		   (setcar (cdr (nth (1+ calc-graph-curve-num) calc-graph-file-cache))
Eli Zaretskii's avatar
Eli Zaretskii committed
514
			   entry)
Jay Belanger's avatar
Jay Belanger committed
515
		   (or calc-graph-keep-file
Eli Zaretskii's avatar
Eli Zaretskii committed
516
		       (calc-graph-format-data)))
Jay Belanger's avatar
Jay Belanger committed
517
		 (or calc-graph-keep-file
Eli Zaretskii's avatar
Eli Zaretskii committed
518
		     (progn
Jay Belanger's avatar
Jay Belanger committed
519
		       (or calc-graph-non-blank
Eli Zaretskii's avatar
Eli Zaretskii committed
520
			   (error "No valid data points for %s:%s"
Jay Belanger's avatar
Jay Belanger committed
521
				  calc-graph-xname calc-graph-yname))
Eli Zaretskii's avatar
Eli Zaretskii committed
522 523 524
		       (write-region tempbuftop (point-max) filename
				     nil 'quiet))))))
	   (insert (prin1-to-string filename))))
Jay Belanger's avatar
Jay Belanger committed
525
       (if calc-graph-surprise-splot
Eli Zaretskii's avatar
Eli Zaretskii committed
526
	   (setcdr cache-env nil))
Jay Belanger's avatar
Jay Belanger committed
527
       (if (= calc-graph-curve-num 0)
Eli Zaretskii's avatar
Eli Zaretskii committed
528 529 530 531
	   (progn
	     (calc-gnuplot-command "clear")
	     (calc-clear-command-flag 'clear-message)
	     (message "No data to plot!"))
Jay Belanger's avatar
Jay Belanger committed
532
	 (setq calc-graph-data-cache-limit (max calc-graph-curve-num
Eli Zaretskii's avatar
Eli Zaretskii committed
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
						calc-graph-data-cache-limit)
	       filename (calc-temp-file-name 0))
	 (write-region (point-min) (point-max) filename nil 'quiet)
	 (calc-gnuplot-command "load" (prin1-to-string filename))
	 (or (equal output "STDOUT")
	     calc-gnuplot-keep-outfile
	     (progn   ; need to close the output file before printing/plotting
	       (setq calc-graph-last-output "STDOUT")
	       (calc-gnuplot-command "set output")))
	 (let ((command (if printing
			    calc-gnuplot-print-command
			  (or calc-gnuplot-plot-command
			      (and (string-match "^dumb" device)
				   'calc-graph-show-dumb)
			      (and tty-output
				   'calc-graph-show-tty)))))
	   (if command
	       (if (stringp command)
		   (calc-gnuplot-command
		    "!" (format command
				(or tempoutfile
				    calc-gnuplot-print-output)))
		 (if (symbolp command)
		     (funcall command output)
557
		   (eval command))))))))))
Eli Zaretskii's avatar
Eli Zaretskii committed
558 559

(defun calc-graph-compute-2d ()
Jay Belanger's avatar
Jay Belanger committed
560 561
  (if (setq calc-graph-yvec (eq (car-safe calc-graph-yvalue) 'vec))
      (if (= (setq calc-graph-numsteps (1- (length calc-graph-yvalue))) 0)
Eli Zaretskii's avatar
Eli Zaretskii committed
562
	  (error "Can't plot an empty vector")
Jay Belanger's avatar
Jay Belanger committed
563 564 565 566 567 568 569 570 571 572 573 574 575
	(if (setq calc-graph-xvec (eq (car-safe calc-graph-xvalue) 'vec))
	    (or (= (1- (length calc-graph-xvalue)) calc-graph-numsteps)
		(error "%s and %s have different lengths" calc-graph-xname calc-graph-yname))
	  (if (and (eq (car-safe calc-graph-xvalue) 'intv)
		   (math-constp calc-graph-xvalue))
	      (setq calc-graph-xstep (math-div (math-sub (nth 3 calc-graph-xvalue)
					      (nth 2 calc-graph-xvalue))
				    (1- calc-graph-numsteps))
		    calc-graph-xvalue (nth 2 calc-graph-xvalue))
	    (if (math-realp calc-graph-xvalue)
		(setq calc-graph-xstep 1)
	      (error "%s is not a suitable basis for %s" calc-graph-xname calc-graph-yname)))))
    (or (math-realp calc-graph-yvalue)
Eli Zaretskii's avatar
Eli Zaretskii committed
576
	(let ((arglist nil))
Jay Belanger's avatar
Jay Belanger committed
577 578
	  (setq calc-graph-yvalue (math-evaluate-expr calc-graph-yvalue))
	  (calc-default-formula-arglist calc-graph-yvalue)
Eli Zaretskii's avatar
Eli Zaretskii committed
579
	  (or arglist
Jay Belanger's avatar
Jay Belanger committed
580
	      (error "%s does not contain any unassigned variables" calc-graph-yname))
Eli Zaretskii's avatar
Eli Zaretskii committed
581 582
	  (and (cdr arglist)
	       (error "%s contains more than one variable: %s"
Jay Belanger's avatar
Jay Belanger committed
583 584
		      calc-graph-yname arglist))
	  (setq calc-graph-yvalue (math-expr-subst calc-graph-yvalue
Eli Zaretskii's avatar
Eli Zaretskii committed
585 586
					(math-build-var-name (car arglist))
					'(var DUMMY var-DUMMY)))))
Jay Belanger's avatar
Jay Belanger committed
587 588
    (setq calc-graph-ycache (assoc calc-graph-yvalue calc-graph-data-cache))
    (delq calc-graph-ycache calc-graph-data-cache)
Eli Zaretskii's avatar
Eli Zaretskii committed
589
    (nconc calc-graph-data-cache
Jay Belanger's avatar
Jay Belanger committed
590 591 592
	   (list (or calc-graph-ycache (setq calc-graph-ycache (list calc-graph-yvalue)))))
    (if (and (not (setq calc-graph-xvec (eq (car-safe calc-graph-xvalue) 'vec)))
	     calc-graph-refine (cdr (cdr calc-graph-ycache)))
Eli Zaretskii's avatar
Eli Zaretskii committed
593
	(calc-graph-refine-2d)
594
      (calc-graph-recompute-2d))))
Eli Zaretskii's avatar
Eli Zaretskii committed
595 596

(defun calc-graph-refine-2d ()
Jay Belanger's avatar
Jay Belanger committed
597 598 599
  (setq calc-graph-keep-file nil
	calc-graph-ycacheptr (cdr calc-graph-ycache))
  (if (and (setq calc-graph-xval (calc-graph-find-command "xrange"))
Eli Zaretskii's avatar
Eli Zaretskii committed
600
	   (string-match "\\`\\[\\([0-9.eE+-]*\\):\\([0-9.eE+-]*\\)\\]\\'"
Jay Belanger's avatar
Jay Belanger committed
601
			 calc-graph-xval))
Eli Zaretskii's avatar
Eli Zaretskii committed
602 603
      (let ((b2 (match-beginning 2))
	    (e2 (match-end 2)))
Jay Belanger's avatar
Jay Belanger committed
604
	(setq calc-graph-xlow (math-read-number (substring calc-graph-xval
Eli Zaretskii's avatar
Eli Zaretskii committed
605 606
						(match-beginning 1)
						(match-end 1)))
Jay Belanger's avatar
Jay Belanger committed
607 608 609 610 611 612 613 614 615 616 617
	      calc-graph-xhigh (math-read-number (substring calc-graph-xval b2 e2))))
    (if calc-graph-xlow
	(while (and (cdr calc-graph-ycacheptr)
		    (Math-lessp (car (nth 1 calc-graph-ycacheptr)) calc-graph-xlow))
	  (setq calc-graph-ycacheptr (cdr calc-graph-ycacheptr)))))
  (setq math-working-step-2 (1- (length calc-graph-ycacheptr)))
  (while (and (cdr calc-graph-ycacheptr)
	      (or (not calc-graph-xhigh)
		  (Math-lessp (car (car calc-graph-ycacheptr)) calc-graph-xhigh)))
    (setq var-DUMMY (math-div (math-add (car (car calc-graph-ycacheptr))
					(car (nth 1 calc-graph-ycacheptr)))
Eli Zaretskii's avatar
Eli Zaretskii committed
618 619
			      2)
	  math-working-step (1+ math-working-step)
Jay Belanger's avatar
Jay Belanger committed
620 621 622 623 624 625
	  calc-graph-yval (math-evaluate-expr calc-graph-yvalue))
    (setcdr calc-graph-ycacheptr (cons (cons var-DUMMY calc-graph-yval)
			    (cdr calc-graph-ycacheptr)))
    (setq calc-graph-ycacheptr (cdr (cdr calc-graph-ycacheptr))))
  (setq calc-graph-yp calc-graph-ycache
	calc-graph-numsteps 1000000))
Eli Zaretskii's avatar
Eli Zaretskii committed
626 627

(defun calc-graph-recompute-2d ()
Jay Belanger's avatar
Jay Belanger committed
628 629 630 631 632 633 634 635 636 637 638 639 640
  (setq calc-graph-ycacheptr calc-graph-ycache)
  (if calc-graph-xvec
      (setq calc-graph-numsteps (1- (length calc-graph-xvalue))
	    calc-graph-yvector nil)
    (if (and (eq (car-safe calc-graph-xvalue) 'intv)
	     (math-constp calc-graph-xvalue))
	(setq calc-graph-numsteps calc-graph-resolution
	      calc-graph-yp nil
	      calc-graph-xlow (nth 2 calc-graph-xvalue)
	      calc-graph-xhigh (nth 3 calc-graph-xvalue)
	      calc-graph-xstep (math-div (math-sub calc-graph-xhigh calc-graph-xlow)
			      (1- calc-graph-numsteps))
	      calc-graph-xvalue (nth 2 calc-graph-xvalue))
Eli Zaretskii's avatar
Eli Zaretskii committed
641
      (error "%s is not a suitable basis for %s"
Jay Belanger's avatar
Jay Belanger committed
642 643 644
	     calc-graph-xname calc-graph-yname)))
  (setq math-working-step-2 calc-graph-numsteps)
  (while (>= (setq calc-graph-numsteps (1- calc-graph-numsteps)) 0)
Eli Zaretskii's avatar
Eli Zaretskii committed
645
    (setq math-working-step (1+ math-working-step))
Jay Belanger's avatar
Jay Belanger committed
646
    (if calc-graph-xvec
Eli Zaretskii's avatar
Eli Zaretskii committed
647
	(progn
Jay Belanger's avatar
Jay Belanger committed
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
	  (setq calc-graph-xp (cdr calc-graph-xp)
		calc-graph-xval (car calc-graph-xp))
	  (and (not (eq calc-graph-ycacheptr calc-graph-ycache))
	       (consp (car calc-graph-ycacheptr))
	       (not (Math-lessp (car (car calc-graph-ycacheptr)) calc-graph-xval))
	       (setq calc-graph-ycacheptr calc-graph-ycache)))
      (if (= calc-graph-numsteps 0)
	  (setq calc-graph-xval calc-graph-xhigh)   ; avoid cumulative roundoff
	(setq calc-graph-xval calc-graph-xvalue
	      calc-graph-xvalue (math-add calc-graph-xvalue calc-graph-xstep))))
    (while (and (cdr calc-graph-ycacheptr)
		(Math-lessp (car (nth 1 calc-graph-ycacheptr)) calc-graph-xval))
      (setq calc-graph-ycacheptr (cdr calc-graph-ycacheptr)))
    (or (and (cdr calc-graph-ycacheptr)
	     (Math-equal (car (nth 1 calc-graph-ycacheptr)) calc-graph-xval))
Eli Zaretskii's avatar
Eli Zaretskii committed
663
	(progn
Jay Belanger's avatar
Jay Belanger committed
664 665 666 667 668 669 670 671 672 673 674 675 676 677
	  (setq calc-graph-keep-file nil
		var-DUMMY calc-graph-xval)
	  (setcdr calc-graph-ycacheptr (cons (cons calc-graph-xval (math-evaluate-expr calc-graph-yvalue))
				  (cdr calc-graph-ycacheptr)))))
    (setq calc-graph-ycacheptr (cdr calc-graph-ycacheptr))
    (if calc-graph-xvec
	(setq calc-graph-yvector (cons (cdr (car calc-graph-ycacheptr)) calc-graph-yvector))
      (or calc-graph-yp (setq calc-graph-yp calc-graph-ycacheptr))))
  (if calc-graph-xvec
      (setq calc-graph-xp calc-graph-xvalue
	    calc-graph-yvec t
	    calc-graph-yp (cons 'vec (nreverse calc-graph-yvector))
	    calc-graph-numsteps (1- (length calc-graph-xp)))
    (setq calc-graph-numsteps 1000000)))
Eli Zaretskii's avatar
Eli Zaretskii committed
678 679

(defun calc-graph-compute-3d ()
Jay Belanger's avatar
Jay Belanger committed
680 681
  (if (setq calc-graph-yvec (eq (car-safe calc-graph-yvalue) 'vec))
      (if (math-matrixp calc-graph-yvalue)
Eli Zaretskii's avatar
Eli Zaretskii committed
682
	  (progn
Jay Belanger's avatar
Jay Belanger committed
683 684 685 686 687 688 689 690 691
	    (setq calc-graph-numsteps (1- (length calc-graph-yvalue))
		  calc-graph-numsteps3 (1- (length (nth 1 calc-graph-yvalue))))
	    (if (eq (car-safe calc-graph-xvalue) 'vec)
		(or (= (1- (length calc-graph-xvalue)) calc-graph-numsteps)
		    (error "%s has wrong length" calc-graph-xname))
	      (if (and (eq (car-safe calc-graph-xvalue) 'intv)
		       (math-constp calc-graph-xvalue))
		  (setq calc-graph-xvalue (calcFunc-index calc-graph-numsteps
					       (nth 2 calc-graph-xvalue)
Eli Zaretskii's avatar
Eli Zaretskii committed
692
					       (math-div
Jay Belanger's avatar
Jay Belanger committed
693 694 695 696 697 698 699 700 701 702 703 704 705
						(math-sub (nth 3 calc-graph-xvalue)
							  (nth 2 calc-graph-xvalue))
						(1- calc-graph-numsteps))))
		(if (math-realp calc-graph-xvalue)
		    (setq calc-graph-xvalue (calcFunc-index calc-graph-numsteps calc-graph-xvalue 1))
		  (error "%s is not a suitable basis for %s" calc-graph-xname calc-graph-yname))))
	    (if (eq (car-safe calc-graph-y3value) 'vec)
		(or (= (1- (length calc-graph-y3value)) calc-graph-numsteps3)
		    (error "%s has wrong length" calc-graph-y3name))
	      (if (and (eq (car-safe calc-graph-y3value) 'intv)
		       (math-constp calc-graph-y3value))
		  (setq calc-graph-y3value (calcFunc-index calc-graph-numsteps3
						(nth 2 calc-graph-y3value)
Eli Zaretskii's avatar
Eli Zaretskii committed
706
						(math-div
Jay Belanger's avatar
Jay Belanger committed
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
						 (math-sub (nth 3 calc-graph-y3value)
							   (nth 2 calc-graph-y3value))
						 (1- calc-graph-numsteps3))))
		(if (math-realp calc-graph-y3value)
		    (setq calc-graph-y3value (calcFunc-index calc-graph-numsteps3 calc-graph-y3value 1))
		  (error "%s is not a suitable basis for %s" calc-graph-y3name calc-graph-yname))))
	    (setq calc-graph-xp nil
		  calc-graph-yp nil
		  calc-graph-zp nil
		  calc-graph-xvec t)
	    (while (setq calc-graph-xvalue (cdr calc-graph-xvalue) calc-graph-yvalue (cdr calc-graph-yvalue))
	      (setq calc-graph-xp (nconc calc-graph-xp (make-list (1+ calc-graph-numsteps3) (car calc-graph-xvalue)))
		    calc-graph-yp (nconc calc-graph-yp (cons 0 (copy-sequence (cdr calc-graph-y3value))))
		    calc-graph-zp (nconc calc-graph-zp (cons '(skip)
				       (copy-sequence (cdr (car calc-graph-yvalue)))))))
	    (setq calc-graph-numsteps (1- (* calc-graph-numsteps 
                                             (1+ calc-graph-numsteps3)))))
	(if (= (setq calc-graph-numsteps (1- (length calc-graph-yvalue))) 0)
Eli Zaretskii's avatar
Eli Zaretskii committed
725
	    (error "Can't plot an empty vector"))
Jay Belanger's avatar
Jay Belanger committed
726 727 728 729 730 731 732 733 734 735 736
	(or (and (eq (car-safe calc-graph-xvalue) 'vec)
		 (= (1- (length calc-graph-xvalue)) calc-graph-numsteps))
	    (error "%s is not a suitable basis for %s" calc-graph-xname calc-graph-yname))
	(or (and (eq (car-safe calc-graph-y3value) 'vec)
		 (= (1- (length calc-graph-y3value)) calc-graph-numsteps))
	    (error "%s is not a suitable basis for %s" calc-graph-y3name calc-graph-yname))
	(setq calc-graph-xp calc-graph-xvalue
	      calc-graph-yp calc-graph-y3value
	      calc-graph-zp calc-graph-yvalue
	      calc-graph-xvec t))
    (or (math-realp calc-graph-yvalue)
Eli Zaretskii's avatar
Eli Zaretskii committed
737
	(let ((arglist nil))
Jay Belanger's avatar
Jay Belanger committed
738 739
	  (setq calc-graph-yvalue (math-evaluate-expr calc-graph-yvalue))
	  (calc-default-formula-arglist calc-graph-yvalue)
Eli Zaretskii's avatar
Eli Zaretskii committed
740 741
	  (setq arglist (sort arglist 'string-lessp))
	  (or (cdr arglist)
Jay Belanger's avatar
Jay Belanger committed
742
	      (error "%s does not contain enough unassigned variables" calc-graph-yname))
Eli Zaretskii's avatar
Eli Zaretskii committed
743
	  (and (cdr (cdr arglist))
Jay Belanger's avatar
Jay Belanger committed
744 745
	       (error "%s contains too many variables: %s" calc-graph-yname arglist))
	  (setq calc-graph-yvalue (math-multi-subst calc-graph-yvalue
Eli Zaretskii's avatar
Eli Zaretskii committed
746 747 748 749
					 (mapcar 'math-build-var-name
						 arglist)
					 '((var DUMMY var-DUMMY)
					   (var DUMMY2 var-DUMMY2))))))
Jay Belanger's avatar
Jay Belanger committed
750 751 752 753 754 755 756 757 758 759
    (if (setq calc-graph-xvec (eq (car-safe calc-graph-xvalue) 'vec))
	(setq calc-graph-numsteps (1- (length calc-graph-xvalue)))
      (if (and (eq (car-safe calc-graph-xvalue) 'intv)
	       (math-constp calc-graph-xvalue))
	  (setq calc-graph-numsteps calc-graph-resolution
		calc-graph-xvalue (calcFunc-index calc-graph-numsteps
				       (nth 2 calc-graph-xvalue)
				       (math-div (math-sub (nth 3 calc-graph-xvalue)
							   (nth 2 calc-graph-xvalue))
						 (1- calc-graph-numsteps))))
Eli Zaretskii's avatar
Eli Zaretskii committed
760
	(error "%s is not a suitable basis for %s"
Jay Belanger's avatar
Jay Belanger committed
761 762 763 764 765 766 767 768 769 770 771
	       calc-graph-xname calc-graph-yname)))
    (if (eq (car-safe calc-graph-y3value) 'vec)
	(setq calc-graph-numsteps3 (1- (length calc-graph-y3value)))
      (if (and (eq (car-safe calc-graph-y3value) 'intv)
	       (math-constp calc-graph-y3value))
	  (setq calc-graph-numsteps3 calc-graph-resolution
		calc-graph-y3value (calcFunc-index calc-graph-numsteps3
					(nth 2 calc-graph-y3value)
					(math-div (math-sub (nth 3 calc-graph-y3value)
							    (nth 2 calc-graph-y3value))
						  (1- calc-graph-numsteps3))))
Eli Zaretskii's avatar
Eli Zaretskii committed
772
	(error "%s is not a suitable basis for %s"
Jay Belanger's avatar
Jay Belanger committed
773 774 775 776 777
	       calc-graph-y3name calc-graph-yname)))
    (setq calc-graph-xp nil
	  calc-graph-yp nil
	  calc-graph-zp nil
	  calc-graph-xvec t)
Eli Zaretskii's avatar
Eli Zaretskii committed
778
    (setq math-working-step 0)
Jay Belanger's avatar
Jay Belanger committed
779 780 781 782 783 784
    (while (setq calc-graph-xvalue (cdr calc-graph-xvalue))
      (setq calc-graph-xp (nconc calc-graph-xp (make-list (1+ calc-graph-numsteps3) (car calc-graph-xvalue)))
	    calc-graph-yp (nconc calc-graph-yp (cons 0 (copy-sequence (cdr calc-graph-y3value))))
	    calc-graph-zp (cons '(skip) calc-graph-zp)
	    calc-graph-y3step calc-graph-y3value
	    var-DUMMY (car calc-graph-xvalue)
Eli Zaretskii's avatar
Eli Zaretskii committed
785 786
	    math-working-step-2 0
	    math-working-step (1+ math-working-step))
Jay Belanger's avatar
Jay Belanger committed
787
      (while (setq calc-graph-y3step (cdr calc-graph-y3step))
Eli Zaretskii's avatar
Eli Zaretskii committed
788
	(setq math-working-step-2 (1+ math-working-step-2)
Jay Belanger's avatar
Jay Belanger committed
789 790 791 792
	      var-DUMMY2 (car calc-graph-y3step)
	      calc-graph-zp (cons (math-evaluate-expr calc-graph-yvalue) calc-graph-zp))))
    (setq calc-graph-zp (nreverse calc-graph-zp)
	  calc-graph-numsteps (1- (* calc-graph-numsteps (1+ calc-graph-numsteps3))))))
Eli Zaretskii's avatar
Eli Zaretskii committed
793 794

(defun calc-graph-format-data ()
Jay Belanger's avatar
Jay Belanger committed
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
  (while (<= (setq calc-graph-stepcount (1+ calc-graph-stepcount)) calc-graph-numsteps)
    (if calc-graph-xvec
	(setq calc-graph-xp (cdr calc-graph-xp)
	      calc-graph-xval (car calc-graph-xp)
	      calc-graph-yp (cdr calc-graph-yp)
	      calc-graph-yval (car calc-graph-yp)
	      calc-graph-zp (cdr calc-graph-zp)
	      calc-graph-zval (car calc-graph-zp))
      (if calc-graph-yvec
	  (setq calc-graph-xval calc-graph-xvalue
		calc-graph-xvalue (math-add calc-graph-xvalue calc-graph-xstep)
		calc-graph-yp (cdr calc-graph-yp)
		calc-graph-yval (car calc-graph-yp))
	(setq calc-graph-xval (car (car calc-graph-yp))
	      calc-graph-yval (cdr (car calc-graph-yp))
	      calc-graph-yp (cdr calc-graph-yp))
	(if (or (not calc-graph-yp)
		(and calc-graph-xhigh (equal calc-graph-xval calc-graph-xhigh)))
	    (setq calc-graph-numsteps 0))))
    (if calc-graph-is-splot
	(if (and (eq (car-safe calc-graph-zval) 'calcFunc-xyz)
		 (= (length calc-graph-zval) 4))
	    (setq calc-graph-xval (nth 1 calc-graph-zval)
		  calc-graph-yval (nth 2 calc-graph-zval)
		  calc-graph-zval (nth 3 calc-graph-zval)))
      (if (and (eq (car-safe calc-graph-yval) 'calcFunc-xyz)
	       (= (length calc-graph-yval) 4))
Eli Zaretskii's avatar
Eli Zaretskii committed
822
	  (progn
Jay Belanger's avatar
Jay Belanger committed
823
	    (or calc-graph-surprise-splot
Eli Zaretskii's avatar
Eli Zaretskii committed
824 825 826 827 828 829
		(save-excursion
		  (set-buffer (get-buffer-create "*Gnuplot Temp*"))
		  (save-excursion
		    (goto-char (point-max))
		    (re-search-backward "^plot[ \t]")
		    (insert "set parametric\ns")
Jay Belanger's avatar
Jay Belanger committed
830 831 832 833 834 835 836 837 838 839 840
		    (setq calc-graph-surprise-splot t))))
	    (setq calc-graph-xval (nth 1 calc-graph-yval)
		  calc-graph-zval (nth 3 calc-graph-yval)
		  calc-graph-yval (nth 2 calc-graph-yval)))
	(if (and (eq (car-safe calc-graph-yval) 'calcFunc-xy)
		 (= (length calc-graph-yval) 3))
	    (setq calc-graph-xval (nth 1 calc-graph-yval)
		  calc-graph-yval (nth 2 calc-graph-yval)))))
    (if (and (Math-realp calc-graph-xval)
	     (Math-realp calc-graph-yval)
	     (or (not calc-graph-zval) (Math-realp calc-graph-zval)))
Eli Zaretskii's avatar
Eli Zaretskii committed
841
	(progn
Jay Belanger's avatar
Jay Belanger committed
842 843 844 845 846 847 848 849
	  (setq calc-graph-blank nil
		calc-graph-non-blank t)
	  (if (Math-integerp calc-graph-xval)
	      (insert (math-format-number calc-graph-xval))
	    (if (eq (car calc-graph-xval) 'frac)
		(setq calc-graph-xval (math-float calc-graph-xval)))
	    (insert (math-format-number (nth 1 calc-graph-xval))
		    "e" (int-to-string (nth 2 calc-graph-xval))))
Eli Zaretskii's avatar
Eli Zaretskii committed
850
	  (insert " ")
Jay Belanger's avatar
Jay Belanger committed
851 852 853 854 855 856 857
	  (if (Math-integerp calc-graph-yval)
	      (insert (math-format-number calc-graph-yval))
	    (if (eq (car calc-graph-yval) 'frac)
		(setq calc-graph-yval (math-float calc-graph-yval)))
	    (insert (math-format-number (nth 1 calc-graph-yval))
		    "e" (int-to-string (nth 2 calc-graph-yval))))
	  (if calc-graph-zval
Eli Zaretskii's avatar
Eli Zaretskii committed
858 859
	      (progn
		(insert " ")
Jay Belanger's avatar
Jay Belanger committed
860 861 862 863 864 865
		(if (Math-integerp calc-graph-zval)
		    (insert (math-format-number calc-graph-zval))
		  (if (eq (car calc-graph-zval) 'frac)
		      (setq calc-graph-zval (math-float calc-graph-zval)))
		  (insert (math-format-number (nth 1 calc-graph-zval))
			  "e" (int-to-string (nth 2 calc-graph-zval))))))
Eli Zaretskii's avatar
Eli Zaretskii committed
866
	  (insert "\n"))
Jay Belanger's avatar
Jay Belanger committed
867
      (and (not (equal calc-graph-zval '(skip)))
868
           (boundp 'var-PlotRejects)
Eli Zaretskii's avatar
Eli Zaretskii committed
869 870 871
	   (eq (car-safe var-PlotRejects) 'vec)
	   (nconc var-PlotRejects
		  (list (list 'vec
Jay Belanger's avatar
Jay Belanger committed
872 873 874
			      calc-graph-curve-num
			      calc-graph-stepcount
			      calc-graph-xval calc-graph-yval)))
Eli Zaretskii's avatar
Eli Zaretskii committed
875
	   (calc-refresh-evaltos 'var-PlotRejects))
Jay Belanger's avatar
Jay Belanger committed
876
      (or calc-graph-blank
Eli Zaretskii's avatar
Eli Zaretskii committed
877 878
	  (progn
	    (insert "\n")
Jay Belanger's avatar
Jay Belanger committed
879
	    (setq calc-graph-blank t))))))
Eli Zaretskii's avatar
Eli Zaretskii committed
880 881 882 883 884 885

(defun calc-temp-file-name (num)
  (while (<= (length calc-graph-file-cache) (1+ num))
    (setq calc-graph-file-cache (nconc calc-graph-file-cache (list nil))))
  (car (or (nth (1+ num) calc-graph-file-cache)
	   (setcar (nthcdr (1+ num) calc-graph-file-cache)
886
		   (list (make-temp-file
Eli Zaretskii's avatar
Eli Zaretskii committed
887 888 889 890
			  (concat calc-gnuplot-tempfile
				  (if (<= num 0)
				      (char-to-string (- ?A num))
				    (int-to-string num))))
891
			 nil)))))
Eli Zaretskii's avatar
Eli Zaretskii committed
892 893 894 895 896 897 898 899

(defun calc-graph-delete-temps ()
  (while calc-graph-file-cache
    (and (car calc-graph-file-cache)
	 (file-exists-p (car (car calc-graph-file-cache)))
	 (condition-case err
	     (delete-file (car (car calc-graph-file-cache)))
	   (error nil)))
900
    (setq calc-graph-file-cache (cdr calc-graph-file-cache))))
Eli Zaretskii's avatar
Eli Zaretskii committed
901 902

(defun calc-graph-kill-hook ()
Jay Belanger's avatar
Jay Belanger committed
903
  (calc-graph-delete-temps))
Eli Zaretskii's avatar
Eli Zaretskii committed
904 905 906 907 908 909

(defun calc-graph-show-tty (output)
  "Default calc-gnuplot-plot-command for \"tty\" output mode.
This is useful for tek40xx and other graphics-terminal types."
  (call-process-region 1 1 shell-file-name
		       nil calc-gnuplot-buffer nil
910
		       "-c" (format "cat %s >/dev/tty; rm %s" output output)))
Eli Zaretskii's avatar
Eli Zaretskii committed
911

Jay Belanger's avatar
Jay Belanger committed
912 913 914
(defvar calc-dumb-map nil
  "The keymap for the \"dumb\" terminal plot.")

Eli Zaretskii's avatar
Eli Zaretskii committed
915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
(defun calc-graph-show-dumb (&optional output)
  "Default calc-gnuplot-plot-command for Pinard's \"dumb\" terminal type.
This \"dumb\" driver will be present in Gnuplot 3.0."
  (interactive)
  (save-window-excursion
    (switch-to-buffer calc-gnuplot-buffer)
    (delete-other-windows)
    (goto-char calc-gnuplot-trail-mark)
    (or (search-forward "\f" nil t)
	(sleep-for 1))
    (goto-char (point-max))
    (re-search-backward "\f\\|^[ \t]+\\^$\\|G N U P L O T")
    (if (looking-at "\f")
	(progn
	  (forward-char 1)
	  (if (eolp) (forward-line 1))
	  (or (calc-graph-find-command "time")
	      (calc-graph-find-command "title")
	      (calc-graph-find-command "ylabel")
	      (let ((pt (point)))
		(insert-before-markers (format "(%s)" (current-time-string)))
		(goto-char pt)))
	  (set-window-start (selected-window) (point))
	  (goto-char (point-max)))
      (end-of-line)
      (backward-char 1)
      (recenter '(4)))
Jay Belanger's avatar
Jay Belanger committed
942
    (or calc-dumb-map
Eli Zaretskii's avatar
Eli Zaretskii committed
943 944 945 946 947 948 949 950 951 952 953 954 955
	(progn
	  (setq calc-dumb-map (make-sparse-keymap))
	  (define-key calc-dumb-map "\n" 'scroll-up)
	  (define-key calc-dumb-map " " 'scroll-up)
	  (define-key calc-dumb-map "\177" 'scroll-down)
	  (define-key calc-dumb-map "<" 'scroll-left)
	  (define-key calc-dumb-map ">" 'scroll-right)
	  (define-key calc-dumb-map "{" 'scroll-down)
	  (define-key calc-dumb-map "}" 'scroll-up)
	  (define-key calc-dumb-map "q" 'exit-recursive-edit)
	  (define-key calc-dumb-map "\C-c\C-c" 'exit-recursive-edit)))
    (use-local-map calc-dumb-map)
    (setq truncate-lines t)
956
    (message "Type `q' or `C-c C-c' to return to Calc")
Eli Zaretskii's avatar
Eli Zaretskii committed
957
    (recursive-edit)
958
    (bury-buffer "*Gnuplot Trail*")))
Eli Zaretskii's avatar
Eli Zaretskii committed
959 960 961 962 963 964 965 966 967 968

(defun calc-graph-clear ()
  (interactive)
  (if calc-graph-last-device
      (if (or (equal calc-graph-last-device "x11")
	      (equal calc-graph-last-device "X11"))
	  (calc-gnuplot-command "set output"
				(if (equal calc-graph-last-output "STDOUT")
				    ""
				  (prin1-to-string calc-graph-last-output)))
969
	(calc-gnuplot-command "clear"))))
Eli Zaretskii's avatar
Eli Zaretskii committed
970 971 972 973

(defun calc-graph-title-x (title)
  (interactive "sX axis title: ")
  (calc-graph-set-command "xlabel" (if (not (equal title ""))
974
				       (prin1-to-string title))))
Eli Zaretskii's avatar
Eli Zaretskii committed
975 976 977 978

(defun calc-graph-title-y (title)
  (interactive "sY axis title: ")
  (calc-graph-set-command "ylabel" (if (not (equal title ""))
979
				       (prin1-to-string title))))
Eli Zaretskii's avatar
Eli Zaretskii committed
980 981 982 983

(defun calc-graph-title-z (title)
  (interactive "sZ axis title: ")
  (calc-graph-set-command "zlabel" (if (not (equal title ""))
984
				       (prin1-to-string title))))
Eli Zaretskii's avatar
Eli Zaretskii committed
985 986 987

(defun calc-graph-range-x (range)
  (interactive "sX axis range: ")
988
  (calc-graph-set-range "xrange" range))
Eli Zaretskii's avatar
Eli Zaretskii committed
989 990 991

(defun calc-graph-range-y (range)
  (interactive "sY axis range: ")
992
  (calc-graph-set-range "yrange" range))
Eli Zaretskii's avatar
Eli Zaretskii committed
993 994 995

(defun calc-graph-range-z (range)
  (interactive "sZ axis range: ")
996
  (calc-graph-set-range "zrange" range))
Eli Zaretskii's avatar
Eli Zaretskii committed
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019

(defun calc-graph-set-range (cmd range)
  (if (equal range "$")
      (calc-wrapper
       (let ((val (calc-top-n 1)))
	 (if (and (eq (car-safe val) 'intv) (math-constp val))
	     (setq range (concat
			  (math-format-number (math-float (nth 2 val))) ":"
			  (math-format-number (math-float (nth 3 val)))))
	   (if (and (eq (car-safe val) 'vec)
		    (= (length val) 3))
	       (setq range (concat
			    (math-format-number (math-float (nth 1 val))) ":"
			    (math-format-number (math-float (nth 2 val)))))
	     (error "Range specification must be an interval or 2-vector")))
	 (calc-pop-stack 1))))
  (if (string-match "\\[.+\\]" range)
      (setq range (substring range 1 -1)))
  (if (and (not (string-match ":" range))
	   (or (string-match "," range)
	       (string-match " " range)))
      (aset range (match-beginning 0) ?\:))
  (calc-graph-set-command cmd (if (not (equal range ""))
1020
				  (concat "[" range "]"))))
Eli Zaretskii's avatar
Eli Zaretskii committed
1021 1022 1023

(defun calc-graph-log-x (flag)
  (interactive "P")
1024
  (calc-graph-set-log flag 0 0))
Eli Zaretskii's avatar
Eli Zaretskii committed
1025 1026 1027

(defun calc-graph-log-y (flag)
  (interactive "P")
1028
  (calc-graph-set-log 0 flag 0))
Eli Zaretskii's avatar
Eli Zaretskii committed
1029 1030 1031

(defun calc-graph-log-z (flag)
  (interactive "P")
1032
  (calc-graph-set-log 0 0 flag))
Eli Zaretskii's avatar
Eli Zaretskii committed
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051

(defun calc-graph-set-log (xflag yflag zflag)
  (let* ((old (or (calc-graph-find-command "logscale") ""))
	 (xold (string-match "x" old))
	 (yold (string-match "y" old))
	 (zold (string-match "z" old))
	 str)
    (setq str (concat (if (if xflag
			      (if (eq xflag 0) xold
				(> (prefix-numeric-value xflag) 0))
			    (not xold)) "x" "")
		      (if (if yflag
			      (if (eq yflag 0) yold
				(> (prefix-numeric-value yflag) 0))
			    (not yold)) "y" "")
		      (if (if zflag
			      (if (eq zflag 0) zold
				(> (prefix-numeric-value zflag) 0))
			    (not zold)) "z" "")))
1052
    (calc-graph-set-command "logscale" (if (not (equal str "")) str))))
Eli Zaretskii's avatar
Eli Zaretskii committed
1053 1054 1055

(defun calc-graph-line-style (style)
  (interactive "P")
1056
  (calc-graph-set-styles (and style (prefix-numeric-value style)) t))
Eli Zaretskii's avatar
Eli Zaretskii committed
1057 1058 1059

(defun calc-graph-point-style (style)
  (interactive "P")
1060
  (calc-graph-set-styles t (and style (prefix-numeric-value style))))
Eli Zaretskii's avatar
Eli Zaretskii committed
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082

(defun calc-graph-set-styles (lines points)
  (calc-graph-init)
  (save-excursion
    (set-buffer calc-gnuplot-input)
    (or (calc-graph-find-plot nil nil)
	(error "No data points have been set!"))
    (let ((base (point))
	  (mode nil) (lstyle nil) (pstyle nil)
	  start end lenbl penbl)
      (re-search-forward "[,\n]")
      (forward-char -1)
      (setq end (point) start end)
      (goto-char base)
      (if (looking-at "[^,\n]*[^,\n \t]\\([ \t]+with\\)")
	  (progn
	    (setq start (match-beginning 1))
	    (goto-char (match-end 0))
	    (if (looking-at "[ \t]+\\([a-z]+\\)")
		(setq mode (buffer-substring (match-beginning 1)
					     (match-end 1))))
	    (if (looking-at "[ \ta-z]+\\([0-9]+\\)")
1083
		(setq lstyle (string-to-number
Eli Zaretskii's avatar
Eli Zaretskii committed
1084 1085 1086
			      (buffer-substring (match-beginning 1)
						(match-end 1)))))
	    (if (looking-at "[ \ta-z]+[0-9]+[ \t]+\\([0-9]+\\)")
1087
		(setq pstyle (string-to-number
Eli Zaretskii's avatar
Eli Zaretskii committed
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
			      (buffer-substring (match-beginning 1)
						(match-end 1)))))))
      (setq lenbl (or (equal mode "lines") (equal mode "linespoints"))
	    penbl (or (equal mode "points") (equal mode "linespoints")))
      (if lines
	  (or (eq lines t)
	      (setq lstyle lines
		    lenbl (>= lines 0)))
	(setq lenbl (not lenbl)))
      (if points
	  (or (eq points t)
	      (setq pstyle points
		    penbl (>= points 0)))
	(setq penbl (not penbl)))
      (delete-region start end)
      (goto-char start)
      (insert " with "
	      (if lenbl
		  (if penbl "linespoints" "lines")
		(if penbl "points" "dots")))
      (if (and pstyle (> pstyle 0))
	  (insert " " (if (and lstyle (> lstyle 0)) (int-to-string lstyle) "1")
		  " " (int-to-string pstyle))
	(if (and lstyle (> lstyle 0))
	    (insert " " (int-to-string lstyle))))))
1113
  (calc-graph-view-commands))
Eli Zaretskii's avatar
Eli Zaretskii committed
1114 1115 1116 1117 1118 1119 1120

(defun calc-graph-zero-x (flag)
  (interactive "P")
  (calc-graph-set-command "noxzeroaxis"
			  (and (if flag
				   (<= (prefix-numeric-value flag) 0)
				 (not (calc-graph-find-command "noxzeroaxis")))
1121
			       " ")))
Eli Zaretskii's avatar
Eli Zaretskii committed
1122 1123 1124 1125 1126 1127 1128

(defun calc-graph-zero-y (flag)
  (interactive "P")
  (calc-graph-set-command "noyzeroaxis"
			  (and (if flag
				   (<= (prefix-numeric-value flag) 0)
				 (not (calc-graph-find-command "noyzeroaxis")))
1129
			       " ")))
Eli Zaretskii's avatar
Eli Zaretskii committed
1130 1131 1132 1133 1134 1135 1136 1137 1138

(defun calc-graph-name (name)
  (interactive "sTitle for current curve: ")
  (calc-graph-init)
  (save-excursion
    (set-buffer calc-gnuplot-input)
    (or (calc-graph-find-plot nil nil)
	(error "No data points have been set!"))
    (let ((base (point))
Jay Belanger's avatar
Jay Belanger committed
1139 1140
	  start
          end)
Eli Zaretskii's avatar
Eli Zaretskii committed
1141 1142 1143 1144 1145 1146 1147 1148 1149
      (re-search-forward "[,\n]\\|[ \t]+with")
      (setq end (match-beginning 0))
      (goto-char base)
      (if (looking-at "[^,\n]*[^,\n \t]\\([ \t]+title\\)")
	  (progn
	    (goto-char (match-beginning 1))
	    (delete-region (point) end))
	(goto-char end))
      (insert " title " (prin1-to-string name))))
1150
  (calc-graph-view-commands))
Eli Zaretskii's avatar
Eli Zaretskii committed
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163

(defun calc-graph-hide (flag)
  (interactive "P")
  (calc-graph-init)
  (and (calc-graph-find-plot nil nil)
       (progn
	 (or (looking-at "{")
	     (error "Can't hide this curve (wrong format)"))
	 (forward-char 1)
	 (if (looking-at "*")
	     (if (or (null flag) (<= (prefix-numeric-value flag) 0))
		 (delete-char 1))
	   (if (or (null flag) (> (prefix-numeric-value flag) 0))