Commit | Line | Data |
---|---|---|
86fbb8ca CD |
1 | ;;; ob-gnuplot.el --- org-babel functions for gnuplot evaluation |
2 | ||
cbd20947 | 3 | ;; Copyright (C) 2009-2011 Free Software Foundation, Inc. |
86fbb8ca CD |
4 | |
5 | ;; Author: Eric Schulte | |
6 | ;; Keywords: literate programming, reproducible research | |
7 | ;; Homepage: http://orgmode.org | |
3ab2c837 | 8 | ;; Version: 7.7 |
86fbb8ca CD |
9 | |
10 | ;; This file is part of GNU Emacs. | |
11 | ||
12 | ;; GNU Emacs 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 of the License, or | |
15 | ;; (at your option) any later version. | |
16 | ||
17 | ;; GNU Emacs 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. | |
21 | ||
22 | ;; You should have received a copy of the GNU General Public License | |
23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
24 | ||
25 | ;;; Commentary: | |
26 | ||
27 | ;; Org-Babel support for evaluating gnuplot source code. | |
28 | ;; | |
29 | ;; This differs from most standard languages in that | |
30 | ;; | |
31 | ;; 1) we are generally only going to return results of type "file" | |
32 | ;; | |
33 | ;; 2) we are adding the "file" and "cmdline" header arguments | |
34 | ||
35 | ;;; Requirements: | |
36 | ||
37 | ;; - gnuplot :: http://www.gnuplot.info/ | |
38 | ;; | |
39 | ;; - gnuplot-mode :: http://cars9.uchicago.edu/~ravel/software/gnuplot-mode.html | |
40 | ||
41 | ;;; Code: | |
42 | (require 'ob) | |
43 | (require 'ob-ref) | |
44 | (require 'ob-comint) | |
45 | (eval-when-compile (require 'cl)) | |
46 | ||
47 | (declare-function org-time-string-to-time "org" (s)) | |
48 | (declare-function org-combine-plists "org" (&rest plists)) | |
49 | (declare-function orgtbl-to-generic "org-table" (table params)) | |
50 | (declare-function gnuplot-mode "ext:gnuplot-mode" ()) | |
51 | (declare-function gnuplot-send-string-to-gnuplot "ext:gnuplot-mode" (str txt)) | |
52 | (declare-function gnuplot-send-buffer-to-gnuplot "ext:gnuplot-mode" ()) | |
53 | ||
54 | (defvar org-babel-default-header-args:gnuplot | |
55 | '((:results . "file") (:exports . "results") (:session . nil)) | |
56 | "Default arguments to use when evaluating a gnuplot source block.") | |
57 | ||
58 | (defvar org-babel-gnuplot-timestamp-fmt nil) | |
59 | ||
60 | (defun org-babel-gnuplot-process-vars (params) | |
61 | "Extract variables from PARAMS and process the variables. | |
62 | Dumps all vectors into files and returns an association list | |
63 | of variable names and the related value to be used in the gnuplot | |
64 | code." | |
65 | (mapcar | |
66 | (lambda (pair) | |
67 | (cons | |
68 | (car pair) ;; variable name | |
69 | (if (listp (cdr pair)) ;; variable value | |
70 | (org-babel-gnuplot-table-to-data | |
afe98dfa | 71 | (cdr pair) (org-babel-temp-file "gnuplot-") params) |
86fbb8ca | 72 | (cdr pair)))) |
afe98dfa | 73 | (mapcar #'cdr (org-babel-get-header params :var)))) |
86fbb8ca | 74 | |
afe98dfa | 75 | (defun org-babel-expand-body:gnuplot (body params) |
86fbb8ca CD |
76 | "Expand BODY according to PARAMS, return the expanded body." |
77 | (save-window-excursion | |
78 | (let* ((vars (org-babel-gnuplot-process-vars params)) | |
79 | (out-file (cdr (assoc :file params))) | |
80 | (term (or (cdr (assoc :term params)) | |
81 | (when out-file (file-name-extension out-file)))) | |
82 | (cmdline (cdr (assoc :cmdline params))) | |
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 | output) | |
92 | (flet ((add-to-body (text) | |
93 | (setq body (concat text "\n" body)))) | |
94 | ;; append header argument settings to body | |
95 | (when title (add-to-body (format "set title '%s'" title))) ;; title | |
96 | (when lines (mapc (lambda (el) (add-to-body el)) lines)) ;; line | |
97 | (when sets | |
98 | (mapc (lambda (el) (add-to-body (format "set %s" el))) sets)) | |
99 | (when x-labels | |
100 | (add-to-body | |
101 | (format "set xtics (%s)" | |
102 | (mapconcat (lambda (pair) | |
103 | (format "\"%s\" %d" (cdr pair) (car pair))) | |
104 | x-labels ", ")))) | |
105 | (when y-labels | |
106 | (add-to-body | |
107 | (format "set ytics (%s)" | |
108 | (mapconcat (lambda (pair) | |
109 | (format "\"%s\" %d" (cdr pair) (car pair))) | |
110 | y-labels ", ")))) | |
111 | (when time-ind | |
112 | (add-to-body "set xdata time") | |
113 | (add-to-body (concat "set timefmt \"" | |
114 | (or timefmt | |
115 | "%Y-%m-%d-%H:%M:%S") "\""))) | |
116 | (when out-file (add-to-body (format "set output \"%s\"" out-file))) | |
117 | (when term (add-to-body (format "set term %s" term))) | |
118 | ;; insert variables into code body: this should happen last | |
119 | ;; placing the variables at the *top* of the code in case their | |
120 | ;; values are used later | |
afe98dfa CD |
121 | (add-to-body (mapconcat #'identity |
122 | (org-babel-variable-assignments:gnuplot params) | |
123 | "\n")) | |
86fbb8ca CD |
124 | ;; replace any variable names preceded by '$' with the actual |
125 | ;; value of the variable | |
126 | (mapc (lambda (pair) | |
127 | (setq body (replace-regexp-in-string | |
128 | (format "\\$%s" (car pair)) (cdr pair) body))) | |
129 | vars)) | |
130 | body))) | |
131 | ||
132 | (defun org-babel-execute:gnuplot (body params) | |
133 | "Execute a block of Gnuplot code. | |
134 | This function is called by `org-babel-execute-src-block'." | |
135 | (require 'gnuplot) | |
136 | (let ((session (cdr (assoc :session params))) | |
137 | (result-type (cdr (assoc :results params))) | |
138 | (out-file (cdr (assoc :file params))) | |
139 | (body (org-babel-expand-body:gnuplot body params)) | |
140 | output) | |
141 | (save-window-excursion | |
142 | ;; evaluate the code body with gnuplot | |
143 | (if (string= session "none") | |
afe98dfa | 144 | (let ((script-file (org-babel-temp-file "gnuplot-script-"))) |
86fbb8ca CD |
145 | (with-temp-file script-file |
146 | (insert (concat body "\n"))) | |
147 | (message "gnuplot \"%s\"" script-file) | |
148 | (setq output | |
afe98dfa CD |
149 | (shell-command-to-string |
150 | (format | |
151 | "gnuplot \"%s\"" | |
152 | (org-babel-process-file-name script-file)))) | |
86fbb8ca CD |
153 | (message output)) |
154 | (with-temp-buffer | |
155 | (insert (concat body "\n")) | |
156 | (gnuplot-mode) | |
157 | (gnuplot-send-buffer-to-gnuplot))) | |
158 | (if (member "output" (split-string result-type)) | |
159 | output | |
3ab2c837 | 160 | nil)))) ;; signal that output has already been written to file |
86fbb8ca CD |
161 | |
162 | (defun org-babel-prep-session:gnuplot (session params) | |
163 | "Prepare SESSION according to the header arguments in PARAMS." | |
164 | (let* ((session (org-babel-gnuplot-initiate-session session)) | |
afe98dfa | 165 | (var-lines (org-babel-variable-assignments:gnuplot params))) |
86fbb8ca CD |
166 | (message "%S" session) |
167 | (org-babel-comint-in-buffer session | |
168 | (mapc (lambda (var-line) | |
169 | (insert var-line) (comint-send-input nil t) | |
170 | (org-babel-comint-wait-for-output session) | |
171 | (sit-for .1) (goto-char (point-max))) var-lines)) | |
172 | session)) | |
173 | ||
174 | (defun org-babel-load-session:gnuplot (session body params) | |
175 | "Load BODY into SESSION." | |
176 | (save-window-excursion | |
177 | (let ((buffer (org-babel-prep-session:gnuplot session params))) | |
178 | (with-current-buffer buffer | |
179 | (goto-char (process-mark (get-buffer-process (current-buffer)))) | |
180 | (insert (org-babel-chomp body))) | |
181 | buffer))) | |
182 | ||
afe98dfa CD |
183 | (defun org-babel-variable-assignments:gnuplot (params) |
184 | "Return list of gnuplot statements assigning the block's variables" | |
185 | (mapcar | |
186 | (lambda (pair) (format "%s = \"%s\"" (car pair) (cdr pair))) | |
187 | (org-babel-gnuplot-process-vars params))) | |
188 | ||
86fbb8ca CD |
189 | (defvar gnuplot-buffer) |
190 | (defun org-babel-gnuplot-initiate-session (&optional session params) | |
191 | "Initiate a gnuplot session. | |
192 | If there is not a current inferior-process-buffer in SESSION | |
193 | then create one. Return the initialized session. The current | |
194 | `gnuplot-mode' doesn't provide support for multiple sessions." | |
195 | (require 'gnuplot) | |
196 | (unless (string= session "none") | |
197 | (save-window-excursion | |
198 | (gnuplot-send-string-to-gnuplot "" "line") | |
199 | gnuplot-buffer))) | |
200 | ||
201 | (defun org-babel-gnuplot-quote-timestamp-field (s) | |
202 | "Convert S from timestamp to Unix time and export to gnuplot." | |
203 | (format-time-string org-babel-gnuplot-timestamp-fmt (org-time-string-to-time s))) | |
204 | ||
205 | (defvar org-table-number-regexp) | |
206 | (defvar org-ts-regexp3) | |
207 | (defun org-babel-gnuplot-quote-tsv-field (s) | |
208 | "Quote S for export to gnuplot." | |
209 | (unless (stringp s) | |
210 | (setq s (format "%s" s))) | |
211 | (if (string-match org-table-number-regexp s) s | |
212 | (if (string-match org-ts-regexp3 s) | |
213 | (org-babel-gnuplot-quote-timestamp-field s) | |
214 | (concat "\"" (mapconcat 'identity (split-string s "\"") "\"\"") "\"")))) | |
215 | ||
216 | (defun org-babel-gnuplot-table-to-data (table data-file params) | |
217 | "Export TABLE to DATA-FILE in a format readable by gnuplot. | |
218 | Pass PARAMS through to `orgtbl-to-generic' when exporting TABLE." | |
219 | (with-temp-file data-file | |
220 | (make-local-variable 'org-babel-gnuplot-timestamp-fmt) | |
221 | (setq org-babel-gnuplot-timestamp-fmt (or | |
222 | (plist-get params :timefmt) | |
223 | "%Y-%m-%d-%H:%M:%S")) | |
224 | (insert (orgtbl-to-generic | |
225 | table | |
226 | (org-combine-plists | |
227 | '(:sep "\t" :fmt org-babel-gnuplot-quote-tsv-field) | |
228 | params)))) | |
229 | data-file) | |
230 | ||
231 | (provide 'ob-gnuplot) | |
232 | ||
5b409b39 | 233 | |
86fbb8ca CD |
234 | |
235 | ;;; ob-gnuplot.el ends here |