22

When I use Sweave with R, I can avoid explicitly naming the plot files by simply enclosing the plot commands within a code-chunk like <<fig=TRUE>> ... @. The Sweave driver automatically generates numbered plot files like fig1.pdf, fig2.pdf, etc.

However in org-mode, it seems like I need to explicitly name the figure file using a :file [...].pdf in the header, e.g.

#+attr_latex: width=8cm placement=[htbp]
#+begin_src R :results output graphics :exports results :file fig.pdf                                                                                                                                                                                                 
    require(ggplot2)                                                                                                                           
    a <- rnorm(100)                                                                                                                            
    b <- 2*a + rnorm(100)                                                                                                                      
    d <- data.frame(a,b)                                                                                                                       
    ggplot(d,aes(a,b)) + geom_point()                                                                                                          
#+end_src                                     

Is there some way to avoid explicitly naming the plot file, and have the org-mode latex export engine generate these file-names?

Update: I'm including the solution that G. Jay Kerns pointed to here for easy reference: all you need to do is include a temp-file-generating emacs-lisp function in the header, like :file (org-babel-temp-file "./figure-" ".pdf"). This creates a temp figure-file in the current directory (because of the ./). If you want the temp figure-file in a global temp directory (defined by the variable org-babel-temporary-directory), then just say ".figure":

#+attr_latex: width=8cm placement=[htbp]
#+begin_src R :results output graphics :exports results :file (org-babel-temp-file "./figure-" ".pdf")                                                                                                                                                                                                 
    require(ggplot2)                                                                                                                           
    a <- rnorm(100)                                                                                                                            
    b <- 2*a + rnorm(100)                                                                                                                      
    d <- data.frame(a,b)                                                                                                                       
    ggplot(d,aes(a,b)) + geom_point()                                                                                                          
#+end_src                                     
Prasad Chalasani
  • 19,912
  • 7
  • 51
  • 73

4 Answers4

7

Great question, and a similar one (plus some extra stuff) came up on the Org-mode mailing list back in September. The original question is here, and a sketch of a possible solution lies in the final message of the thread here (see #1, the other items are about other things).

G. Jay Kerns
  • 238
  • 3
  • 12
4

Here's another approach using an incrementor, as the use of

(org-babel-temp-file "./figure-" ".pdf")

didn't seem to work for me:

(setq i 0)
#+begin_src R :file (concat "f" (number-to-string (incf i)) ".pdf") :results output graphics :exports results
(plot (rnorm(10))
#+end_src

(setq i) only needs to be called once per session to define the variable; it can then be erased. The plots are saved to your default-directory and appear automatically when exporting the .org file to .tex using (org-latex-export-as-latex).

dardisco
  • 5,086
  • 2
  • 39
  • 54
  • 2
    The selected answer worked well enough within the buffer, but I had issues exporting to pdf because of the temp files. I prefer this answer because it works for the pdf export and saves figures in working directory. – Tedward Feb 02 '16 at 21:49
1

I improved the approach of [dardisco] to make the behavior truly automatic. Basically, the code below includes a block that creates a lisp variable that is then fed to all figure blocks.

This elisp block should be placed at the beginning of your file (before any figure block, at least).

#+name: fignumber 
#+begin_src emacs-lisp :results value silent :exports none :session 
(setq fignumber 0)
#+end_src

#+BEGIN_SRC R :results output graphics file :file (concat "figure" (number-to-string (incf fignumber)) ".pdf") :exports results :session
x <- 1:100
y <- 1:100
plot(x,y)
#+END_SRC


Elijah
  • 414
  • 3
  • 8
0

I made a lisp function below. This function has 2 arguments DIRNAME and FNAME"fname". This function generates a path DIRNAME/FNAME##.png, where ## is a sequencial number in the directory. For example, if there are fig1.png fig2.png fig4.png and you give fig as FNAME, this function returns fig3.png(missing number). If there are fig1.png fig2.png fig3.png, this returns fig4.png. If there are no files, this returns fig1.png.

(defun search-file-name (dirname fname) 
  "This function generates a path DIRNAME/FNAME##.png,
   where ## is a sequencial number in the directory.
   For example, if there are fig1.png fig2.png fig4.png and 
   you give fig as FNAME, this function returns fig3.png(missing number).
   If there are fig1.png fig2.png fig3.png, this returns fig4.png.
   If there are no files, this returns fig1.png."

  (setq string (directory-files dirname nil (concat fname "[0-9]+\\.png") t))
  (if (not string) (concat dirname fname "1.png")
    (progn
      (setq number-list
            (mapcar '(lambda (x)
                       (string-match (concat fname "\\([0-9]+\\)\\.png") x)
                       (match-string 1 x))
                    string))
      (setq w1 (sort (mapcar 'parse-integer number-list) '<))

      (setq missing nil)
      (loop for j from 1 to (length w1) do
            (if (not (equal j (elt w1 (- j 1))))
                (progn (setq missing j) (return missing))))
      (if (not missing) (setq missing (+ 1 (car (last w1)))))
      (concat dirname fname (number-to-string missing) ".png"))))

  (setq missing nil)
  (loop for j from 1 to (length w1) do
        (if (not (equal j (elt w1 (- j 1))))
            (progn (setq missing j) (return missing))))
  (if (not missing) (setq missing (+ 1 (car (last w1)))))
  (concat dirname fname (number-to-string missing) ".png"))))