9

I am writing a Rmd report with some R code chunks, obviously. My code structure is like the following:

  • A functions.R script for custom functions
  • DataDependency.R script for loading packages and my data, this already sources functions.R for exactly these tasks
  • Some analysis.R scripts sourcing DataDependency.R
  • Some more furtheranalyis.R sourcing analysis.R, since then I don't have to write some steps multiple times

Therefore, I am heavily depending on the function to source files in a nested way. However, I am unable to accomplish this in RMarkdown which gives me errors every single time (see below). Am I too stupid or is this functionality missing?! All tries so far resulted in error.

The other questions I saw regarding the topic only included sourcing of .Rmd within .Rmd files (here) and the distinction between source() and read_chunk() (here). Both do not answer my question.

I already tried to make sure that it is really the nested sourcing that produces the errors. So here is a minimal working example:

MWE

File mweA.R

x = 1:10

and file mweB.R

source("./mweA.R")
y = x * x

Now, in my .Rmd file I want to just load file B (or both if I must) and then get on with it:

```{r}
source("./mweB.R")
plot(y ~ x)
```

And even if I do this:

```{r}
source("./mweA.R")
source("./mweB.R")
plot(y ~ x)
```

the same error occurs, namely:

Error in file(filename, "r", encoding = encoding) : cannot open the connection Calls: <Anonymous> ... source -> withVisible -> eval -> source -> file Execution halted

Please note that I don't get an error, if I just do source("./mweA.R") or source any other non-depending R script.

Hopefully, there is a (more or less) secret parameter that you have to specify in the chunk which solves all this. I really have a hard time with Rmarkdown's code chunks and it is often not clear to me, what the error is. This mainly keeps me from switching from latex to RMarkdown...

ruaridhw
  • 2,305
  • 8
  • 22
bamphe
  • 328
  • 3
  • 12
  • 1
    [This](https://stackoverflow.com/questions/24464318/sourcing-references-in-rmarkdown-workaround) might be helpful. Also, [another](http://zevross.com/blog/2014/07/09/making-use-of-external-r-code-in-knitr-and-r-markdown/) article on sourcing in `Rmarkdown`. – vladli Feb 08 '18 at 11:51
  • Thanks for the nice links, I was totally unaware of these options. However, no matter if I use the `child` option from the first or the `<>` option from the second example, I end up with errors. However, the first link directed to [this](https://yihui.name/knitr/demo/child/) site, which I will now try to understand ;) – bamphe Feb 08 '18 at 12:07
  • Ok, it seems to me that the `child` option is only useful to include other `.Rmd` or `.Rnw` files, right? And the function to *include* a `R` script is not my problem, but the sourcing of an `R` script within a `R` script is. It is no way obivous to me, why this should be a problem for Rmarkdown... (Even though it will be very useful to me that I now know that you can include the code chunks within the `R` script via the `<< >>` marker!) – bamphe Feb 08 '18 at 12:18
  • I never used `Rmarkdown`. I left these links as I did a quick search on your topic and they seemed like they might help you. From what I understand you need to google how to load other scripts in your `.Rmd` file, what are the differences etc – vladli Feb 08 '18 at 12:22
  • Thank you anyways. `Rmarkdown` is just so poorly documented and so I thought I should just ask for a quick answer to this *supposedly* simple problem. Of course I was searching through the net before ;) – bamphe Feb 08 '18 at 12:31
  • Ok, I found a very annoying workaround: I have to comment out every line in my `R` scripts which does `source()`. Then I have to load all the scripts in their correct order. Also, since I have all paths defined from my R-Project point of view (and `RMarkdown` not) and all in one special `locations.R` script, I will have to change all paths to the `Rmarkdown` format. And then, finally, I cannot move up and down folders correctly... I guess `Rmarkdown` just does not fit my workflow/structure and is also **very frustrating!** – bamphe Feb 08 '18 at 12:53
  • 1
    The error message you provided says that the file does not exist, indicating this is to do with the relative location of your files to one another, not an `rmd` issue. This is easily fixed with [`here`](https://github.com/krlmlr/here) which will resolve all your file paths regardless of whether they are called in an `rmd` directory or the project root. – ruaridhw Feb 08 '18 at 13:03
  • If you run your own reprex there is no error. Are all the files located in the top directory of the project or are some in subdirectories? – ruaridhw Feb 08 '18 at 13:11
  • Nice! The `here` package fixed my problem. I did realize that `R` and `RMarkdown` had a different root directory, but I forgot to adapt the `source` links within the `R` files to `RMarkdown`'s liking... With the `here` package that runs smoothly now. If you put your comment as an answer, I would accept it as such ;) – bamphe Feb 08 '18 at 19:13

1 Answers1

9

The issue you're facing is not related to knitr or being able to correctly nest the documents but is instead a product of the R project "working directory insanity" one faces as rmarkdown will knit the document relative to the file directory as opposed to the project root. This leads to different relative paths depending on whether the document is run in the project session or knitr session.

In addition to the gist, this issue shows a number of workarounds:

knitr specific:

Set a root directory for all chunks to be evaluated relative to rather than the document location.

opts_knit$set(root.dir = '/Users/username/path_to_project')

General case:

Use either rprojroot or here (the latter is a wrapper over the former), which uses several criteria to determine the top level directory of your files. You need not be using an RStudio project for this to work.

Any reference to another local file is called using here::here which will resolve to the same location regardless of the subdirectory in which it's called.

source(here("functions.R"))
source(here("subdirectory", "DataDependency.R"))
source(here("subdirectory2", "furtheranalyis.R"))

This is probably a better solution as it doesn't rely on knitr options. Alternatively you can set the root.dir chunk using rprojroot:

opts_knit$set(root.dir = rprojroot::find_rstudio_root_file())

provided you are using an RStudio project. If not, use rprojroot::find_root with a specified criterion.

ruaridhw
  • 2,305
  • 8
  • 22
  • Thanks! I was just going to answer myself. Actually, I tried the `here()` function and it worked *sometimes*. I don't know what happened, but somehow `.Rmd` only sometimes accepts the `here` function. I'm not sure, what changed between the tests, I would say nothing. A more stable solution for me was the `find_rstudio_root_file()` function of the `rprojroot` package which I put in a small wrapper myself. To set a static path in `opts_knit$set(root.dir = "...") would be suboptimal imo. But I will try the above mentioned option. – bamphe Feb 09 '18 at 11:54
  • This could be due to `here` relying on loading the package to setup its environment variables. I've revised the answer as `rprojroot` is perhaps more stable within a `knitr` setting. – ruaridhw Feb 09 '18 at 12:33
  • Ok, now I got it! My problem with `here()` was totally unrelated to `knitr`. It is just that I also loaded the `lubridate` package which has a deprecated function of the same name. Of course, it couldn't work that way... So I take everything back about it being less stable for me! – bamphe Feb 09 '18 at 12:38
  • For people potentially interested in this: According to [this post](https://stackoverflow.com/questions/5564564/r-2-functions-with-the-same-name-in-2-different-packages) I just put `here = here::here` at the top of my documents (which need sourcing)... this way it is shorter than always using `find_rstudio_root_file()` and it prevents conflicts with `lubridate`. – bamphe Feb 09 '18 at 12:53
  • Small comment that might help someone, because I missed it for a while: if using the `opts_knit` solution, bear in mind the working directory change doesn't take effect until the _next_ chunk - sourcing still won't work if it's in the same chunk. – Serenthia Mar 15 '22 at 11:12