2009-11-15 Carsten Dominik <carsten.dominik@gmail.com>
[bpt/emacs.git] / lisp / org / org-plot.el
index f8e268d..55c0877 100644 (file)
-;;; org-plot.el --- Support for plotting from Org-mode\r
-\r
-;; Copyright (C) 2008 Free Software Foundation, Inc.\r
-;;\r
-;; Author: Eric Schulte <schulte dot eric at gmail dot com>\r
-;; Keywords: tables, plotting\r
-;; Homepage: http://orgmode.org\r
-;; Version: 6.06b\r
-;;\r
-;; This file is part of GNU Emacs.\r
-;;\r
-;; GNU Emacs is free software: you can redistribute it and/or modify\r
-;; it under the terms of the GNU General Public License as published by\r
-;; the Free Software Foundation, either version 3 of the License, or\r
-;; (at your option) any later version.\r
-\r
-;; GNU Emacs is distributed in the hope that it will be useful,\r
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-;; GNU General Public License for more details.\r
-\r
-;; You should have received a copy of the GNU General Public License\r
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.\r
-\r
-;;; Commentary:\r
-\r
-;; Borrows ideas and a couple of lines of code from org-exp.el.\r
-\r
-;; Thanks to the org-mode mailing list for testing and implementation\r
-;; and feature suggestions\r
-\r
-;;; Code:\r
-(require 'org)\r
-(require 'org-exp)\r
-(require 'org-table)\r
-(eval-and-compile\r
-  (require 'cl))\r
-\r
-(declare-function gnuplot-delchar-or-maybe-eof "ext:gnuplot" (arg))\r
-(declare-function gnuplot-mode "ext:gnuplot" ())\r
-(declare-function gnuplot-send-buffer-to-gnuplot "ext:gnuplot" ())\r
-\r
-(defvar org-plot/gnuplot-default-options\r
-  '((:plot-type . 2d)\r
-    (:with . lines)\r
-    (:ind . 0))\r
-  "Default options to gnuplot used by `org-plot/gnuplot'")\r
-\r
-(defun org-plot/add-options-to-plist (p options)\r
-  "Parse an OPTIONS line and set values in the property list P.\r
-Returns the resulting property list."\r
-  (let (o)\r
-    (when options\r
-      (let ((op '(("type"   . :plot-type)\r
-                 ("script" . :script)\r
-                 ("line"   . :line)\r
-                 ("set"    . :set)\r
-                 ("title"  . :title)\r
-                 ("ind"    . :ind)\r
-                 ("deps"   . :deps)\r
-                 ("with"   . :with)\r
-                 ("file"   . :file)\r
-                 ("labels" . :labels)\r
-                 ("map"    . :map)))\r
-           (multiples '("set" "line"))\r
-           (regexp ":\\([\"][^\"]+?[\"]\\|[(][^)]+?[)]\\|[^ \t\n\r;,.]*\\)")\r
-           (start 0)\r
-           o)\r
-       (while (setq o (pop op))\r
-         (if (member (car o) multiples) ;; keys with multiple values\r
-             (while (string-match\r
-                     (concat (regexp-quote (car o)) regexp)\r
-                     options start)\r
-               (setq start (match-end 0))\r
-               (setq p (plist-put p (cdr o)\r
-                                  (cons (car (read-from-string\r
-                                              (match-string 1 options)))\r
-                                        (plist-get p (cdr o)))))\r
-               p)\r
-           (if (string-match (concat (regexp-quote (car o)) regexp)\r
-                             options)\r
-               (setq p (plist-put p (cdr o)\r
-                                  (car (read-from-string\r
-                                        (match-string 1 options)))))))))))\r
-  p)\r
-\r
-(defun org-plot/goto-nearest-table ()\r
-  "Move the point forward to the beginning of nearest table.\r
-Return value is the point at the beginning of the table."\r
-  (interactive) (move-beginning-of-line 1)\r
-  (while (not (or (org-at-table-p) (< 0 (forward-line 1)))))\r
-  (goto-char (org-table-begin)))\r
-\r
-(defun org-plot/collect-options (&optional params)\r
-  "Collect options from an org-plot '#+Plot:' line.\r
-Accepts an optional property list PARAMS, to which the options\r
-will be added.  Returns the resulting property list."\r
-  (interactive)\r
-  (let ((line (thing-at-point 'line)))\r
-    (if (string-match "#\\+PLOT: +\\(.*\\)$" line)\r
-       (org-plot/add-options-to-plist params (match-string 1 line))\r
-      params)))\r
-\r
-(defun org-plot-quote-tsv-field (s)\r
-  "Quote field S for export to gnuplot."\r
-  (if (string-match org-table-number-regexp s) s\r
-    (concat "\"" (mapconcat 'identity (split-string s "\"") "\"\"") "\"")))\r
-\r
-(defun org-plot/gnuplot-to-data (table data-file params)\r
-  "Export TABLE to DATA-FILE in a format readable by gnuplot.\r
-Pass PARAMS through to `orgtbl-to-generic' when exporting TABLE."\r
-  (with-temp-file\r
-      data-file (insert (orgtbl-to-generic\r
-                        table\r
-                        (org-combine-plists\r
-                         '(:sep "\t" :fmt org-plot-quote-tsv-field)\r
-                         params))))\r
-  nil)\r
-\r
-(defun org-plot/gnuplot-to-grid-data (table data-file params)\r
-  "Export the data in TABLE to DATA-FILE for gnuplot.\r
-This means, in a format appropriate for grid plotting by gnuplot.\r
-PARAMS specifies which columns of TABLE should be plotted as independant\r
-and dependant variables."\r
-  (interactive)\r
-  (let* ((ind (- (plist-get params :ind) 1))\r
-        (deps (if (plist-member params :deps)\r
-                  (mapcar (lambda (val) (- val 1)) (plist-get params :deps))\r
-                (let (collector)\r
-                  (dotimes (col (length (first table)))\r
-                    (setf collector (cons col collector)))\r
-                  collector)))\r
-        row-vals (counter 0))\r
-    (when (>= ind 0) ;; collect values of ind col\r
-      (setf row-vals (mapcar (lambda (row) (setf counter (+ 1 counter))\r
-                              (cons counter (nth ind row))) table)))\r
-    (when (or deps (>= ind 0)) ;; remove non-plotting columns\r
-      (setf deps (delq ind deps))\r
-      (setf table (mapcar (lambda (row)\r
-                           (dotimes (col (length row))\r
-                             (unless (memq col deps)\r
-                               (setf (nth col row) nil)))\r
-                           (delq nil row))\r
-                         table)))\r
-    ;; write table to gnuplot grid datafile format\r
-    (with-temp-file data-file\r
-      (let ((num-rows (length table)) (num-cols (length (first table)))\r
-           front-edge back-edge)\r
-       (flet ((gnuplot-row (col row value)\r
-                           (setf col (+ 1 col)) (setf row (+ 1 row))\r
-                           (format "%f  %f  %f\n%f  %f  %f\n"\r
-                                   col (- row 0.5) value ;; lower edge\r
-                                   col (+ row 0.5) value))) ;; upper edge\r
-         (dotimes (col num-cols)\r
-           (dotimes (row num-rows)\r
-             (setf back-edge\r
-                   (concat back-edge\r
-                           (gnuplot-row (- col 1) row (string-to-number\r
-                                                       (nth col (nth row table))))))\r
-             (setf front-edge\r
-                   (concat front-edge\r
-                           (gnuplot-row col row (string-to-number\r
-                                                 (nth col (nth row table)))))))\r
-           ;; only insert once per row\r
-           (insert back-edge) (insert "\n") ;; back edge\r
-           (insert front-edge) (insert "\n") ;; front edge\r
-           (setf back-edge "") (setf front-edge "")))))\r
-    row-vals))\r
-\r
-(defun org-plot/gnuplot-script (data-file num-cols params)\r
-  "Write a gnuplot script to DATA-FILE respecting the options set in PARAMS.\r
-NUM-COLS controls the number of columns plotted in a 2-d plot."\r
-  (let* ((type (plist-get params :plot-type))\r
-        (with (if (equal type 'grid)\r
-                  'pm3d\r
-                (plist-get params :with)))\r
-        (sets (plist-get params :set))\r
-        (lines (plist-get params :line))\r
-        (map (plist-get params :map))\r
-        (title (plist-get params :title))\r
-        (file (plist-get params :file))\r
-        (ind (plist-get params :ind))\r
-        (text-ind (plist-get params :textind))\r
-        (deps (if (plist-member params :deps) (plist-get params :deps)))\r
-        (col-labels (plist-get params :labels))\r
-        (x-labels (plist-get params :xlabels))\r
-        (y-labels (plist-get params :ylabels))\r
-        (plot-str "'%s' using %s%d%s with %s title '%s'")\r
-        (plot-cmd (case type\r
-                    ('2d "plot")\r
-                    ('3d "splot")\r
-                    ('grid "splot")))\r
-        (script "reset") plot-lines)\r
-    (flet ((add-to-script (line) (setf script (format "%s\n%s" script line))))\r
-      (when file ;; output file\r
-       (add-to-script (format "set term %s" (file-name-extension file)))\r
-       (add-to-script (format "set output '%s'" file)))\r
-      (case type ;; type\r
-       ('2d ())\r
-       ('3d (if map (add-to-script "set map")))\r
-       ('grid (if map\r
-                  (add-to-script "set pm3d map")\r
-                (add-to-script "set pm3d"))))\r
-      (when title (add-to-script (format "set title '%s'" title))) ;; title\r
-      (when lines (mapc (lambda (el) (add-to-script el)) lines)) ;; line\r
-      (when sets ;; set\r
-       (mapc (lambda (el) (add-to-script (format "set %s" el))) sets))\r
-      (when x-labels ;; x labels (xtics)\r
-       (add-to-script\r
-        (format "set xtics (%s)"\r
-                (mapconcat (lambda (pair)\r
-                             (format "\"%s\" %d" (cdr pair) (car pair)))\r
-                           x-labels ", "))))\r
-      (when y-labels ;; y labels (ytics)\r
-       (add-to-script\r
-        (format "set ytics (%s)"\r
-                (mapconcat (lambda (pair)\r
-                             (format "\"%s\" %d" (cdr pair) (car pair)))\r
-                           y-labels ", "))))\r
-      (case type ;; plot command\r
-       ('2d (dotimes (col num-cols)\r
-              (unless (and (equal type '2d)\r
-                           (or (and ind (equal (+ 1 col) ind))\r
-                               (and deps (not (member (+ 1 col) deps)))))\r
-                (setf plot-lines\r
-                      (cons\r
-                       (format plot-str data-file\r
-                               (or (and (not text-ind) ind\r
-                                        (> ind 0) (format "%d:" ind)) "")\r
-                               (+ 1 col)\r
-                               (if text-ind (format ":xticlabel(%d)" ind) "")\r
-                               with\r
-                               (or (nth col col-labels) (format "%d" (+ 1 col))))\r
-                       plot-lines)))))\r
-       ('3d\r
-        (setq plot-lines (list (format "'%s' matrix with %s title ''"\r
-                                       data-file with))))\r
-       ('grid\r
-        (setq plot-lines (list (format "'%s' with %s title ''"\r
-                                       data-file with)))))\r
-      (add-to-script\r
-       (concat plot-cmd " " (mapconcat 'identity (reverse plot-lines) ",\\\n    ")))\r
-      script)))\r
-\r
-;;-----------------------------------------------------------------------------\r
-;; facade functions\r
-;;;###autoload\r
-(defun org-plot/gnuplot (&optional params)\r
-  "Plot table using gnuplot. Gnuplot options can be specified with PARAMS.\r
-If not given options will be taken from the +PLOT\r
-line directly before or after the table."\r
-  (interactive)\r
-  (require 'gnuplot)\r
-  (save-window-excursion\r
-    (delete-other-windows)\r
-    (when (get-buffer "*gnuplot*") ;; reset *gnuplot* if it already running\r
-      (save-excursion\r
-       (set-buffer "*gnuplot*") (goto-char (point-max))\r
-       (gnuplot-delchar-or-maybe-eof nil)))\r
-    (org-plot/goto-nearest-table)\r
-    ;; set default options\r
-    (mapc\r
-     (lambda (pair)\r
-       (unless (plist-member params (car pair))\r
-        (setf params (plist-put params (car pair) (cdr pair)))))\r
-     org-plot/gnuplot-default-options)\r
-    ;; collect table and table information\r
-    (let* ((data-file (make-temp-file "org-plot"))\r
-          (table (org-table-to-lisp))\r
-          (num-cols (length (if (eq (first table) 'hline) (second table)\r
-                              (first table)))))\r
-      (while (equal 'hline (first table)) (setf table (cdr table)))\r
-      (when (equal (second table) 'hline)\r
-       (setf params (plist-put params :labels (first table))) ;; headers to labels\r
-       (setf table (delq 'hline (cdr table)))) ;; clean non-data from table\r
-      ;; collect options\r
-      (save-excursion (while (and (equal 0 (forward-line -1))\r
-                                 (looking-at "#\\+"))\r
-                       (setf params (org-plot/collect-options params))))\r
-      ;; dump table to datafile (very different for grid)\r
-      (case (plist-get params :plot-type)\r
-       ('2d   (org-plot/gnuplot-to-data table data-file params))\r
-       ('3d   (org-plot/gnuplot-to-data table data-file params))\r
-       ('grid (let ((y-labels (org-plot/gnuplot-to-grid-data\r
-                               table data-file params)))\r
-                (when y-labels (plist-put params :ylabels y-labels)))))\r
-      ;; check for text ind column\r
-      (let ((ind (- (plist-get params :ind) 1)))\r
-       (when (and (>= ind 0) (equal '2d (plist-get params :plot-type)))\r
-         (if (> (length\r
-                 (delq 0 (mapcar\r
-                          (lambda (el)\r
-                            (if (string-match org-table-number-regexp el)\r
-                                0 1))\r
-                          (mapcar (lambda (row) (nth ind row)) table)))) 0)\r
-             (plist-put params :textind t))))\r
-      ;; write script\r
-      (with-temp-buffer\r
-       (if (plist-get params :script) ;; user script\r
-           (progn (insert-file-contents (plist-get params :script))\r
-                  (goto-char (point-min))\r
-                  (while (re-search-forward "$datafile" nil t)\r
-                    (replace-match data-file nil nil)))\r
-         (insert\r
-          (org-plot/gnuplot-script data-file num-cols params)))\r
-       ;; graph table\r
-       (gnuplot-mode)\r
-       (gnuplot-send-buffer-to-gnuplot))\r
-      ;; cleanup\r
-      (bury-buffer (get-buffer "*gnuplot*"))(delete-file data-file))))\r
-\r
-(provide 'org-plot)\r
-\r
-;;; org-plot.el ends here\r
+;;; org-plot.el --- Support for plotting from Org-mode
+
+;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+;;
+;; Author: Eric Schulte <schulte dot eric at gmail dot com>
+;; Keywords: tables, plotting
+;; Homepage: http://orgmode.org
+;; Version: 6.33c
+;;
+;; This file is part of GNU Emacs.
+;;
+;; 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 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Borrows ideas and a couple of lines of code from org-exp.el.
+
+;; Thanks to the org-mode mailing list for testing and implementation
+;; and feature suggestions
+
+;;; Code:
+(require 'org)
+(require 'org-exp)
+(require 'org-table)
+(eval-when-compile
+  (require 'cl))
+
+(declare-function gnuplot-delchar-or-maybe-eof "ext:gnuplot" (arg))
+(declare-function gnuplot-mode "ext:gnuplot" ())
+(declare-function gnuplot-send-buffer-to-gnuplot "ext:gnuplot" ())
+
+(defvar org-plot/gnuplot-default-options
+  '((:plot-type . 2d)
+    (:with . lines)
+    (:ind . 0))
+  "Default options to gnuplot used by `org-plot/gnuplot'")
+
+(defvar org-plot-timestamp-fmt nil)
+
+(defun org-plot/add-options-to-plist (p options)
+  "Parse an OPTIONS line and set values in the property list P.
+Returns the resulting property list."
+  (let (o)
+    (when options
+      (let ((op '(("type"    . :plot-type)
+                 ("script"  . :script)
+                 ("line"    . :line)
+                 ("set"     . :set)
+                 ("title"   . :title)
+                 ("ind"     . :ind)
+                 ("deps"    . :deps)
+                 ("with"    . :with)
+                 ("file"    . :file)
+                 ("labels"  . :labels)
+                 ("map"     . :map)
+                  ("timeind" . :timeind)
+                 ("timefmt" . :timefmt)))
+           (multiples '("set" "line"))
+           (regexp ":\\([\"][^\"]+?[\"]\\|[(][^)]+?[)]\\|[^ \t\n\r;,.]*\\)")
+           (start 0)
+           o)
+       (while (setq o (pop op))
+         (if (member (car o) multiples) ;; keys with multiple values
+             (while (string-match
+                     (concat (regexp-quote (car o)) regexp)
+                     options start)
+               (setq start (match-end 0))
+               (setq p (plist-put p (cdr o)
+                                  (cons (car (read-from-string
+                                              (match-string 1 options)))
+                                        (plist-get p (cdr o)))))
+               p)
+           (if (string-match (concat (regexp-quote (car o)) regexp)
+                             options)
+               (setq p (plist-put p (cdr o)
+                                  (car (read-from-string
+                                        (match-string 1 options)))))))))))
+  p)
+
+(defun org-plot/goto-nearest-table ()
+  "Move the point forward to the beginning of nearest table.
+Return value is the point at the beginning of the table."
+  (interactive) (move-beginning-of-line 1)
+  (while (not (or (org-at-table-p) (< 0 (forward-line 1)))))
+  (goto-char (org-table-begin)))
+
+(defun org-plot/collect-options (&optional params)
+  "Collect options from an org-plot '#+Plot:' line.
+Accepts an optional property list PARAMS, to which the options
+will be added.  Returns the resulting property list."
+  (interactive)
+  (let ((line (thing-at-point 'line)))
+    (if (string-match "#\\+PLOT: +\\(.*\\)$" line)
+       (org-plot/add-options-to-plist params (match-string 1 line))
+      params)))
+
+(defun org-plot-quote-timestamp-field (s)
+  "Convert field S from timestamp to Unix time and export to gnuplot."
+  (format-time-string org-plot-timestamp-fmt (org-time-string-to-time s)))
+
+(defun org-plot-quote-tsv-field (s)
+  "Quote field S for export to gnuplot."
+  (if (string-match org-table-number-regexp s) s
+    (if (string-match org-ts-regexp3 s)
+       (org-plot-quote-timestamp-field s)
+      (concat "\"" (mapconcat 'identity (split-string s "\"") "\"\"") "\""))))
+
+(defun org-plot/gnuplot-to-data (table data-file params)
+  "Export TABLE to DATA-FILE in a format readable by gnuplot.
+Pass PARAMS through to `orgtbl-to-generic' when exporting TABLE."
+  (with-temp-file
+      data-file
+    (make-local-variable 'org-plot-timestamp-fmt)
+    (setq org-plot-timestamp-fmt (or
+                                 (plist-get params :timefmt)
+                                 "%Y-%m-%d-%H:%M:%S"))
+    (insert (orgtbl-to-generic
+            table
+            (org-combine-plists
+             '(:sep "\t" :fmt org-plot-quote-tsv-field)
+             params))))
+  nil)
+
+(defun org-plot/gnuplot-to-grid-data (table data-file params)
+  "Export the data in TABLE to DATA-FILE for gnuplot.
+This means, in a format appropriate for grid plotting by gnuplot.
+PARAMS specifies which columns of TABLE should be plotted as independent
+and dependant variables."
+  (interactive)
+  (let* ((ind (- (plist-get params :ind) 1))
+        (deps (if (plist-member params :deps)
+                  (mapcar (lambda (val) (- val 1)) (plist-get params :deps))
+                (let (collector)
+                  (dotimes (col (length (first table)))
+                    (setf collector (cons col collector)))
+                  collector)))
+        row-vals (counter 0))
+    (when (>= ind 0) ;; collect values of ind col
+      (setf row-vals (mapcar (lambda (row) (setf counter (+ 1 counter))
+                              (cons counter (nth ind row))) table)))
+    (when (or deps (>= ind 0)) ;; remove non-plotting columns
+      (setf deps (delq ind deps))
+      (setf table (mapcar (lambda (row)
+                           (dotimes (col (length row))
+                             (unless (memq col deps)
+                               (setf (nth col row) nil)))
+                           (delq nil row))
+                         table)))
+    ;; write table to gnuplot grid datafile format
+    (with-temp-file data-file
+      (let ((num-rows (length table)) (num-cols (length (first table)))
+           front-edge back-edge)
+       (flet ((gnuplot-row (col row value)
+                           (setf col (+ 1 col)) (setf row (+ 1 row))
+                           (format "%f  %f  %f\n%f  %f  %f\n"
+                                   col (- row 0.5) value ;; lower edge
+                                   col (+ row 0.5) value))) ;; upper edge
+         (dotimes (col num-cols)
+           (dotimes (row num-rows)
+             (setf back-edge
+                   (concat back-edge
+                           (gnuplot-row (- col 1) row (string-to-number
+                                                       (nth col (nth row table))))))
+             (setf front-edge
+                   (concat front-edge
+                           (gnuplot-row col row (string-to-number
+                                                 (nth col (nth row table)))))))
+           ;; only insert once per row
+           (insert back-edge) (insert "\n") ;; back edge
+           (insert front-edge) (insert "\n") ;; front edge
+           (setf back-edge "") (setf front-edge "")))))
+    row-vals))
+
+(defun org-plot/gnuplot-script (data-file num-cols params &optional preface)
+  "Write a gnuplot script to DATA-FILE respecting the options set in PARAMS.
+NUM-COLS controls the number of columns plotted in a 2-d plot.
+Optional argument PREFACE returns only option parameters in a
+manner suitable for prepending to a user-specified script."
+  (let* ((type (plist-get params :plot-type))
+        (with (if (equal type 'grid)
+                  'pm3d
+                (plist-get params :with)))
+        (sets (plist-get params :set))
+        (lines (plist-get params :line))
+        (map (plist-get params :map))
+        (title (plist-get params :title))
+        (file (plist-get params :file))
+        (ind (plist-get params :ind))
+        (time-ind (plist-get params :timeind))
+        (timefmt (plist-get params :timefmt))
+        (text-ind (plist-get params :textind))
+        (deps (if (plist-member params :deps) (plist-get params :deps)))
+        (col-labels (plist-get params :labels))
+        (x-labels (plist-get params :xlabels))
+        (y-labels (plist-get params :ylabels))
+        (plot-str "'%s' using %s%d%s with %s title '%s'")
+        (plot-cmd (case type
+                    ('2d "plot")
+                    ('3d "splot")
+                    ('grid "splot")))
+        (script "reset") plot-lines)
+    (flet ((add-to-script (line) (setf script (format "%s\n%s" script line))))
+      (when file ;; output file
+       (add-to-script (format "set term %s" (file-name-extension file)))
+       (add-to-script (format "set output '%s'" file)))
+      (case type ;; type
+       ('2d ())
+       ('3d (if map (add-to-script "set map")))
+       ('grid (if map
+                  (add-to-script "set pm3d map")
+                (add-to-script "set pm3d"))))
+      (when title (add-to-script (format "set title '%s'" title))) ;; title
+      (when lines (mapc (lambda (el) (add-to-script el)) lines)) ;; line
+      (when sets ;; set
+       (mapc (lambda (el) (add-to-script (format "set %s" el))) sets))
+      (when x-labels ;; x labels (xtics)
+       (add-to-script
+        (format "set xtics (%s)"
+                (mapconcat (lambda (pair)
+                             (format "\"%s\" %d" (cdr pair) (car pair)))
+                           x-labels ", "))))
+      (when y-labels ;; y labels (ytics)
+       (add-to-script
+        (format "set ytics (%s)"
+                (mapconcat (lambda (pair)
+                             (format "\"%s\" %d" (cdr pair) (car pair)))
+                           y-labels ", "))))
+      (when time-ind ;; timestamp index
+       (add-to-script "set xdata time")
+       (add-to-script (concat "set timefmt \""
+                              (or timefmt ;; timefmt passed to gnuplot
+                                  "%Y-%m-%d-%H:%M:%S") "\"")))
+      (unless preface
+        (case type ;; plot command
+       ('2d (dotimes (col num-cols)
+              (unless (and (equal type '2d)
+                           (or (and ind (equal (+ 1 col) ind))
+                               (and deps (not (member (+ 1 col) deps)))))
+                (setf plot-lines
+                      (cons
+                       (format plot-str data-file
+                               (or (and (not text-ind) ind
+                                        (> ind 0) (format "%d:" ind)) "")
+                               (+ 1 col)
+                               (if text-ind (format ":xticlabel(%d)" ind) "")
+                               with
+                               (or (nth col col-labels) (format "%d" (+ 1 col))))
+                       plot-lines)))))
+       ('3d
+        (setq plot-lines (list (format "'%s' matrix with %s title ''"
+                                       data-file with))))
+       ('grid
+        (setq plot-lines (list (format "'%s' with %s title ''"
+                                       data-file with)))))
+        (add-to-script
+         (concat plot-cmd " " (mapconcat 'identity (reverse plot-lines) ",\\\n    "))))
+      script)))
+
+;;-----------------------------------------------------------------------------
+;; facade functions
+;;;###autoload
+(defun org-plot/gnuplot (&optional params)
+  "Plot table using gnuplot. Gnuplot options can be specified with PARAMS.
+If not given options will be taken from the +PLOT
+line directly before or after the table."
+  (interactive)
+  (require 'gnuplot)
+  (save-window-excursion
+    (delete-other-windows)
+    (when (get-buffer "*gnuplot*") ;; reset *gnuplot* if it already running
+      (with-current-buffer "*gnuplot*"
+       (goto-char (point-max))
+       (gnuplot-delchar-or-maybe-eof nil)))
+    (org-plot/goto-nearest-table)
+    ;; set default options
+    (mapc
+     (lambda (pair)
+       (unless (plist-member params (car pair))
+        (setf params (plist-put params (car pair) (cdr pair)))))
+     org-plot/gnuplot-default-options)
+    ;; collect table and table information
+    (let* ((data-file (make-temp-file "org-plot"))
+          (table (org-table-to-lisp))
+          (num-cols (length (if (eq (first table) 'hline) (second table)
+                              (first table)))))
+      (while (equal 'hline (first table)) (setf table (cdr table)))
+      (when (equal (second table) 'hline)
+       (setf params (plist-put params :labels (first table))) ;; headers to labels
+       (setf table (delq 'hline (cdr table)))) ;; clean non-data from table
+      ;; collect options
+      (save-excursion (while (and (equal 0 (forward-line -1))
+                                 (looking-at "#\\+"))
+                       (setf params (org-plot/collect-options params))))
+      ;; dump table to datafile (very different for grid)
+      (case (plist-get params :plot-type)
+       ('2d   (org-plot/gnuplot-to-data table data-file params))
+       ('3d   (org-plot/gnuplot-to-data table data-file params))
+       ('grid (let ((y-labels (org-plot/gnuplot-to-grid-data
+                               table data-file params)))
+                (when y-labels (plist-put params :ylabels y-labels)))))
+      ;; check for timestamp ind column
+      (let ((ind (- (plist-get params :ind) 1)))
+       (when (and (>= ind 0) (equal '2d (plist-get params :plot-type)))
+         (if (= (length
+                 (delq 0 (mapcar
+                          (lambda (el)
+                            (if (string-match org-ts-regexp3 el)
+                                0 1))
+                          (mapcar (lambda (row) (nth ind row)) table)))) 0)
+             (plist-put params :timeind t)
+           ;; check for text ind column
+
+           (if (or (string= (plist-get params :with) "hist")
+                   (> (length
+                       (delq 0 (mapcar
+                                (lambda (el)
+                                  (if (string-match org-table-number-regexp el)
+                                      0 1))
+                                (mapcar (lambda (row) (nth ind row)) table)))) 0))
+               (plist-put params :textind t)))))
+      ;; write script
+      (with-temp-buffer
+       (if (plist-get params :script) ;; user script
+           (progn (insert
+                    (org-plot/gnuplot-script data-file num-cols params t))
+                   (insert "\n")
+                   (insert-file-contents (plist-get params :script))
+                   (goto-char (point-min))
+                   (while (re-search-forward "$datafile" nil t)
+                     (replace-match data-file nil nil)))
+         (insert
+          (org-plot/gnuplot-script data-file num-cols params)))
+       ;; graph table
+       (gnuplot-mode)
+       (gnuplot-send-buffer-to-gnuplot))
+      ;; cleanup
+      (bury-buffer (get-buffer "*gnuplot*"))
+      (run-with-idle-timer 0.1 nil (lambda () (delete-file data-file))))))
+
+(provide 'org-plot)
+
+;; arch-tag: 5763f7c6-0c75-416d-b070-398ee4ec0eca
+;;; org-plot.el ends here