96 Child Documents

In general, I find that a single R Markdown file quickly becomes unwieldy. I recommend breaking the document up into multiple “child” documents and sourcing these child documents in a parent document. My child documents generally represent major subsections of the document.

I prefer to store the parent R Markdown file in a folder labeled “markdown” (rproject/markdown) and the child R Markdown files in a sub-directory of my “markdown” folder called “sections” (rproject/markdown/sections). In the parent file, the child files are sourced within the code chunk header using child = 'sections/example.Rmd'. After sourcing all the child chunks, the parent file can be knit (compiled) like a normal R markdown document. The child documents cannot be run in the parent file.

96.1 Extract and Run R-Code from R Markdown Files

The parent file is great for organizing sections of your document, but the child documents cannot be executed within R Studio like a normal code chunk. Without the ability to easily execute the R code within the child documents it can become very difficult to develop new child documents because new child documents often depend on upstream code execution.

Imagine you have a parent document that sources child sections which import your data and clean your data. You now want to visualize your data; accordingly, you begin to develop a visualization child document, which depends on information from the upstream child sections. It would be inefficient and inappropriate to perform all the steps in the upstream child sections within the visualization section. Therefore, you need an effective way to execute the upstream child sections while you continue to develop the visualization section. The inefficient way of doing this is to open each child Rmd file in R Studio and execute them manually in the correct sequence. This becomes tedious after you have three or more documents (imagine doing this for 10+ child sections). The most efficient way that I have found to run upstream child sections is to extract the R-code chunks from each Rmd file, save them in a “raw_scripts” folder, and then source/execute the scripts within a regular R script file (.R).

96.1.1 R Code

In this section we establish the file path to the folder that contains all the child documents. The names of the child documents are extracted and stored as a vector. The grepl() function is used to retain only the Rmd files stored in the vector.

sections_path <- file.path(
  rprojroot::find_root("r_in_practice.Rproj"),
  "markdown",
  "sections"
)
r_files_vec <- list.files(sections_path)
r_files_vec <- r_files_vec[grepl(".Rmd", r_files_vec)]

Next, a file path is specified for the R-scripts that will be extracted from the R Markdown documents; I place these files within a “raw_script/extracted” folder. The map() function from the purrr package is used to loop through each file in the vector (r_files_vec). Within the map() loop, the purl() function from knitr is used to extract the R-code from the R Markdown documents and save the code to the specified folder.

extracted_path <- file.path(
  rprojroot::find_root("r_in_practice.Rproj"),
  "markdown",
  "raw_scripts",
  "extracted"
)

purrr::map(r_files_vec, function(file.i) {
  # print(file.i)
  file_name <- gsub(".Rmd", "", file.i)
  extracted_file <- paste0(file_name, ".R")
  knitr::purl(
    file.path(sections_path, file.i),
    file.path(extracted_path, extracted_file)
  )
})

Finally, create a vector of file names (vec_source) stored in the “raw_script/extracted” folder. You will want to type these out manually (do not use list.files() functions) because in this format you can easily comment out certain scripts and only run the scripts of interest. map() is then used to loop through each specified file in vec_source. Keep in mind that the order of the file names specified in vec_source will determine the order that these files are executed in the map() function; therefore, order the files in vec_source from furthest upstream to furthest downstream. Each iteration of the loop, executes (sources) the specified R-script.

vec_source <- c(
  "introduction.R",
  "quick_reference.R",
  "installation_updates.R",
  "r_project.R",
  "version_control.R"
)

purrr::map(vec_source, function(source_i) {
  source(file.path(extracted_path, source_i))
})

Once all the R-scripts extracted from the upstream child R Markdown files have been executed, you can begin or continue work on a new child R Markdown document. I keep all the above code in a single R-script and execute the entire script each time I use this file to make sure all of the files are up-to-date.

96.2 Your Turn

  1. Create an R Markdown document for each of the sections, designated by Header level 1s, we have created thus far.

    • save the documents within your project root (where your .Rproj file lives)
  2. Copy the Header and the relevant content below the header. Paste the content into the appropriate R Markdown document.

  3. Create a parent R Markdown document.

    • create a code chunk for each section.
    • add child = 'insert-file-name-here.Rmd' to the header of the appropriate code chunk
  4. Knit the document