org-babel: further cleaning of parameter-passing to language files
[org-mode.git] / contrib / babel / lisp / langs / org-babel-gnuplot.el
blob353f28f7b776cf1dc8140c8c1804ddc5ae6f61f1
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 ;; evaluate the code body with gnuplot
124 (if (string= session "none")
125 (let ((script-file (make-temp-file "org-babel-gnuplot-script")))
126 (with-temp-file script-file
127 (insert (concat body "\n")))
128 (message "gnuplot \"%s\"" script-file)
129 (message (shell-command-to-string (format "gnuplot \"%s\"" script-file))))
130 (with-temp-buffer
131 (insert (concat body "\n"))
132 (gnuplot-mode)
133 (gnuplot-send-buffer-to-gnuplot)))
134 out-file))))
136 (defun org-babel-prep-session:gnuplot (session params)
137 "Prepare SESSION according to the header arguments specified in PARAMS."
138 (let* ((session (org-babel-gnuplot-initiate-session session))
139 (vars (org-babel-ref-variables params))
140 (var-lines (mapconc
141 (lambda (pair) (format "%s = \"%s\"" (car pair) (cdr pair)))
142 vars)))
143 (org-babel-comint-in-buffer session
144 (mapc (lambda (var-line)
145 (insert var-line) (comint-send-input nil t)
146 (org-babel-comint-wait-for-output session)
147 (sit-for .1) (goto-char (point-max))) var-lines))))
149 (defun org-babel-gnuplot-initiate-session (&optional session)
150 "If there is not a current inferior-process-buffer in SESSION
151 then create. Return the initialized session. The current
152 `gnuplot-mode' doesn't provide support for multiple sessions."
153 (unless (string= session "none")
154 (save-window-excursion (gnuplot-send-string-to-gnuplot "" "line")
155 (current-buffer))))
157 (defun org-babel-gnuplot-quote-timestamp-field (s)
158 "Convert field S from timestamp to Unix time and export to gnuplot."
159 (format-time-string org-babel-gnuplot-timestamp-fmt (org-time-string-to-time s)))
161 (defun org-babel-gnuplot-quote-tsv-field (s)
162 "Quote field S for export to gnuplot."
163 (unless (stringp s)
164 (setq s (format "%s" s)))
165 (if (string-match org-table-number-regexp s) s
166 (if (string-match org-ts-regexp3 s)
167 (org-babel-gnuplot-quote-timestamp-field s)
168 (concat "\"" (mapconcat 'identity (split-string s "\"") "\"\"") "\""))))
170 (defun org-babel-gnuplot-table-to-data (table data-file params)
171 "Export TABLE to DATA-FILE in a format readable by gnuplot.
172 Pass PARAMS through to `orgtbl-to-generic' when exporting TABLE."
173 (with-temp-file data-file
174 (make-local-variable 'org-babel-gnuplot-timestamp-fmt)
175 (setq org-babel-gnuplot-timestamp-fmt (or
176 (plist-get params :timefmt)
177 "%Y-%m-%d-%H:%M:%S"))
178 (insert (orgtbl-to-generic
179 table
180 (org-combine-plists
181 '(:sep "\t" :fmt org-babel-gnuplot-quote-tsv-field)
182 params))))
183 data-file)
185 (provide 'org-babel-gnuplot)
186 ;;; org-babel-gnuplot.el ends here