babel: smarter `org-babel-ref-split-args' -- fixes bug parsing indexed function-style...
[rgr-org-mode.git] / contrib / babel / lisp / langs / org-babel-gnuplot.el
blob2053f3e8d0a1fbdeb15400bfe04d109c03e5fae1
1 ;;; org-babel-gnuplot.el --- org-babel functions for gnuplot evaluation
3 ;; Copyright (C) 2009 Eric Schulte
5 ;; Author: Eric Schulte
6 ;; Keywords: literate programming, reproducible research
7 ;; Homepage: http://orgmode.org
8 ;; Version: 0.01
10 ;;; License:
12 ;; This program is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 3, or (at your option)
15 ;; any later version.
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
27 ;;; Commentary:
29 ;; Org-Babel support for evaluating gnuplot source code.
31 ;; This differs from most standard languages in that
33 ;; 1) we are generally only going to return results of type "file"
35 ;; 2) we are adding the "file" and "cmdline" header arguments
37 ;;; Requirements:
39 ;; - gnuplot :: http://www.gnuplot.info/
40 ;;
41 ;; - gnuplot-mode :: http://cars9.uchicago.edu/~ravel/software/gnuplot-mode.html
43 ;;; Code:
44 (require 'org-babel)
45 (require 'gnuplot)
47 (org-babel-add-interpreter "gnuplot")
49 (add-to-list 'org-babel-tangle-langs '("gnuplot" "gnuplot"))
51 (defvar org-babel-default-header-args:gnuplot
52 '((:results . "file") (:exports . "results") (:session . nil))
53 "Default arguments to use when evaluating a gnuplot source block.")
55 (defvar org-babel-gnuplot-timestamp-fmt nil)
57 (defun org-babel-gnuplot-process-vars (params)
58 "Extract variables from PARAMS and process the variables
59 dumping all vectors into files returning an association list of
60 variable names and the value to be used in the gnuplot code."
61 (mapcar
62 (lambda (pair)
63 (cons
64 (car pair) ;; variable name
65 (if (listp (cdr pair)) ;; variable value
66 (org-babel-gnuplot-table-to-data
67 (cdr pair) (make-temp-file "org-babel-gnuplot") params)
68 (cdr pair))))
69 (org-babel-ref-variables params)))
71 (defun org-babel-execute:gnuplot (body params)
72 "Execute a block of Gnuplot code with org-babel. This function is
73 called by `org-babel-execute-src-block'."
74 (message "executing Gnuplot source code block")
75 (save-window-excursion
76 (let* ((vars (org-babel-gnuplot-process-vars params))
77 (session (cdr (assoc :session params)))
78 (out-file (cdr (assoc :file params)))
79 (term (or (cdr (assoc :term params))
80 (when out-file (file-name-extension out-file))))
81 (cmdline (cdr (assoc :cmdline params)))
82 (in-file (make-temp-file "org-babel-ditaa"))
83 (title (plist-get params :title))
84 (lines (plist-get params :line))
85 (sets (plist-get params :set))
86 (x-labels (plist-get params :xlabels))
87 (y-labels (plist-get params :ylabels))
88 (timefmt (plist-get params :timefmt))
89 (time-ind (or (plist-get params :timeind)
90 (when timefmt 1))))
91 (flet ((add-to-body (text)
92 (setq body (concat text "\n" body))))
93 ;; append header argument settings to body
94 (when title (add-to-body (format "set title '%s'" title))) ;; title
95 (when lines (mapc (lambda (el) (add-to-body el)) lines)) ;; line
96 (when sets
97 (mapc (lambda (el) (add-to-body (format "set %s" el))) sets))
98 (when x-labels
99 (add-to-body
100 (format "set xtics (%s)"
101 (mapconcat (lambda (pair)
102 (format "\"%s\" %d" (cdr pair) (car pair)))
103 x-labels ", "))))
104 (when y-labels
105 (add-to-body
106 (format "set ytics (%s)"
107 (mapconcat (lambda (pair)
108 (format "\"%s\" %d" (cdr pair) (car pair)))
109 y-labels ", "))))
110 (when time-ind
111 (add-to-body "set xdata time")
112 (add-to-body (concat "set timefmt \""
113 (or timefmt
114 "%Y-%m-%d-%H:%M:%S") "\"")))
115 (when out-file (add-to-body (format "set output \"%s\"" out-file)))
116 (when term (add-to-body (format "set term %s" term)))
117 ;; insert variables into code body: this should happen last
118 ;; placing the variables at the *top* of the code in case their
119 ;; values are used later
120 (add-to-body (mapconcat
121 (lambda (pair) (format "%s = \"%s\"" (car pair) (cdr pair)))
122 vars "\n"))
123 ;; replace any variable names preceded by '$' with the actual
124 ;; value of the variable
125 (mapc (lambda (pair)
126 (setq body (replace-regexp-in-string
127 (format "\\$%s" (car pair)) (cdr pair) body)))
128 vars)
129 ;; evaluate the code body with gnuplot
130 (if (string= session "none")
131 (let ((script-file (make-temp-file "org-babel-gnuplot-script")))
132 (with-temp-file script-file
133 (insert (concat body "\n")))
134 (message "gnuplot \"%s\"" script-file)
135 (message (shell-command-to-string (format "gnuplot \"%s\"" script-file))))
136 (with-temp-buffer
137 (insert (concat body "\n"))
138 (gnuplot-mode)
139 (gnuplot-send-buffer-to-gnuplot)))
140 out-file))))
142 (defun org-babel-prep-session:gnuplot (session params)
143 "Prepare SESSION according to the header arguments specified in PARAMS."
144 (let* ((session (org-babel-gnuplot-initiate-session session))
145 (vars (org-babel-ref-variables params))
146 (var-lines (mapcar
147 (lambda (pair) (format "%s = \"%s\"" (car pair) (cdr pair)))
148 vars)))
149 (message "%S" session)
150 (org-babel-comint-in-buffer session
151 (mapc (lambda (var-line)
152 (insert var-line) (comint-send-input nil t)
153 (org-babel-comint-wait-for-output session)
154 (sit-for .1) (goto-char (point-max))) var-lines))
155 session))
157 (defun org-babel-load-session:gnuplot (session body params)
158 "Load BODY into SESSION."
159 (save-window-excursion
160 (let ((buffer (org-babel-prep-session:gnuplot session params)))
161 (with-current-buffer buffer
162 (goto-char (process-mark (get-buffer-process (current-buffer))))
163 (insert (org-babel-chomp body)))
164 buffer)))
166 (defun org-babel-gnuplot-initiate-session (&optional session)
167 "If there is not a current inferior-process-buffer in SESSION
168 then create. Return the initialized session. The current
169 `gnuplot-mode' doesn't provide support for multiple sessions."
170 (unless (string= session "none")
171 (save-window-excursion (gnuplot-send-string-to-gnuplot "" "line")
172 gnuplot-buffer)))
174 (defun org-babel-gnuplot-quote-timestamp-field (s)
175 "Convert field S from timestamp to Unix time and export to gnuplot."
176 (format-time-string org-babel-gnuplot-timestamp-fmt (org-time-string-to-time s)))
178 (defun org-babel-gnuplot-quote-tsv-field (s)
179 "Quote field S for export to gnuplot."
180 (unless (stringp s)
181 (setq s (format "%s" s)))
182 (if (string-match org-table-number-regexp s) s
183 (if (string-match org-ts-regexp3 s)
184 (org-babel-gnuplot-quote-timestamp-field s)
185 (concat "\"" (mapconcat 'identity (split-string s "\"") "\"\"") "\""))))
187 (defun org-babel-gnuplot-table-to-data (table data-file params)
188 "Export TABLE to DATA-FILE in a format readable by gnuplot.
189 Pass PARAMS through to `orgtbl-to-generic' when exporting TABLE."
190 (with-temp-file data-file
191 (make-local-variable 'org-babel-gnuplot-timestamp-fmt)
192 (setq org-babel-gnuplot-timestamp-fmt (or
193 (plist-get params :timefmt)
194 "%Y-%m-%d-%H:%M:%S"))
195 (insert (orgtbl-to-generic
196 table
197 (org-combine-plists
198 '(:sep "\t" :fmt org-babel-gnuplot-quote-tsv-field)
199 params))))
200 data-file)
202 (provide 'org-babel-gnuplot)
203 ;;; org-babel-gnuplot.el ends here