I'm maintaining R code in my company that is use by multiple colleagues. I decided to convert my code into a package to make it simpler to share, maintain and document. My package is build to stay internal, be used in a close environment and is not going to be on CRAN. I'm using Rstudio and it's going relatively well but I hit a problem when building vignettes.
The problem is that my code makes very specific, long and complex analysis on very big datasets. It's therefore not possible for me to have the vignette built every time I rebuilt the package. Even less having the user do it when using devtools::install_git(build_vignettes = TRUE)
. I've found a solution to this problem in this nice blog (https://ropensci.org/blog/2019/12/08/precompute-vignettes/). Briefly, you add .orig
after your vignettes names .Rmd
so they are not identified as vignette by the build process. Then, when you are ready, you precompile your script by knitting your .Rmd.orig
file with:
knitr::knit("vignettes/longexample.Rmd.orig", output = "vignettes/longexample.Rmd")
This will create a quick and easy compilable version of your vignette for your package. This works for basic document with text and figures. However, I need to enter a leaflet map into my vignette. If I use this process to create my vignette with a leaflet, I get an error:
## PhantomJS not found. You can install it with webshot::install_phantomjs(). If it is installed, please make sure the phantomjs executable can be found via the PATH variable.
## PhantomJS not found. You can install it with webshot::install_phantomjs(). If it is installed, please make sure the phantomjs executable can be found via the PATH variable.
## Error in path.expand(path): invalid 'path' argument
I think this is a message showing that knitr is trying to get a screenshot of my map to save it as an image. This is not what I want, I want an actual map.
The vignette I wrote:
---
title: "Example"
author: "BastienFR"
date: "09/05/2022"
output: html_document
---
```{r setup, message=F, warning=FALSE}
library(leaflet)
```
## Intro
A simple and slow example of vignette with a `leaflet`
## The slow part
```{r}
time <- 2
Sys.sleep(time)
message("I've waited this long!")
```
## The leaflet
```{r}
m <- leaflet() %>%
addTiles() %>% # Add default OpenStreetMap map tiles
addMarkers(lng=174.768, lat=-36.852, popup="The birthplace of R")
```
```{r}
m
```
Then, I compile it with :
knitr::knit("c://temp//longexample.Rmd.orig", output = "c://temp//longexample.Rmd")
which produce this output:
---
title: "Example"
author: "BastienFR"
date: "09/05/2022"
output: html_document
---
```r
library(leaflet)
```
## Intro
A simple and slow example of vignette with a `leaflet`
## The slow part
```r
time <- 2
Sys.sleep(time)
message("I've waited this long!")
```
```
## I've waited this long!
```
## The leaflet
```r
m <- leaflet() %>%
addTiles() %>% # Add default OpenStreetMap map tiles
addMarkers(lng=174.768, lat=-36.852, popup="The birthplace of R")
```
```{r}
m
```
```
## PhantomJS not found. You can install it with webshot::install_phantomjs(). If it is installed, please make sure the phantomjs executable can be found via the PATH variable.
## PhantomJS not found. You can install it with webshot::install_phantomjs(). If it is installed, please make sure the phantomjs executable can be found via the PATH variable.
```
```
## Error in path.expand(path): invalid 'path' argument
```
So, it's not able to pass along the leaflet into the new knit markdown file (which makes sense).
I tried to bypass this problem by saving the leaflet into a temporary file like this (in my .orig
file):
```{r, include=FALSE}
saveRDS(m, "c://temp/temp_leaflet.rds")
```
This would save my map, but then I have to find a way to add the next code block in the compiled version, so it appears and it's run only there. Some way to have the code block below passed as-is by knitr.
```{r, include=FALSE}
m <- readRDS("c://temp/temp_leaflet.rds")
```
So I'm stuck. Any idea how to display a leaflet into a markdown/vignette after a precompilation?
This problem can be fix by having knitr knit "asis" the lines of code you want to knit in the second run, so when building the vignette... To do this, you can change the section:
```{r}
m
```
by:
```{r, echo=FALSE}
saveRDS(m, "c://temp/temp_leaflet.rds")
```
```{r, eval=T, results="asis", echo=FALSE}
cat("```{r, echo=FALSE, warning=FALSE} \n")
cat("library(leaflet) \n")
cat("m <- readRDS('c://temp/temp_leaflet.rds') \n")
cat("```")
```
```{r, eval=T, results="asis", echo=FALSE}
cat("```{r, echo=TRUE} \n")
cat("m \n")
cat("```")
```
First, you save your map (or data) somewhere in an rds file. Then, you use the results="asis"
code block option and the cat
function to write the code block that you need rendered only the in the second compilation (when the vignettes are build). So you are actually wrapping Rmarkdown code into Rmarkdown... It's ugly and confusing, but it works. Using this approach, the render code after knitting the Rmd.orig
file looks like normal Rmarkdown code:
```{r, echo=FALSE, warning=FALSE}
library(leaflet)
m <- readRDS('c://temp/temp_leaflet.rds')
```
```{r, echo=TRUE}
m
```
It will then be perfectly render in your vignettes.
The only complication now is to manage the save and read location of the rds
file because markdown and vignettes can have tricky working directories.
So the final .orig
file is now:
---
title: "Example"
author: "BastienFR"
date: "09/05/2022"
output: html_document
---
```{r setup, message=F, warning=FALSE}
library(leaflet)
```
## Intro
A simple and slow example of vignette with a `leaflet`
## The slow part
```{r}
time <- 2
Sys.sleep(time)
message("I've waited this long!")
```
## The leaflet
```{r}
m <- leaflet() %>%
addTiles() %>% # Add default OpenStreetMap map tiles
addMarkers(lng=174.768, lat=-36.852, popup="The birthplace of R")
```
```{r, echo=FALSE}
saveRDS(m, "c://temp/temp_leaflet.rds")
```
```{r, eval=T, results="asis", echo=FALSE}
cat("```{r, echo=FALSE, warning=FALSE} \n")
cat("library(leaflet) \n")
cat("m <- readRDS('c://temp/temp_leaflet.rds') \n")
cat("```")
```
```{r, eval=T, results="asis", echo=FALSE}
cat("```{r, echo=TRUE} \n")
cat("m \n")
cat("```")
```