30

I'd like to embed some R into a LaTeX document. After a bit of googling I found that Sweave and knitr allow you to do this. I compiled a simple example with Sweave and it works.

I'd be much obliged if somebody could answer the following questions:

  • Are there other approaches?
  • What are the merits of the different approaches?

Please note that I'd like to run LaTeX from the command line. I am not interested in IDE solutions.

TIA for your help.

13
  • 1
    There exist packages to insert program code in a LaTeX program, such as ctan.org/pkg/listings.
    – Karlo
    Dec 30, 2015 at 10:54
  • 5
    @MWijnand: I think, the O.P. wants to execute R calculations from LaTeX, not just displaying R codes
    – user31729
    Dec 30, 2015 at 11:02
  • 1
    @ChristianHupfer is right.
    – user10274
    Dec 30, 2015 at 12:23
  • 2
    knitr is a lot more preferable to Sweave, IMHO. knitr integrates nicely with tikzDevice, so you can use tikz for graphs (thus: ensuring a consistent font between your document and graphs, better math typesetting in the labels of the graphs, etc.; see, e.g., here). Also, you might want to look at ezknitr.
    – Adam Liter
    Dec 30, 2015 at 14:59
  • 1
    As a comparison looking at PythonTeX might be useful. In principle this can be used for other languages as well. Another approach is the project Jupyter, which is not really LaTeX based but can handle LaTeX markup.
    – Alexander
    Jan 6, 2016 at 11:54

4 Answers 4

24
+150

0. tl;dr

knitr is preferable to Sweave, and ezknitr is a wrapper around knitr that is probably worth using—especially if you are only building documents from the command line (but this limits you to R Markdown; see below); I don't think there are IDEs that have integrated ezknitr use (at least not at the time of writing)—because it makes it easier to ensure the directories and paths are all correct.

knitr/ezknitr (henceforth just knitr) may or may not be preferable to Thruston's suggested approach approach, depending on your use-case.

What follows is some justification for these points, coupled with examples.

1. knitr vs. Sweave

knitr is preferrable to Sweave for a variety of reasons. Two main reasons to prefer knitr to Sweave are (i) you get better integration with tikzDevice in knitr, and (ii) chunk options are more versatile.

1.1. knitr and tikzDevice

I should mention the caveat that I've never really used Sweave, but my understanding from reading blog posts on the internet is that it is much more straightforward to use tikzDevice with knitr than it is with Sweave.

Two reasons you might want to use tikzDevice with your graphs are because (i) you get better typesetting in labels and titles (especially of math), and (ii) you get a consistent font between the text in your document and the text in your graphs inside of your document. Here's an MWE showing both of these things.1

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing}

\tikzstyle{underbrace style}=[decorate,decoration={brace,raise=5mm,amplitude=3pt,mirror},color=gray]
\tikzstyle{underbrace text style}=[font=\scriptsize, below, pos=.5, yshift=-8mm]

\newcommand*{\MyContrivedTitle}{%
  \begin{tikzpicture}
    \node (MyTitle) {Average miles per gallon by gear (and some math for fun: $\int_{a}^{b} x^2 dx$)};
    \draw [underbrace style] (MyTitle.north west) -- (MyTitle.north east) node [underbrace text style] {My contrived title with \texttt{tikz}};
  \end{tikzpicture}}

\begin{document}

\section{Introduction}

<<setup, include=FALSE, cache=FALSE>>=
### Set the global chunk options
### See http://yihui.name/knitr/options/#chunk_options
library(knitr)
opts_chunk$set(cache=FALSE,
               echo=FALSE,
               message=FALSE,
               warning=FALSE,
               highlight=FALSE,
               sanitize=FALSE,
               tidy=TRUE,
               dev='tikz',
               fig.env='figure',
               fig.show='hold',
               fig.lp='fig:',
               fig.align='center',
               fig.pos='htbp',
               out.width='.75\\textwidth'
               )
@

As can be seen in Figure \ref{fig:car-plot}, \ldots

<<car-plot,fig.cap='A graphic produced by \\texttt{knitr} and \\texttt{tikzDevice}'>>=
library(dplyr) # a good package for data manipulation
library(ggplot2) # a good package for graphing
data <- mtcars %>%
    group_by(gear) %>%
    summarise(SD = sd(mpg),
              SE= (SD/sqrt(length(mpg))),
              MEAN = mean(mpg)
              )
carplot <- ggplot(data,
                   aes(x = factor(gear),
                       y = MEAN
                       )
                   ) +
    geom_bar(stat = "identity") + 
    geom_errorbar(aes(ymin = MEAN - SE,
                      ymax = MEAN + SE
                      ),
                  width = 0.25,
                  size = 0.5
                  ) +
    ggtitle("\\MyContrivedTitle") +
    xlab("Gear") +
    ylab("Mean MPG") +
    theme(plot.margin=unit(c(1,0,0,0),"cm"))
carplot
@

\end{document} 

This produces the following output:

example output of the above MWE demonstrating the better typesetting with knitr and tikzDevice

1.2. More versatile chunk options in knitr (compared to Sweave)

This example is taken directly from Yihui. In knitr (but not Sweave), it is possible to delay the evaluation of certain chunk options, so that you could, for example, include the p-value of a t-test in a caption.

\documentclass{article}

\begin{document}

\section{Introduction}

<<setup, include=FALSE, cache=FALSE>>=
library(knitr)
opts_knit$set(eval.after = 'fig.cap') # evaluate fig.cap after the chunk
opts_chunk$set(cache=FALSE,
               echo=FALSE,
               message=FALSE,
               warning=FALSE,
               highlight=FALSE,
               sanitize=FALSE,
               tidy=TRUE,
               dev='tikz',
               fig.env='figure',
               fig.show='hold',
               fig.lp='fig:',
               fig.align='center',
               fig.pos='htbp',
               out.width='.75\\textwidth'
               )
@


<<t-test, fig.cap=paste("The P-value is", t.test(x)$p.value)>>=
x = rnorm(100)
boxplot(x)
@

\end{document}

The output of this is:

output of the example MWE demonstrating delayed chunk option evaluation

2. knitr vs. Thruston's suggested approach

If you prefer to keep your R code and your LaTeX code separate, Thruston's suggested approach is not necessarily preferable, because it is possible to use external R code in a LaTeX document with knitr. That being said, there are some advantages and disadvantages of the two different approaches that are worth mentioning.

Some advantages of knitr over Thruston's suggested approach are:

  • You have a literately programmed document and thus reproducible research/workflow/whatever.
  • There's very little room for human error (except in writing your R code, of course).
  • It's easier to get consistent fonts across the document and figures (though it's not impossible to do this if you use Thruston's suggested approach and have your R code output a PDF with the font that you want to use embedded in the PDF).

Some advantages of Thruston's suggested approach over knitr are:

  • Your R code is not evaluated each time you compile your document, so compilation time will be faster, potentially a lot faster if you're drawing a lot of graphics or doing heavy calculations in R (though this can be mitigated to some extent with caching).
  • Your source code could potentially be more human-readable (but this introduces more room for human error). For example, the following code block is arguably less human readable than the subsequent code block:

Using knitr to make a document more reproducible (but trading off in readability):

\begin{tabular}{lcc}
                   & Adults                                                                       & Children \\
Active sentences   & \Sexpr{data[data$GROUP == "Adults" & data$CONDITION == "Active",]$ACCURACY}  & \Sexpr{data[data$GROUP == "Children" & data$CONDITION == "Active",]$ACCURACY} \\
Passive sentences  & \Sexpr{data[data$GROUP == "Adults" & data$CONDITION == "Passive",]$ACCURACY} & \Sexpr{data[data$GROUP == "Children" & data$CONDITION == "Passive",]$ACCURACY} \\
\end{tabular}

Not using knitr but copying and pasting the values from the output of an R script (thus arguably being more human-readable but introducing more possibility for human error):

\begin{tabular}{lcc}
                   & Adults  & Children \\
Active sentences   & 98      & 93 \\
Passive sentences  & 94      & 67 \\
\end{tabular}

3. ezknitr vs. knitr


UPDATE: It seems that ezknitr does not currently process .Rnw files. Hopefully this is a feature that will be added in the future (see here; also see here).


I have yet to try out ezknitr myself, so I'll have to update this answer once I have a chance to do so, but the blog post that introduces ezknitr suggests that it addresses problems with paths and working directories that can sometimes be frustrating. To quote from the blog post:

One common source of frustration with knitr is that it assumes the directory where the source file lives should be the working directory, which is often not true. ezknitr addresses this problem by giving you complete control over where all the inputs and outputs are, and adds several other convenient features. The two main functions are ezknit() and ezspin(), which are wrappers around knitr's knit() and spin(), used to make rendering markdown/HTML documents easier.

This is presumably useful, especially if you are building documents from the command line for a project with files in many different directories.

4. Compiling (from the command line)

For posterity: RStudio—for the most part—is a good IDE for use with knitr and LaTeX (things get dicey as soon as you have a bibliography involved).

You said you were more interested in compiling documents from the command line. When you use knitr, you edit a .Rnw file and then you process it with knitr's knit() function, which outputs a .tex file. You never want to edit that .tex file directly. All changes should be made to the .Rnw file, and then you should regenerate the .tex file using knit().

Thus, you could build your document from the command line by doing something like this:

Rscript -e "library(knitr); knit('my_file.Rnw')" # this command produces my_file.tex
pdflatex my_file.tex                             # this command produces my_file.pdf

You could also easily write some sort of batch/make/bash script to do this.2


Notes

  1. It seems that there is a problem when setting the dev chunk option to tikz in knitr and loading fontspec, so it's not possible to use an arbitrary font with XeLaTeX or LuaLaTeX, unfortunately. Hopefully this is an issue that will be fixed soon.
  2. There is currently a problem in using arara to build .Rnw documents from the command line, but in the upcoming version of arara, Paulo has promised an out-of-the-box and batteries-included arara rule that works with knitr, so it should be possible to use arara to build .Rnw documents in the (near) future.
8
  • 1
    I was wondering when you would crawl out from under your poster to answer this :)
    – Alan Munn
    Jan 6, 2016 at 21:28
  • Thanks Adam. I'll have a look at ntr/enitr. (Having to run two commands from the command line instead of one isn't a real problem. My main concern is that I'd like to keep the R and LaTeX documents integrated.)
    – user10274
    Jan 7, 2016 at 6:32
  • 1
    @MarcvanDongen knitr is a good way to do that then! :) And the 0. tl;dr is a summary. tl;dr has come to stand for "Too long; didn't read". The 0 was just for sectioning purposes since the answer is so long, but it seemed more appropriate to have the summary be section 0, rather than section 1.
    – Adam Liter
    Jan 7, 2016 at 6:37
  • 1
    @AlanMunn :p Finished with a full 24 hours to print!
    – Adam Liter
    Jan 7, 2016 at 6:37
  • 1
    @jabberwocky Looks like you might have Sweave—not knitr—set as RStudio's default engine for compiling .Rnw files. There is an option in RStudio's Tools > Global Options > Sweave to change it to knitr.
    – Adam Liter
    Jan 19, 2017 at 1:17
18

The baseline approach is just to keep them separate. My work flow on a recent paper was as follows:

  1. I wrote an R script to calculate the statistics and generate (a) charts and (b) tables of numbers.

    The script produced charts either as eps (which I used with LaTeX) or as png (which were needed for the online version of the paper). The charts had long descriptive file names.

    The tables were produced as plain text using the R sink() function to capture the output from aggregate and table.

  2. I wrote a LaTeX document that embedded the charts with includegraphics (using the nice long descriptive names, so I knew which was which).

    For the tables, I just copied the text from the tables output file into my LaTex source and marked the tables up using an editor macro.

  3. When I needed to make changes, the charts were easy: I just ran the R script to re-create the eps files and re-ran LaTeX to re-create the final pdf.

    The tables were a bit harder, but not much: I just replaced body of each table from the text output file produced by R and marked them up again. Since I was using my macro, and because I retained the table header and footer in the LaTeX source, this only took a second or two for each table.

The main advantage of this approach was simplicity; I retained all control of formatting in the LaTeX source. The main disadvantage was that I had to re-create the tables semi-manually for each change, and that I had to maintain two scripts. On the other hand it was very useful on this occasion to have an R script that could produce versions of the same chart in two different formats.

Code

Here's my R function to switch between png and eps.

desired.format = "eps"

fig <- function(name) {
   if(desired.format=="png") {
       png(filename=sprintf("%s-A.png",name), width=1536, height=1152, res=144)
   }
   else if (desired.format=="eps") {
       postscript(file=sprintf("%s-A.eps",name), onefile=FALSE, horizontal=FALSE, paper="special", width=10, height=7.5)
   }
}
2
  • 1
    Thanks. Ideally, I'd not want to do that. I just want to run LaTeX once or twice and then end up with the document. E.g. I'd like to generate the data for the pictures using R and then create them with TikZ. Having seen Sweave and the example on TeXample.net I know this should be possible. Before committing to a solution, I want to know a bit more about the solutions, which is why i asked the question.
    – user10274
    Dec 30, 2015 at 12:22
  • 1
    I'm sure that approaches like that are possible, but I thought it might be interesting to have a base line for comparison. I find that the law of diminishing returns sets in quite soon with this sort of automation.
    – Thruston
    Dec 30, 2015 at 12:39
7
+150

Are there other approaches?

Yes, lazyWeave. While Sweave and knitr process LaTeX files with R chunks (R noweb files), lazyWeave can create LaTeX documents from scratch.

Beside this, it is worth to note that other R packages as the famous xtable and Hmisc can produce some type ofLaTeX code.

What are the merits?

To be honest, I never used lazyWeave, but according to the documentation provides the functionality to write complete documents LaTeX code from within R without messing too much with LaTeX code, being the main strength the design of reports with custom and complex tables. But the same documentation also alert that knitr approach is easier (i.e, messing with lazyWeave functions is a doubtful advantage), that lazyWeave is a "rather inefficient way to go about writing reports with LaTeX" and that "is only intended to provide the most basic functionality of LaTeX".

With respect the documentation, is the typical of R packages, were each function is systematically described even with some examples, but still it is hard to guess how combine them to have a working report, since some buggy aspects are not well explained. I left as exercise how discover that you need the lazyWeave_latexComments="latex" option to avoid HTML comments in the ouput, or why only lazy.matrix(df) alone work (you see LaTeX code in the ouput), but not lazy.write( ...,lazy.matrix(df),...) although it is supposed that should work regarding the non-working example.

In spite of this, below is showed my first moderately successful test.

Others packages as xtable or Hmisc can produce only LaTeX chunks but fortunately can be used without problems with Sweave/knitr chunks (using the options results='tex' or results='asis' respectively) or even lazyWeave.

lazyWeawe MWE

1) Run the following R script. (It is assumed that lazyWeawe is already installed)

# R script
library(lazyWeave)
df <- data.frame(A=c(1,2,3),B=c("a","b","c"),C=c(3.3,5.3,7.5))
options(lazyReportFormat="latex",lazyWeave_latexComments="latex")
lazy.write(
lazy.file.start(title="My MWE of lazyWeave",author="Fran",date="\\today"),
lazy.toc(),
lazy.section("Introduction", ordered=TRUE), 
lazy.text("This MWE \\LaTeX\\ example was made with recyclable electrons."), 
lazy.section("Example data frame", ordered=TRUE), 
lazy.matrix(df,cat=F), 
lazy.section("Mean test", ordered=TRUE),
lazy.text("The mean of C is ",round(mean(df$C),1)," that is not 0 with p=",round(t.test(df$C)$p.value,3),"."), 
lazy.file.end(), 
OutFile="Example.tex")

1b) Edit the ouput file Example.tex and remove the packages breakurl and Sweave to avoid compilation errors, and save it. This point should not exist. It is possible add additional LaTeX packages in the lazy.file.start function but not remove the default package. However, it is a minor problem. If you need a working file without any edition, it should be to easy construct your own through lazy.text("\\documentclass ...") or even rewriting the lazy.file.start() function.

2) Compile Example.tex. The result should be:

mwe

2
  • Thanks. It would be nice if you could provide an example.
    – user10274
    Jan 11, 2016 at 15:37
  • 2
    @MarcvanDongen It is done.
    – Fran
    Jan 12, 2016 at 20:03
3
+250

Some critiques of Thruston's alternative approach v knitr:

  1. It is actually possible to create multiple outputs of plots from the one .Rnw file (only including the pdf version in the LaTeX output). In a report I did recently, each time the document was compiled, each plot was rendered as:

    a. a pdf

    b. a png

    c. a Windows Enhanced Metafile

    d. a PowerPoint slide

    in addition, I wrote a hook that wrote the data supplied to each ggplot chart to a csv file. All these things add to the compilation time (though not much actually), and require additional setup. But it is simply a matter of passing additional functions to the dev chunk option in knitr::opts_chunk$set(). For example knitr::opts_chunk$set(dev = c("pdf", "png"), fig.ext = c("pdf", "png")) will produce a pdf and png for each plot.

  2. Don't underestimate your need to generate your prose as well as your tables and plots through R. For example, our report looked at the impacts of a particular tax change on budget revenue and number of people affected. A few weeks from release, we decided to modify these tax proposals slightly. If we hadn't had a literate copy of the document, sentences like:

    Our proposal (estimated to raise $1 billion in 2017-18) would affect only 13% of the poorest one-fifth of households.

    which were peppered throughout the report, were at a high risk of not being updated. Instead, they were automatically updated simply by modifying a single value at the top of the script.

    Our proposal (estimated to raise $1.3 billion in 2017-18) would affect only 14% of the poorest one-fifth of households.

    And because R can create objects, you needn't use verbose R expressions in \Sexpr. Instead, evaluate the object you need in a chunk, and pass that

    <<revenue_from_policy>>=
    revenue1718_from_policy <- 
      ... calculations ...
    @
    
    <<prop_affected_bottom_quintile>>=
    prop_affected_bottom_quintile <- 
      ... calculations ...
    @
    
    Our proposal (estimated to raise \Sexpr{revenue1718_from_policy} in 2017-18) would affect only \Sexpr{percent(prop_affected_bottom_quintile)} of the poorest one-fifth of households.
    
    1. RStudio makes knitr very easy. You simply hit Compile PDF in an Rnw file and it just works. It also allows things like code-folding and provides keyboard shortcuts for running chunks of code in the REPL. That said, as a pure LaTeX IDE, RStudio pales in comparison to others. Syntax highlighting is basic, error parsing and code completion is basically non-existent. Furthermore, you can basically only run pdflatex or xelatex on the tex file. In particular, you can't run (directly) biber etc. I believe that in the later half of this year (Sept 2016) there will be a substantial improvement to these features, but nothing yet. That said, RStudio is the supreme IDE for R. And it's straightforward to switch to another IDE to write your prose.

    2. I find tikzDevice to be quite unwieldy. There are problems with certain fonts, errors are common, and it's basically a take-it-or-leave-it approach the tikz file -- it's difficult to edit the tikz. I'd say you are far better off using the chunk option fig.showtext=TRUE and library(sysfonts) to apply consistent fonts in your charts. This is not a disadvantage of knitr, just an observation that I have not found tikzDevice to be one of its advantages.

To get the same fonts, use the following method (for helvet):

<<font_add>>=
library(showtext)
library(sysfonts)
library(knitr)
font.add("helvet", 
         regular = "C:/Program Files/MiKTeX 2.9/fonts/type1/urw/helvetic/uhvr8a.pfb", 
         bold = "C:/Program Files/MiKTeX 2.9/fonts/type1/urw/helvetic/uhvb8a.pfb", 
         italic = "C:/Program Files/MiKTeX 2.9/fonts/type1/urw/helvetic/uhvro8a.pfb")

ggplot2::update_geom_defaults("text", list(family = "helvet"))
ggplot <- function(...) ggplot2::ggplot(...) + ggplot2::theme_grey(base_family = "helvet")
@

Incorporating booktabs is easy with xtable:

<<mytable, results='asis'>>=
library(xtable)
print.xtable(xtable(data.frame(abdef = 1:5, ghif = 1:5)), booktabs = TRUE)
@

I've made use of the function described in this answer https://stackoverflow.com/q/36660598/1664978, which highlights that automatic but succinct production of tables are possible.

4
  • +1 for the moment:-) Please show how this guarantees I can get output/plots/tables that use the same fonts as the LaTeX source document. A few pictures would be nice as well.
    – user10274
    Jul 19, 2016 at 17:04
  • The font reference in my previous comment wasn't very clear. I want to make sure I don't have to manually tell knitr about the fonts and the current font size. So I'd like to avoid your font.add.
    – user10274
    Jul 19, 2016 at 17:26
  • What should the font in charts be? How are your charts (in R) produced? Ultimately, you have to specify how R is to draw charts, and their width and height in the pdf. What about your workflow precludes a knitr call to define this aspect of the design? For example, are you writing a document where the fonts in the charts and the prose have to be identical, but the document will be compiled externally (and may be an arbitrary typeface)?
    – Hugh
    Jul 20, 2016 at 2:44
  • Yes, all fonts should be the same as the currently active font in the LaTeX source. I am not sure what you mean by charts. FWIW, providing a good API for creating proper (booktabs) tables and (pgfplots) graphs would already help. I note it's possible to dump a CSV file in R, so it is possible (I've done it) to create a proper plot in LaTeX with pgfplots.
    – user10274
    Jul 20, 2016 at 4:57

You must log in to answer this question.