3
votes

Problem

I want to knit multiple PDFs from a single data frame. Therefore I've tried various solutions, but my knowledge in R, R Studio, LaTex, knitr is very limited so I wasn't able to adapt some solution approaches and finally tried it on my own. I actually think my code is absolutely not the way you actually use to achieve what I want to achieve. So, please feel free to tell me where and what I can/should improve.

I would be really grateful for some help. I've been googling for hours now and I would also appreciate if you could recommend me any tutorial/guide/explanation. I don't even know where to start.

Current State: Solved

Code

main.R

for(i in 1:nrow(mtcars)) {
  g_title <- rownames(mtcars)[i]
  knit2pdf(input  = "main.Rnw", 
           output = paste0("output\\", g_title, ".pdf"), 
           quiet  = FALSE, 
           envir  = parent.frame())
}

template.Rnw

\documentclass{article}
\usepackage[ngerman]{babel}

\begin{document}
\begin{titlepage}
  Titlepage
\end{titlepage}

\tableofcontents
\newpage

\section{Topic 1}
\newpage

\section{Topic 2}    

\end{document}

Solution Approaches

Global Variables

I tried to create global variables which are altered by a for loop. These variables are then used in the .Rnw file in form of a function. I wasn't able to get this working due unknown errors.

Code in the .R file:

printPlot <- function() {
  print(g_plot)
}

for(i in 1:nrow(mtcars)) {
  g_title <- rownames(mtcars)[i]
  g_plot  <- ggplot(mtcars[i,], aes(x = cyl, y = disp) ) + 
             geom_point()
  knit2pdf(input  = "main.Rnw", 
           output = paste0("output\\", g_title, ".pdf"), 
           quiet  = FALSE, 
           envir  = parent.frame())
}

Code in the .Rnw file:

<<>>=
printPlot()
@

Errors:

The PDFs are created, but their contents are messed up. You can see it in the image under 'Current State'.

I also receive several error/warning messages, e.g.:

Warning messages: 1: running command '"C:\Users\Marc\AppData\Local\Programs\MIKTEX~1.9\miktex\bin\x64\texify.exe" --quiet --pdf "Mazda RX4.pdf" --max-iterations=20 -I "C:/PROGRA~1/R/R-33~1.2/share/texmf/tex/latex" -I "C:/PROGRA~1/R/R-33~1.2/share/texmf/bibtex/bst"' had status 1 2: running command '"C:\Users\Marc\AppData\Local\Programs\MIKTEX~1.9\miktex\bin\x64\texify.exe" --quiet --pdf "Mazda RX4 Wag.pdf" --max-iterations=20 -I "C:/PROGRA~1/R/R-33~1.2/share/texmf/tex/latex" -I "C:/PROGRA~1/R/R-33~1.2/share/texmf/bibtex/bst"' had status 1

MakeFile

I just read the first time about makefile. Maybe this could help solving the problem.

If I got it right makefile is used with Markdown and not directly with LaTex. This seems to be a massive loss in performance. This point is quite important to me, so I will try to find another solution.

Other SO Questions

In most of the cases I tried to adapt the code, but simply failed, because I am missing knowledge to understand the given solution approaches.

1

1 Answers

2
votes

From the question, I'm not entirely sure about the expected output, but there concept is clear. And although the task itself is quite simple, surprisingly many things can go wrong.

Code:

code.R

library(knitr)
library(ggplot2)

dir.create(path = "output/")
opts_knit$set(base.dir = "output/")

for(i in 1:nrow(mtcars)) {
  filename <- rownames(mtcars)[i]
  knit(input  = "template.Rnw", output = paste0("output/", filename, ".tex"))
  tools::texi2pdf(paste0("output/", filename, ".tex"), clean = TRUE)
  file.copy(from = paste0(filename, ".pdf"), to = paste0("output/", filename, ".pdf"))
  # file.remove(paste0(filename, ".pdf")) # this will DELETE filename.pdf from the current working directory (should be safe because we just created this file)
}

template.Rnw

\documentclass{article}
\begin{document}
<<>>=
ggplot(mtcars[i,], aes(x = cyl, y = disp) ) + geom_point()
@
\end{document}
  • We need to set base.dir because the current working directory is one level above the directory where the document is created. This would lead to wrong figure paths: knitr produces the plots in figure/ but they should be in output/figure/. Consequently, compilation will fail.
  • For some reason knit2pdf cannot compile the generated intermediate TEX file. Therefore I use knit to produce a TEX file and then tools::texi2pdf to compile this file to PDF.

Note how variables from code.R are visible to the code in the template document. That's why i can be used in template.Rnw.