Custom comparison function for sorting data in R

Many languages allow you to use a custom comparison function in sorting. R is not an exception, but it is not entirely straightforward – it requires you to define a new class and overload certain operators. Here is how to do it.

Consider the following example. You have a certain number of paired values, for example

v <- list(a=c(2,1), b=c(1,3), d=c(1,1), e=c(2,3))

The job is to order these pairs in the following way. Given two pairs, p1=(x1, y1) and p2=(x2, y2), p1 < p2 iff one of the following conditions is fulfilled: either x1 < x2 and y1 <= y2, or x1 <= x2 and y1 < y2. The point is that if we draw lines, where one end of the line is at the height x1, and the other end is at the height y1, we want to sort these lines only if they do not cross — at most, only if one of their ends overlaps (but not both, because then the lines would be identical):

On the figure above, left panel, p1 < p2, because one of the ends is below the end of the other line (x1 < x2 and y1=y2). Of course, if y1 < y2 the inequality still holds. On the other hand, the right panel shows a case where we cannot resolve the comparison; the lines cross, so we should treat them as equal.

If now we have a list of such pairs and want to order it, we will have a problem. Here is the thing: the desired order is {d, a, b, e}. The element d=(1,1) is clearly smaller (as defined above) than all the others. However, b=(1,3) is not smaller than a=(2,1), and a is not smaller than b; that means, that a is equal to b, and their order should not be modified.

There is no way to do that with regular tools such as order, especially since x and y may not only be on different scales — they might be even completely different data types! One might be a numeric vector, the other a character string. Or, possibly, a type of requisite from Monty Python (with a defined relation stating that a banana is less than a gun). We must use a custom comparator.

For this, we need to notice that the R functions sort and order rely on the function xtfrm. This in turns relies on the methods ==, &gt; and [, defined for a given class. For numeric vectors, for example, these give what you would expect.

Our v vector is a list with elements which are pairs of numbers. For this type of data, there is no comparison defined; and comparing two pairs of numbers results with a vector of two logical numbers, which is not what we want.

> v[1] < v[2]
Error in v[1] < v[2] : comparison of these types is not implemented
> v[[1]] < v[[2]]
[1] FALSE  TRUE

R, however, is an object oriented language (even if it does not always feel like that). Comparisons (“, ==) are generic functions and it is possible to define (or redefine) them for any class of objects. So here is the plan: we invent a new class for the object v, and define custom comparisons for the elements of this class of objects. Remember that if we define a function which name consists of a generic (like "plot" or "["), a dot, and a name of the class, we are defining the method for the given class:

## make v an object of class "foo"
class(v) <- "foo"

## to use the "extract" ([) method, 
## we need to momentarily change the class of x, because 
## otherwise we will end up in an endless loop
'[.foo' <- function(x, i) {
    class(x) <- "list"
    x <- x[i]
    class(x) <- "foo"
    x
}

## define ">" as stated above
## the weird syntax results from the fact that a and b
## are lists with one element, this element being a vector 
## of a pair of numbers
'>.foo' <- function(a,b) {
a <- a[[1]]
b <- b[[1]]
ifelse( (a[1] > b[1] && a[2] >= b[2])
                     ||
        (a[1] >= b[1] && a[2] > b[2]), TRUE, FALSE)
}

## if we can't find a difference, then there is no difference
'==.foo' <- function(a, b) 
    ifelse(a > b || b > a, FALSE, TRUE)

## we don't need that, but for the sake of completeness...
'<.foo' <- function(a, b) b > a

This will now do exactly what we want:

> v["a"] == v["b"]
[1] TRUE
> v["a"] > v["d"]
[1] TRUE
> sort(v)
$d
[1] 1 1

$a
[1] 2 1

$b
[1] 1 3

$e
[1] 2 3

attr(,"class")
[1] "foo"

Adding figure labels (A, B, C, …) in the top left corner of the plotting region

I decided to submit a manuscript using only R with knitr, pandoc and make. Actually, it went quite well. Certainly, revisions of manuscript with complex figures did not require much of manual work once the R code for the figures has been created. The manuscript ended up as a Word file (for the sake of co-authors), looking no different than any other manuscript. However, you can look up precisely how all the figures have been generated and, with a single command, re-create the manuscript (with all figures and supplementary data) after you changed a parameter.

One of the small problems I faced was adding labels to pictures. You know — like A, B, C… in the top right corner of each panel of a composite figure. Here is the output I was striving at:

Doing it proved to be more tedious than I thought at first. By default, you can only plot things in the plotting region, everything else gets clipped — you cannot put arbitrary text anywhere outside the rectangle containing the actual plot:

plot(rnorm(100))
text(-20, 0, "one two three four", cex=2)

This is because the plotting are is the red rectangle on the figure below, and everything outside will not be shown by default:

One can use the function mtext to put text on the margins. However, there is no simple way to say “put the text in the top left corner of the figure”, and the results I was able to get were never perfect. Anyway, to push the label really to the very left of the figure region using mtext, you first need to have the user coordinate of that region (to be able to use option ‘at’). However, if you know these coordinates, it is much easier to achieve the desired effect using text.

First, we need to figure out a few things. To avoid clipping of the region, one needs to change the parameter xpd:

par(xpd=NA)

Then, we need to know where to draw the label. We can get the coordinates of the device (in inches), and then we can translate these to user coordinates with appropriate functions:

plot(rnorm(100))
di <- dev.size("in")
x <- grconvertX(c(0, di[1]), from="in", to="user")
y <- grconvertY(c(0, di[2]), from="in", to="user")

x[1] and y[2] are the coordinates of the top left corner of the device… but not of the figure. Since we might have manipulated the layout, for example, by calling par(mfrow=...) or layout to put multiple plots on the device, and we would like to always label the current plot only (i.e. put the label in the corner of the current figure, not of the whole device), we have to take this into account as well:

fig <- par("fig")
x <- x[1] + (x[2] - x[1]) * fig[1:2]
y <- y[1] + (y[2] - y[1]) * fig[3:4]

Before plotting, we have to adjust this position by half of the text string width and height, respectively:

txt <- "A"
x <- x[1] + strwidth(txt, cex=3) / 2
y <- y[2] - strheight(txt, cex=3) / 2
text(x, y, txt, cex=3)

Looks good! That is exactly what I wanted:

Below you will find an R function that draws a label in one of the three regions — figure (default), plot or device. You specify the position of the label using the labels also used by legend: “topleft”, “bottomright” etc.

First, a few examples how to use it:

Basic use:

par(mfrow=c(2,2))
sapply(LETTERS[1:4], function(x) { 
    plot(rnorm(100))
    fig_label(x, cex=2) 
})

Result:

Plotting at different positions and in different regions:

plot(rnorm(100))
for(i in c("topleft", "topright", "top", 
           "left", "center", "right", 
           "bottomleft", "bottom", "bottomright")) {
    fig_label(i, pos=i, cex=2, col="blue")
    fig_label(i, pos=i, cex=1.5, col="red", region="plot")
}

Result:

All the different regions:

par(mfrow=c(2,2))
sapply(LETTERS[1:4], function(x) { 
    plot(rnorm(100))
    fig_label("figure region", cex=2, col="red") 
    fig_label("plot region", region="plot", cex=2, col="blue")
})
fig_label("device region", cex=2, pos="bottomright", 
  col="darkgreen", region="device")

Result:

And here is the function:

fig_label <- function(text, region="figure", pos="topleft", cex=NULL, ...) {

  region <- match.arg(region, c("figure", "plot", "device"))
  pos <- match.arg(pos, c("topleft", "top", "topright", 
                          "left", "center", "right", 
                          "bottomleft", "bottom", "bottomright"))

  if(region %in% c("figure", "device")) {
    ds <- dev.size("in")
    # xy coordinates of device corners in user coordinates
    x <- grconvertX(c(0, ds[1]), from="in", to="user")
    y <- grconvertY(c(0, ds[2]), from="in", to="user")

    # fragment of the device we use to plot
    if(region == "figure") {
      # account for the fragment of the device that 
      # the figure is using
      fig <- par("fig")
      dx <- (x[2] - x[1])
      dy <- (y[2] - y[1])
      x <- x[1] + dx * fig[1:2]
      y <- y[1] + dy * fig[3:4]
    } 
  }

  # much simpler if in plotting region
  if(region == "plot") {
    u <- par("usr")
    x <- u[1:2]
    y <- u[3:4]
  }

  sw <- strwidth(text, cex=cex) * 60/100
  sh <- strheight(text, cex=cex) * 60/100

  x1 <- switch(pos,
    topleft     =x[1] + sw, 
    left        =x[1] + sw,
    bottomleft  =x[1] + sw,
    top         =(x[1] + x[2])/2,
    center      =(x[1] + x[2])/2,
    bottom      =(x[1] + x[2])/2,
    topright    =x[2] - sw,
    right       =x[2] - sw,
    bottomright =x[2] - sw)

  y1 <- switch(pos,
    topleft     =y[2] - sh,
    top         =y[2] - sh,
    topright    =y[2] - sh,
    left        =(y[1] + y[2])/2,
    center      =(y[1] + y[2])/2,
    right       =(y[1] + y[2])/2,
    bottomleft  =y[1] + sh,
    bottom      =y[1] + sh,
    bottomright =y[1] + sh)

  old.par <- par(xpd=NA)
  on.exit(par(old.par))

  text(x1, y1, text, cex=cex, ...)
  return(invisible(c(x,y)))
}

Using external data from within another package

If you make the error which I did, you will try to use the data (say, “pckgdata”) from another package (say, “pckg”) naively like this:

someFunc <- function() {
  data(pckgdata)
  foo <- pckgdata$whatever
}

This will result in an error:

someFunc: no visible binding for global variable ‘pckgdata’
someFunc : <anonymous>: no visible binding for global variable
  ‘pckgdata’
Undefined global functions or variables:
  pckgdata

Here is the solution (thanks to the comments from stackexchange:

.myenv <- new.env(parent=emptyenv())

someFunc <- function() {
  data("pckgdata", package="pckg", envir=".myenv")
  foo <- .myenv$pckgdata$whatever
}

Actually, let us load the object as soon as our package is loaded:

.myenv <- new.env(parent=emptyenv())

.onLoad <- function(libname, pkgname){
  data("pckgdata", package="pckg", envir=".myenv") 
}

someFunc <- function() {

  foo <- .myenv$pckgdata$whatever
}

Now any of the functions in our package can use the pckgdata, whenever. Note that we want to use .onLoad(), and not .onAttach() — the latter one is for such things as startup messages when the package is manually attached by the user.

Alternatively, you can create your environment within the function itself:

<br />someFunc <- function() {
  myenv <- new.env(parent=emptyenv())
  data("pckgdata", package="pckg", envir="myenv")
  foo <- .myenv$pckgdata$whatever
}

R-devel in parallel to regular R installation

Unfortunately, you need both: R-devel (development version of R) if you want to submit your packages to CRAN, and regular R for your research (you don’t want the unstable release for that).

Fortunately, installing R-devel in parallel is less trouble than one might think.

Say, we want to install R-devel into a directory called ~/R-devel/, and we will download the sources to ~/src/. We will first set up two environment variables to hold these two directories:

export RSOURCES=~/src
export RDEVEL=~/R-devel

Then we get the sources with SVN. In Ubuntu, you need package subversion for that:

mkdir -p $RSOURCES
cd $RSOURCES
svn co https://svn.r-project.org/R/trunk R-devel
R-devel/tools/rsync-recommended

Then, we compile R-devel. R might complain about missing developer packages with header files, in such a case the necessary package name must be guessed and the package installed (e.g. libcurl4-openssl-dev for Ubuntu when configure is complaining about missing curl):

mkdir -p $RDEVEL
cd $RDEVEL
$RSOURCES/R-devel/configure && make -j

That's it. Now we just need to set up a script to launch the development version of R:

#!/bin/bash
export PATH="$RDEVEL/bin/:\$PATH"
export R_LIBS=$RDEVEL/library
R "$@"

You need to save the script in an executable file somewhere in your $PATH, e.g. ~/bin might be a good idea.

Here are commands that make this script automatically in ~/bin/Rdev:

cat <<EOF>~/bin/Rdev;
#!/bin/bash

export R_LIBS=$RDEVEL/library
export PATH="$RDEVEL/bin/:\$PATH"
R "\$@"
EOF
chmod a+x ~/bin/Rdev

One last thing remaining is to populate the library with packages necessary for the R-devel to run and check the packages, in my case c("knitr", "devtools", "ellipse", "Rcpp", "extrafont", "RColorBrewer", "beeswarm", "testthat", "XML", "rmarkdown", "roxygen2" ) and others (I keep expanding this list while checking my packages). Also, bioconductor packages limma and org.Hs.eg.db, which I need for a package which I build.

Now I can check my packages with Rdev CMD build xyz / Rdev CMD check xyz_xyz.tar.gz

Presentations in (R)markdown

There are many ways to turn a markdown or Rmarkdown document into a presentation. Way too many, and none of them is perfect. I made my first presentation with knitr / Rmarkdown for the tmod package.

After trying various options in knitr, I decided on an approach in which the Rmarkdown document is oblivious of the presentation system and the job of turning it into a presentation is taken up by pandoc. There were several bumps and problems, and I will give now a step – by – step guide.

1. Input file

Let’s start with an example Rmd. In the following, I assume it has been saved under “test.Rmd”.

---
title: "Example presentation"
author: January Weiner 
date: "`r Sys.Date()`"
---

# First part
## Slide 1
Code:

```{r plot1}
plot(1:10, 1:10)
```

## Slide 2
Some maths: $sum_{i=1}^{N}$

# Second part
## Slide 3
... contents ...

2. From Rmarkdown to markdown

I use knitr only to create a markdown file.

Rscript -e 'knitr::knit("test.Rmd")'

This produces the file test.md. With that, knitr’s job is finished, we will not need it anymore.

3. Download reveal.js

I decided for reveal.js. It was easy to work with and adapt to my needs, it had elegant default themes, it has a low footprint and shortcuts. And it has the “2D” layout, meaning that sections (level one headers) are arranged horizontally, while slides within one section are arranged vertically. Pressing “Esc” in a presentation shows the slide overview:

reveal_example

Anyway, download reveal.js and unpack it in the same directory as test.md.

Making the presentation

Use pandoc to create the reveal.js presentation. Note that this is not the final command line; in the following points I will discuss the problems which will influence the final version.

pandoc -s -S -t revealjs --mathjax -o test.html test.md

4. MathJax

On slide 2, we have a bit of maths. The maths is written in a LaTeX-like notation, and there are many ways to turn it into an elegant mathematical equation on the final presentation. I have tried many options with pandoc, and found that only MathJax works properly and without a major hassle. This is why on the previous command line I used the option --mathjax.

However, if you run the above command line, you will notice that on “Slide 2”, the maths doesn’t work, despite using the ‘–mathjax’ option. It would work, though, if we put the file on a server. The reason is that pandoc puts the URL to MathJax in the form ‘src=”//cdn.mathjax…”‘. This assumes the context of how we opened the file. If we opened it from a server, using http or https, this would have worked. If we open it directly in a browser, it uses “file://cdn.mathjax…” which is obviously not on our file system. We have two options.

4.1 External MathJax

Use the command line

pandoc -s -S -t revealjs --mathjax="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" -o test.html test.md

This works unless we have no Internet access, for example because we show our presentation in another institute, where our laptop cannot connect to the Internet, because then we are screwed.

4.2 Local MathJax

Alternatively, you can download the whole MathJax:

wget https://github.com/mathjax/MathJax/archive/v2.5-latest.zip
unzip v2.5-latest.zip
mv MathJax-2.5-latest/ MathJax

and specify the local installation with the following command line:

pandoc -s -S -t revealjs --mathjax="MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML" -o test.html test.md

This works, but our presentation has suddenly over 170 megabytes. Which sucks.

5. 2D layout and section headers

I mentioned previously that reveal.js allows a neat 2D layout, in which slides from one section are arranged vertically, and sections are put next to each other. However, sections with only a title and no contents might be a bit boring, so let us modify the .md file changing the second section as follows:

# Second part

This is the second part, even more interesting.

## Slide 3
... contents ...

You run pandoc again, and…

reveal2

Huh, where is the 2D layout gone? Why are all slides next to each other? Why are all slides from one section all on one single slide?

Pandoc automatically guesses which level header denotes boundaries between slides. It defines “slide level” as “the highest level followed immediately by non-header contents”. After our modification, the top level header (starting with a single #) became the level at which slides are separated. OK, so maybe we try specifying the slide level manually?

pandoc -s -S -t revealjs --mathjax="MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML" -o test.html test.md

OK, this works, but… the contents under the first level header (“This is the second part…”) is gone! This is because “Headers above the slide level in the hierarchy create “title slides,” which just contain the section title and help to break the slide show into sections.”

Turns out that there is no way we can have both: 2D with slides divided neatly into sections, and section slides which contain more than just a title. Not if we use pandoc, that is.

6. Modifying the layout

6.1 reveal.js theme

This is the easiest part: pick one of the existing reveal.js themes (I omit the mathjax command line for simplicity sake, do remember to put it back in):

pandoc -s -S -t revealjs -o test.html test.md -V theme=blood

Note that the themes listed on the reveal.js website start with a capital letter, but you must specify a lowercase letter in the above command line.

6.2 Fine tuning the theme

I did not like the sans-serif, capitalized and decorated fonts of the blood theme (shadows on titles, I beg you). Ugly. However, if you know a little CSS (and you’d better learn it!), you can easily adapt it to your needs.

Look up the file reveal.js/css/theme/blood.css for hints and create your own CSS file (let us call it test.css) in the same directory as test.md. In the file below, I reset all the ugly decorations and set two fonts for headers and body, respectively: Garamond for headers, and Quattrocento Sans for body, using the google fonts service:

@import url('http://fonts.googleapis.com/css?family=EB+Garamond');
@import url('http://fonts.googleapis.com/css?family=Quattrocento+Sans');

.reveal {
  font-size: 32px;
  font-family: 'Quattrocento Sans', 'sans-serif'; }

.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {
  font-family: 'EB Garamond', 'serif';
  font-weight:normal;
  text-transform: none;
  text-shadow: none; }

.reveal h1 { font-size: 2em; }
.reveal h2 { font-size: 1.7em; }
.reveal h3 { font-size: 1.4em; }
.reveal h4 { font-size: 1em; }

Also, as you might notice, I prefer smaller fonts here. We integrate our test.css file with the following option

pandoc -s -S -t revealjs -o test.html test.md -V theme=blood --css test.css

6.3 Adding a logo

You can add a logo (or whatever other background for your slides) by modifying the CSS file test.css. If logo.png is the name of your logo, adding this to your CSS will put it on all your slides in the top left corner:

body {
  background-image: url(logo.png);
  background-repeat: no-repeat;
  background-position:20px 20px;
}

6.4 Better syntax highliting

Pandoc’s syntax highlighting doesn’t look good on a dark background. You can add the following to the “test.css” file to reproduce the Solarized theme.

.reveal pre code { color: #839496; 
  background-color: #2B2B2B; } /* use #FDF6E3 for light background */

.sourceCode .kw { color: #268BD2; }
.sourceCode .dt { color: #268BD2; }
.sourceCode .dv, .sourceCode .bn, .sourceCode .fl { color: #D33682; }
.sourceCode .ch { color: #DC322F; }
.sourceCode .st { color: #2AA198; }
.sourceCode .co { color: #93A1A1; }
.sourceCode .ot { color: #A57800; }
.sourceCode .al { color: #CB4B16; font-weight: bold; }
.sourceCode .fu { color: #268BD2; }
.sourceCode .re { }
.sourceCode .er { color: #D30102; font-weight: bold; }
}

# 7. Creating a PDF of your presentation

Of course you need a PDF for printing and as a backup.

There are two ways for producing PDF from reveal.js. Each one is imperfect. 

## 7.1 Creating PDF using pandoc

Since the `test.md` file is a generic markup, we can turn it into a simple PDF

```bash
pandoc -s -S -o test.pdf test.md

Or even beamer presentation:

pandoc -s -S -t beamer -o test.pdf test.md

Unfortunately, this is not so nice as our presentation, and completely ignores whatever we have put in the CSS.

7.2 Using the reveal.js printing facility and Google Chrome

The second way is interactive only (you cannot create the PDF with a command line). Open the file in google chrome and add ?print-pdf to the file URL, such that the end of the URL reads test.html?print-pdf.

The output looks garbled: the slides overlap. Don’t worry, it’s OK. Open the print dialog (press Ctrl-P), and you will see that now the output is correct. You can save it as PDF or send it to a printer.

8. The final command line

pandoc -s -S -t revealjs --mathjax="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"  -V theme=blood --css test.css -o test.html test.md

Kneat tricks

So I have finally switched to knitr for doing my vignettes. The result is satisfactory, but the process was not entirely painless.

  • The command to run instead of “R CMD Sweave foo.Rnw” is

    Rscript -e 'rmarkdown::render("foo.rmd")'

  • I think that the concept of writing a package which has the main purpose to generate documentation in literate programming without providing mandatory documentation (such as list of options) within the package itself, referring instead to the online resources is beautifully subversive.

  • Knitr in the current R version requires pandoc X.Y.Z, while Ubuntu has X.Y.(Z-1). It was necessary to download the deb package from the pandoc site and install it manually.

  • To use knitr in vignettes, you need to add `VignetteBuilder:knitr` to your `DESCRIPTION` file.

  • I was confused at first as to what to do the old vignette header (the lines that start with “%\Vignette…”). The markdown header is different. Turns out you have to include these lines in the markdown header (Kill me, but I have no idea why there is a “>” behind “vignette:” or “|” behind “abstract:”. Knitr produces neat results, but it is one of the most confusing packages I have ever encountered.):

                    ---
                    title: "FOO: the fooly of foology"
                    author: "January Weiner"
                    date: "`r Sys.Date()`"
                    output: 
                      pdf_document:
                    vignette: >
                      %\VignetteIndexEntry{Foo}
                      %\VignetteKeyword{foo}
                      %\VignetteKeyword{foology}
                      %\VignetteEngine{knitr::rmarkdown}
                      %\SweaveUTF8
                      \usepackage[utf8](inputenc)
                    abstract: |
                      Foo foo foo foo. Foo foo, foo foo foo, foo.
                    toc: yes
                    bibliography: bibliography.bib
                    ---
     

  • <>= becomes ```{r label, fig.width=5, fig.height=5}. Also, any character argument to options must be in quotes.

  • I have no idea why fig.width=5 works, but opt.chunk$set(fig.width=5) doesn’t and at this point I don’t care to ask.

  • I had a nightmarish forensic experience trying to figure out why my figures don’t get updated, where is the cache and some other things. Turns out that if you provide a symbolic link to an rmd file to knitr, it will change to the directory to where the original is. Which is not the same behavior as in the case of Sweave.

  • It turns out that some options are valid for HTML, but not PDF, and vice versa, and you don’t get a warning. Also, it’s not mentioned in the documentation. Why? Because f— you, that’s why. For example, I spent half an hour trying to change the theme of a PDF vignette, after which it turned out that the theme option is not valid for PDFs. There was a table somewhere showing which options can be used when, but I lost the link and can’t find it in the documentation.

  • I haven’t found out how to change the font size if generating pdf_document (my favorite). Update: I have found out that it is not possible.

  • Also, no idea how to prevent breaking code small chunks between pages, which really, really should not happen.

  • At first I specified the vignette engine to be knitr::knitr, but apparently this produces only (botched) HTML vignette (botched: no title, no author, no references). To generate neat, honest-to-Knuth PDF via pandoc and LaTeX, one should use knitr::rmarkdown, although that is not documented anywhere.

    %\VignetteEngine{knitr::rmarkdown}

pandoc, markdown and pander

Pandoc + markdown seem to be a great way of documenting my work.

Markdown syntax is very simple and allows to add basic formatting and figures to an otherwise simple text document, without obfuscating the actual text.

Then I simply compile the document using the pandoc command:

pandoc -o document.docx document.md
pandoc -o document.pdf  document.md

There are some more tricks, of course, and plenty of output formats are possible. One thing I was struggling with was that images in docx files were much too large. It turns out that the PNG graphics I generate from PDFs (which, in turn, come from R) lacked the information about density units. I was using the convert program from ImageMagick, and it turns out it is necessary to add the option -units PixelsPerInch:

convert -density 300 -units PixelsPerInch image.pdf image.png

Another thing that I found useful was the pander package. Of course, there is this whole science of generating dynamic documents and reports from R using Sweave or knittr, but at the moment I rather produce two files: a commented R pipeline and, separately, a report in markdown format.

(The reason for not using knittr is that I given that I work with some very large data sets that sometimes take ages to compute, I would have to work out the details of cacheing and handling code that takes a while to execute. Also, I want to have a document with all commands, for me, and report without any R code for everyone else).

Pander allows to create nice tables in R that can be directly copied and pasted to a markdown document (of course, pander is so much more, but this is my main use at the moment):

pander(foo, 
       emphasize.strong.cols=1, justify="left", 
       style="simple", digits=2, split.tables=Inf)

I was astonished how nice the resulting word file is. The PDFs, which are produced by TeX/LaTeX, I think, are actually more trouble, for example because LaTeX disregards my order of figures and tables, they are all floating objects and there is no easy way to change this from within the document.