Split Rmarkdown (.Rmd) file into mutiple files (.Rmd) - r

I made a big Rmarkdown (.Rmd) file that contains only chunks of R codes. I'm wondering if there's a way to automatically generate a (.Rmd) file for every chunk or if I have to manually create a (.Rmd) file for every chunk I have (over 200 chunks).
Let's say I have this (.Rmd) file :
---
title: "Untitled"
output: html_document
date: '2022-08-13'
---
R Markdown
``{r cars}
summary(cars)
``
Including Plots
``{r pressure, echo=FALSE}
plot(pressure)
``
Is there a way to generate automatically a (.Rmd) file for the chuck r cars and another for the chunk r pressure?
Thanks in advance.

A possible solution is to use package parsemd:
library(parsermd)
rmd <- parse_rmd("x.Rmd")
rlabels <- c("cars", "pressure")
yaml <- rmd_select(rmd, has_type("rmd_yaml_list"))
for (i in rlabels)
{
rchunk <- rmd_select(rmd, all_of(i))
sink(paste0(i, ".Rmd"))
cat(as_document(yaml), sep = "\n")
cat(as_document(rchunk), sep = "\n")
sink()
}

Related

How to extract all code from an RMarkdown (.Rmd) file?

How can I extract all the code (chunks) from an RMarkdown (.Rmd) file and dump them into a plain R script?
Basically I wanted to do the complementary operation described in this question, which uses chunk options to pull out just the text (i.e. non-code) portion of the Rmd.
So concretely I would want to go from an Rmd file like the following
---
title: "My RMarkdown Report"
author: "John Appleseed"
date: "19/02/2022"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents.
For more details on using R Markdown see <http://rmarkdown.rstudio.com>.
Some text description here.
```{r cars}
a = 1
print(a)
summary(cars)
```
## Including Plots
You can also embed plots, for example:
```{r pressure, echo=FALSE}
plot(pressure)
```
Some more comments here.
To an R script containing just the code portions of the above, as the following:
knitr::opts_chunk$set(echo = TRUE)
a = 1
print(a)
summary(cars)
plot(pressure)
You could use knitr::purl, see convert Markdown to R script :
knitr::purl(input = "Report.Rmd", output = "Report.R",documentation = 0)
gives Report.R:
knitr::opts_chunk$set(echo = TRUE)
a = 1
print(a)
summary(cars)
plot(pressure)
Another way is to set the purl hook in your Rmd:
```{r setup, include=FALSE}
knitr::knit_hooks$set(purl = knitr::hook_purl)
knitr::opts_chunk$set(echo = TRUE)
```
Then the R script is generated when you knit. You can exclude some chunks with the chunk option purl = FALSE.

Looping Flextables in R Markdown documents with Word output

I am looking to print multiple flextables in a single R Markdown document. This is not challenging when using html output, but I need Word output.
With html output, the following R Markdown code (example taken from https://davidgohel.github.io/flextable/articles/offcran/examples.html#looping-in-r-mardown-documents) produces a document with multiple Flextables:
---
output:
html_document: default
---
```{r}
library(htmltools)
library(flextable)
ft <- flextable(head(iris))
tab_list <- list()
for(i in 1:3){
tab_list[[i]] <- tagList(
tags$h6(paste0("iteration ", i)),
htmltools_value(ft)
)
}
tagList(tab_list)
```
I have been unable to get an equivalent output using Word document output.
The solution proposed in
How to knit_print flextable with loop in a rmd file similarly works fine with html output, but I have failed to get this to render correctly with Word output.
Any advice on a R Markdown Word document output equivalent of the above example would be very helpful!
You need to use flextable::docx_value and the chunk option results='asis'
---
title: "Untitled"
output: word_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(flextable)
```
```{r results='asis'}
ft <- flextable(head(iris))
for(i in 1:3){
cat("<w:p/>")## add this to add an empty new paragraph between tables
flextable::docx_value(ft)
}
```

How to generate rmarkdown chunk within a chunk

I'm trying to generate a rmarkdown chunk using code. I've read similar questions and their solutions, such as using pander or using cat. I just can't seem to generate it. I also tried knitting the output manually. Here's an example of a Rmd file:
---
title: "test"
output: pdf_document
---
## R Markdown
```{r, results='asis',echo=FALSE}
txt <- paste("```{r}",
"2+2",
"```")
pander::pander(txt)
```
When I knit this, I get a verbatim {r} 2+2. I would like to see the number four instead. In my real example, I'm using bookdown and trying to generate a block2 chunk.
Any ideas how to generate this chunk that gets evaluated as R code?
Does this do what you want?
## R Markdown
```{r, results='asis',echo=FALSE}
txt <- paste("```{r}",
2+2,
"```")
pander::pander(txt)
```
This evalutates to
```{r} 4 ```
in your markdown document.
You using a string literal "2+2" as opposed to the expression 2+2. This is the first issue, I guess.
If you want it correctly parsed you need to add an sep = "\n" argument to paste or manually add the newline breaks.
I.e.
## R Markdown
```{r, results='asis',echo=FALSE}
txt <- paste("```{r}\n",
2+2,
"\n```", sep = "")
pander::pander(txt)
```
This evalutates to
```{r}
4
```
which is interpreted as R code in the markdown document.

RMarkdown render to Notebook with child chunks included

I'm after a way to render an Rmd document (that contains references to various "child" files) to a self-contained R Notebook without these dependencies.
At the moment, the .Rmd code chunks are located throughout a number of .R, .py and .sql files and are referenced in the report using
```{r extraction, include=FALSE, cache=FALSE}
knitr::read_chunk("myscript.R")
```
followed by
```{r chunk_from_myscript}
```
as documented here.
I've done this to avoid code duplication and to allow for running the source files separately however these code chunks are only executable in the report via a call to knit or render (when read_chunk is run and the code chunk is available).
Is there a way to spin-off an Rmd (prior to knitting) with
just these chunks populated?
This function
rmarkdown::render("report.Rmd", clean = FALSE)
almost gets there as it leaves the markdown files behind whilst removing extraction and populating chunk_from_myscript however as these files are straight markdown, the chunks are no longer executable and the chunk options are missing. It obviously also doesn't include chunks where eval=TRUE, echo=FALSE which would be needed to run the resulting notebook.
I've also looked at knitr::spin however this would mean disseminating the contents of the report to every source file and isn't terribly ideal.
Reprex
report.Rmd
---
title: 'Report'
---
```{r read_chunks, include=FALSE, cache=FALSE}
knitr::read_chunk("myscript.R")
```
Some documentation
```{r chunk_from_myscript}
```
Some more documentation
```{r chunk_two_from_myscript, eval=TRUE, echo=FALSE}
```
myscript.R
#' # MyScript
#'
#' This is a valid R source file which is formatted
#' using the `knitr::spin` style comments and code
#' chunks.
#' The file's code can be used in large .Rmd reports by
#' extracting the various chunks using `knitr::read_chunk` or
#' it can be spun into its own small commented .Rmd report
#' using `knitr::spin`
# ---- chunk_from_myscript
sessionInfo()
#' This is the second chunk
# ---- chunk_two_from_myscript
1 + 1
Desired Output
notebook.Rmd
---
title: 'Report'
---
Some documentation
```{r chunk_from_myscript}
sessionInfo()
```
Some more documentation
```{r chunk_two_from_myscript, eval=TRUE, echo=FALSE}
1 + 1
```
Working through your reprex I now better understand the issue you are trying to solve. You can knit into an output.Rmd to merge your report and scripts into a single markdown file.
Instead of using knitr::read_chunk, I've read in with knitr::spin to cat the asis output into another .Rmd file. Also note the params$final flag to allow rendering the final document when set as TRUE or allowing the knit to an intermediate .Rmd as FALSE by default.
report.Rmd
---
title: "Report"
params:
final: false
---
```{r load_chunk, include=FALSE}
chunk <- knitr::spin(text = readLines("myscript.R"), report = FALSE, knit = params$final)
```
Some documentation
```{r print_chunk, results='asis', echo=FALSE}
cat(chunk, sep = "\n")
```
to produce the intermediate file:
rmarkdown::render("report.Rmd", "output.Rmd")
output.Rmd
---
title: "Report"
---
Some documentation
```{r chunk_from_myscript, echo=TRUE}
sessionInfo()
```
With the secondary output.Rmd, you could continue with my original response below to render to html_notebook so that the document may be shared without needing to regenerate but still containing the source R markdown file.
To render the final document from report.Rmd you can use:
rmarkdown::render("report.Rmd", params = list(final = TRUE))
Original response
You need to include additional arguments to your render statement.
rmarkdown::render(
input = "output.Rmd",
output_format = "html_notebook",
output_file = "output.nb.html"
)
When you open the .nb.html file in RStudio the embedded .Rmd will be viewable in the editing pane.
Since neither knitr::knit nor rmarkdown::render seem suited to rendering to R markdown, I've managed to somewhat work around this by dynamically inserting the chunk text into each empty chunk and writing that to a new file:
library(magrittr)
library(stringr)
# Find the line numbers of every empty code chunk
get_empty_chunk_line_nums <- function(file_text){
# Create an Nx2 matrix where the rows correspond
# to code chunks and the columns are start/end line nums
mat <- file_text %>%
grep(pattern = "^```") %>%
matrix(ncol = 2, byrow = TRUE)
# Return the chunk line numbers where the end line number
# immediately follows the starting line (ie. chunk is empty)
empty_chunks <- mat[,1] + 1 == mat[,2]
mat[empty_chunks, 1]
}
# Substitute each empty code chunk with the code from `read_chunk`
replace_chunk_code <- function(this_chunk_num) {
this_chunk <- file_text[this_chunk_num]
# Extract the chunk alias
chunk_name <- stringr::str_match(this_chunk, "^```\\{\\w+ (\\w+)")[2]
# Replace the closing "```" with "<chunk code>\n```"
chunk_code <- paste0(knitr:::knit_code$get(chunk_name), collapse = "\n")
file_text[this_chunk_num + 1] %<>% {paste(chunk_code, ., sep = "\n")}
file_text
}
render_to_rmd <- function(input_file, output_file, source_files) {
lapply(source_files, knitr::read_chunk)
file_text <- readLines(input_file)
empty_chunks <- get_empty_chunk_line_nums(file_text)
for (chunk_num in empty_chunks){
file_text <- replace_chunk_code(file_text, chunk_num)
}
writeLines(file_text, output_file)
}
source_files <- c("myscript.R")
render_to_rmd("report.Rmd", "output.Rmd", source_files)
This has the added benefits of preserving chunk options and working
with Python and SQL chunks too since there is no requirement to evaluate
any chunks in this step.

How to include external R file with RMarkdown? [duplicate]

It's fairly trivial to load external R scripts as per this R Sweave example:
<<external-code, cache=FALSE>>=
read_chunk('foo-bar.R')
#
Can the same be done for R Markdown?
Yes.
Put this at the top of your R Markdown file:
```{r setup, echo=FALSE}
opts_chunk$set(echo = FALSE, cache=FALSE)
read_chunk('../src/your_code.R')
```
Delimit your code with the following hints for knitr (just like #yihui does in the example):
## #knitr part1
plot(c(1,2,3),c(1,2,3))
## #knitr part2
plot(c(1,2,3),c(1,2,3))
In your R Markdown file, you can now have the snippets evaluated in-line:
Title
=====
Foo bar baz...
```{r part1}
```
More foo...
```{r part2}
```

Resources