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
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)
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.
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
39 ;; - gnuplot :: http://www.gnuplot.info/
41 ;; - gnuplot-mode :: http://cars9.uchicago.edu/~ravel/software/gnuplot-mode.html
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."
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
)
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
)
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
97 (mapc (lambda (el) (add-to-body (format "set %s" el
))) sets
))
100 (format "set xtics (%s)"
101 (mapconcat (lambda (pair)
102 (format "\"%s\" %d" (cdr pair
) (car pair
)))
106 (format "set ytics (%s)"
107 (mapconcat (lambda (pair)
108 (format "\"%s\" %d" (cdr pair
) (car pair
)))
111 (add-to-body "set xdata time")
112 (add-to-body (concat "set 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
)))
123 ;; replace any variable names preceded by '$' with the actual
124 ;; value of the variable
126 (setq body
(replace-regexp-in-string
127 (format "\\$%s" (car pair
)) (cdr pair
) body
)))
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
))))
137 (insert (concat body
"\n"))
139 (gnuplot-send-buffer-to-gnuplot)))
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
))
147 (lambda (pair) (format "%s = \"%s\"" (car pair
) (cdr pair
)))
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
))
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
)))
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")
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."
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
198 '(:sep
"\t" :fmt org-babel-gnuplot-quote-tsv-field
)
202 (provide 'org-babel-gnuplot
)
203 ;;; org-babel-gnuplot.el ends here