R, rmarkdown, cache and objects

If your rmarkdown takes hours to generate, and you want to be able to generate different document output types on the fly, using the output_format option from rmarkdown::render is extremely annoying: every time you change the output format, the cache is reset, so you need to wait hours to get the other format.

I found no clean solution to this problem, but here is an ugly hack. We create a copy of the document and render it. First time it will take hours, but then the cache will be separate from your original document:

file.copy("test.rmd", "test_html.rmd", overwrite=TRUE)
rmarkdown::render("test_html.rmd")

Of course, this is annoying, and we can wrap this two commands with a function. But beware! Markdown by default evaluates in its parent environment, so to make sure it is evaluated in the global environment, you need to set an option. Here is a wrapper function which also opens by default the resulting document in google-chrome:

myrender <- function(fn, open=TRUE) {

  fb <- gsub("\\.rmd$", "", fn, ignore.case=TRUE)
  fn2 <- paste0(fb, "_html.rmd")
  file.copy(fn, fn2, overwrite=T)
  res <- render(fn2, output_format="html_document", envir=globalenv())
  system(sprintf("google-chrome %s", res))
  res
} 

Accessing object from another package by variable

Say the package name is stored in variable x and the name of the object you would like to access from that package (without loading the package) is stored in y. Of course the :: will not work, but fortunately it is just a wrapper around the function getExportedValue, so the following will work:

getExportedValue(x, y)

Invert a list / map

Often we use lists to map keywords onto values, for example

foo <- list(a=c("quark", "fark"), 
            b=c("quark", "foo", "bark"), 
            c=c("fark", "bark"))

To invert this list (such that “fark”, “bark” etc. become keywords, and “a”, “b” and “c” the values), do

foo.rev <- split(rep(names(foo), lengths(foo)), unlist(foo))

split splits a vector or data frame along a factor. In this case, we expand the names of foo using rep such that we get two vectors, as can be seen with the following command:

cbind(rep(names(foo), lengths(foo)), unlist(foo))

with the result

   [,1] [,2]   
a1 "a"  "quark"
a2 "a"  "fark" 
b1 "b"  "quark"
b2 "b"  "foo"  
b3 "b"  "bar"  
c1 "c"  "fark" 
c2 "c"  "bar"

When we apply split() to the first vector with the second to guide the split, we will get

$bar
[1] "b" "c"

$fark
[1] "a" "c"

$foo
[1] "b"

$quark
[1] "a" "b"

R, shiny and source()

This one cost me more time to figure out than it should have. The reason being, it turns out that I never properly understood what the source() function does.

So here is the story: I was setting up a shiny server for a student based on her code. She was running the shiny app from within RDesktop, and so before starting the app with runApp() she would load all necessary object and source() a file called helpers.R with some common calculations.

In order to put the app on a server, I have moved these pre-runApp() initializations into ui.R and server.R. Suddenly, weird errors appeared. The functions in the helpers.R no longer seemed to be able to find anything in the parent environment — object X not found! Even though I called source() immediately after loading the necessary objects into the environment:

# file server.R
load("myobjects.rda")
source("helpers.R")

The solution was, as usual, to read documentation. Specifically, documentation on source():

local   TRUE, FALSE or an environment, determining where the 
        parsed expressions are evaluated. FALSE (the default) 
        corresponds to the user's workspace (the global 
        environment) and TRUE to the environment from which 
        source is called.

The objects which I have load()-ed before were not in the global environment, but instead in another environment created by shiny. However, the expressions from helpers.R were evaluated in the global environment. Thus, a new function defined in helpers.R could be seen from inside server.R, but an object loaded from server.R could not be seen by helpers.R.

It is the first time that I have noticed this. Normally, I would use a file such as helpers.R only to define helper functions, and actually call them from server.R or ui.R. However, I was thinking that source() is something like #include in C, simply calling the commands in the given file as if they were inserted at this position into the code — or called from the environment from which source() was called.

This is not so.