From 062bc09d84e2cd3ddbdb4eea230262d7c3d77c92 Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Sun, 19 Jul 2009 01:07:07 -0400 Subject: [PATCH] Adding support for column names (header line) when using R. Unlike the other languages, it's central to R to be able to index columns of a data frame d, either by d[,"columnname"] of d$columnname. With this change, if colnames are present in the *input* from org-babel, the corresponding R variable is *always* constructed with the colnames. In addition, with the :colnames header arg, the *output* to elisp/org buffer contains the colnames separated from the rest of the table by 'hline. This behaviour is not default because other languages may expect a simple table without the 'hline. --- lisp/langs/org-babel-R.el | 23 ++++++++++++----------- lisp/org-babel.el | 18 ++++++++++-------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/lisp/langs/org-babel-R.el b/lisp/langs/org-babel-R.el index 82413380f..5ec3efce4 100644 --- a/lisp/langs/org-babel-R.el +++ b/lisp/langs/org-babel-R.el @@ -45,8 +45,9 @@ called by `org-babel-execute-src-block' via multiple-value-bind." (lambda (pair) (org-babel-R-assign-elisp (car pair) (cdr pair))) vars "\n") "\n" body "\n")) - (session (org-babel-R-initiate-session session))) - (org-babel-R-evaluate session full-body result-type)))) + (session (org-babel-R-initiate-session session)) + (colnames (cdr (assoc :colnames params)))) + (org-babel-R-evaluate session full-body result-type colnames)))) (defun org-babel-prep-session:R (session params) "Prepare SESSION according to the header arguments specified in PARAMS." @@ -71,8 +72,8 @@ called by `org-babel-execute-src-block' via multiple-value-bind." (with-temp-file transition-file (insert (orgtbl-to-tsv value '(:fmt org-babel-R-quote-tsv-field))) (insert "\n")) - (format "%s <- read.table(\"%s\", header=FALSE, sep=\"\\t\", as.is=TRUE)" - name transition-file)) + (format "%s <- read.table(\"%s\", header=%s, sep=\"\\t\", as.is=TRUE)" + name transition-file (if (eq (second value) 'hline) "TRUE" "FALSE"))) (format "%s <- %s" name (org-babel-R-quote-tsv-field value)))) (defun org-babel-R-initiate-session (session) @@ -89,9 +90,9 @@ called by `org-babel-execute-src-block' via multiple-value-bind." (defvar org-babel-R-eoe-indicator "'org_babel_R_eoe'") (defvar org-babel-R-eoe-output "[1] \"org_babel_R_eoe\"") (defvar org-babel-R-wrapper-method "main <- function ()\n{\n%s\n} -write.table(main(), file=\"%s\", sep=\"\\t\", na=\"nil\",row.names=FALSE, col.names=FALSE, quote=FALSE)") +write.table(main(), file=\"%s\", sep=\"\\t\", na=\"nil\",row.names=FALSE, col.names=%s, quote=FALSE)") -(defun org-babel-R-evaluate (buffer body result-type) +(defun org-babel-R-evaluate (buffer body result-type colnames) "Pass BODY to the R process in BUFFER. If RESULT-TYPE equals 'output then return a list of the outputs of the statements in BODY, if RESULT-TYPE equals 'value then return the value of the @@ -108,15 +109,15 @@ last statement in BODY, as elisp." (with-temp-buffer (insert-file-contents out-tmp-file) (buffer-string))) (value (with-temp-file in-tmp-file - (insert (format org-babel-R-wrapper-method body out-tmp-file))) + (insert (format org-babel-R-wrapper-method + body out-tmp-file (if colnames "TRUE" "FALSE")))) (shell-command (format "R --no-save < '%s'" in-tmp-file)) - (org-babel-import-elisp-from-file out-tmp-file)))) + (org-babel-import-elisp-from-file out-tmp-file colnames)))) ;; comint session evaluation (org-babel-comint-in-buffer buffer (let* ((tmp-file (make-temp-file "org-babel-R")) (last-value-eval - (format "write.table(.Last.value, file=\"%s\", sep=\"\\t\", na=\"nil\",row.names=FALSE, col.names=FALSE, quote=FALSE)" - tmp-file)) + (format "write.table(.Last.value, file=\"%s\", sep=\"\\t\", na=\"nil\",row.names=FALSE, col.names=%s, quote=FALSE)" tmp-file (if colnames "TRUE" "FALSE"))) (full-body (mapconcat #'org-babel-chomp (list body last-value-eval org-babel-R-eoe-indicator) "\n")) (raw (org-babel-comint-with-output buffer org-babel-R-eoe-output nil @@ -138,7 +139,7 @@ last statement in BODY, as elisp." (mapcar #'org-babel-trim raw)))))) (case result-type (output (org-babel-trim (mapconcat #'identity results "\n"))) - (value (org-babel-import-elisp-from-file tmp-file))))))) + (value (org-babel-import-elisp-from-file tmp-file colnames))))))) (provide 'org-babel-R) diff --git a/lisp/org-babel.el b/lisp/org-babel.el index 54f806ac9..6232f4cd6 100644 --- a/lisp/org-babel.el +++ b/lisp/org-babel.el @@ -566,7 +566,7 @@ This is taken almost directly from `org-read-prop'." (if (string-match "^[[:digit:]]*\\.?[[:digit:]]*$" string) (string-to-number string))) -(defun org-babel-import-elisp-from-file (file-name) +(defun org-babel-import-elisp-from-file (file-name &optional colnames) "Read the results located at FILE-NAME into an elisp table. If the table is trivial, then return it as a scalar." (let (result) @@ -578,14 +578,16 @@ the table is trivial, then return it as a scalar." (setq result (mapcar (lambda (row) (mapcar #'org-babel-string-read row)) (org-table-to-lisp)))) - (error nil)) + (error nil))) + (if colnames + (setq result (cons (car result) (cons 'hline (cdr result)))) (if (null (cdr result)) ;; if result is trivial vector, then scalarize it - (if (consp (car result)) - (if (null (cdr (car result))) - (caar result) - result) - (car result)) - result)))) + (if (consp (car result)) + (if (null (cdr (car result))) + (caar result) + result) + (car result)) + result)))) (defun org-babel-string-read (cell) "Strip nested \"s from around strings in exported R values."