Suppose i have a main R-Markdown file called index.Rmd and another R-Markdown file called child.Rmd. If i want to include the R-Markdown file child.Rmd based on the condition params$value1 > params$value2, i can add the following code to the file index.Rmd
condition <- params$value1 > params$value2
filepathToChild <- "/home/user/child.Rmd"
```{r conditional_print,
child=filepathToChild , eval = condition
}
```
Using bookdown, i can create a file called _bookdown.yml with the following content to include the content of the file child.Rmd after the content of the file index.Rmd:
rmd_files: ["index.Rmd", "child.Rmd"]
How can i include the content of the file child.Rmd in bookdown based on the condition params$value1 > params$value2?
I can't think of a solution to do it in yml, but you could create that yml-file programmatically and combine it with the rendering process.
Just create a simple script to generate the .yml-file and do the rendering:
# compile_my_book.R
# get the parameters
param1 <- commandArgs(trailingOnly = TRUE)[1]
param2 <- commandArgs(trailingOnly = TRUE)[2]
# just some dummy yml from bookdown examples
my_yml <- paste0(
"book_filename: 'my-book.Rmd'
before_chapter_script: ['script1.R', 'script2.R']
output_dir: 'book-output'
clean: ['my-book.bbl', 'R-packages.bib']"
)
# list the files
# (here you could also use list.files to get them automatically, sorting them etc.)
my_files <- c("chapter01.Rmd", "chapter02.Rmd", "References.Rmd")
# add your conditional files
if (param1 > param2) my_files <- c(my_files, "conditional.Rmd")
# create the _bookdown.yml
cat(my_yml,
"\nrmd_files: ['", paste0(my_files, collapse = "', '"), "']",
file = "_bookdown.yml", sep = "")
# render your book with the arguments you want (excluding the values you want to check for)
bookdown::render_book('index.Rmd', 'bookdown::gitbook')
Then you could compile the book from command line:
Rscript compile_my_book.R value1 value2
(or create a makefile or something similar to run multiple things for you)
So running Rscript compile_my_book.R 1 2 does not add the conditional files, but Rscript compile_my_book.R 2 1 does it.
It's a bit hacky, but I'm using similar workflows to create long .xml-config files for some web apps I use, by reading in data from several sources, checking some conditions and creating the config file.
Another way is simply to put all your chapter's code in another Rmd(child2.Rmd), to call it in child.Rmd and to add an eval condition :
```{r, child= 'child.Rmd',eval=params$value1 > params$value2}
```
And you change nothing to your yml.
Related
I have two files and am using R's diffobj to create an HTML difference file between them.
When I run the RScript in RStudio all is well and I get a diff HTML file like:
When I run the script from the command line, the HTML diff file looks like:
How do I run the R Script from the command line and get the nice HTML formatting?
R Script and Text Files
Original Text File - file_name_original
Hello there I am a file
I have three lines
And no fourth line
Changed Text File - file_name_changed
Hello there I am a file
I have three lines but I am a little longer than usual
And no fourth line
R Script
library("diffobj")
file_name_diff <- "diff.html"
file_name_original <- # Path to original file
file_name_changed <- # Path to changed file
# Compare files
diff_content <- diffFile(current = file_name_original,
target = file_name_changed,
mode = "sidebyside",
format = "html")
writeLines(as.character(diff_content), file_name_diff)
By default diffFile() behaves differently depending on if R is in interactive mode or not so you need to use the argument interactive = TRUE to get the same result as you would from the console.
Using the function example from the documentation:
library("diffobj")
file_name_diff <- "C:\\Path\\to\\file\\diff.html"
url.base <- "https://raw.githubusercontent.com/wch/r-source"
f1 <- file.path(url.base, "29f013d1570e1df5dc047fb7ee304ff57c99ea68/README")
f2 <- file.path(url.base, "daf0b5f6c728bd3dbcd0a3c976a7be9beee731d9/README")
res <- diffFile(f1,
f2,
mode = "sidebyside",
format = "html",
interactive = TRUE)
writeLines(as.character(res), file_name_diff)
I saw someone ask a similar question to this but did not have a conclusive answer... I am trying to knit an rmd file to html and am using a function that I wrote in a .R file. I get an error saying the function can not be found etc.
Also just a note that when I run the chunk of code that the function is called for, it works. Just an error when knitting.
This is because you're using the knit button in Rstudio which creates a new session then executes rmarkdown::render, in order to use locally defined function you have to call rmarkdown::render from the console.
Note: that this will block the console until the .Rmd file is rendered.
my.envir <- new.env(parent=baseenv())
local({
f <- function() { ... }
#...
}, my.envir)
# OR source your file directly into my.envir
source("ur.file.R", local = my.envir)
rmarkdown::render(input, # path to the .Rmd file
output_format = "html_document", # output type if not set it'll use the first one found in the yaml header
output_file = NULL, # name of the output file by default it will be the
# name of the .Rmd with the extension changed
clean = TRUE, # set to FALSE if you want to keep intermediary files
envir = my.envir, # this where the magic happens
# if you don't want to modify the global env you can create your own environment and add the function to it
quiet = FALSE # set to TRUE if you want to suppress the output
)
EDIT following #KonardRudolph's comments:
It's better to source your file into the rmd itself, as the main goal of Rmarkdown is reproducible research.
```{r setup, include=FALSE}
.
.
.
source("path/to/file.R")
```
I'm writing a personal use package which trains/tests models, and finally runs a myriad of LIME and DALEX explanations on them. I save these as their own ggplot2 objects (say lime_plot_1), and at the end of the function these are all returned to the global environment.
However, what I would like to have happen is that, at the end of the function, not only would I have these graphs in the environment but a small html report would also be rendered - containing all the graphs that were made.
I would like to point out that while I do know I could do this by simply using the function within an Rmarkdown or Rnotebook, I would like to avoid that as I plan on using it as an .R script to streamline the whole process (since I'll be running this with a certain frequency), and from my experience running big chunks in .Rmd tends to crash R.
Ideally, I'd have something like this:
s_plot <- function(...){
1. constructs LIME explanations
2. constructs DALEX explanations
3. saves explanations as ggplot2 objects, and list them under graphs_list
4. render graphs_list as an html file
}
1, 2, and 3 all work but I haven't found a way to tackle 4. that doesn't include doing the whole process in a .Rmd file.
EDIT: Thanks to #Richard Telford's and #Axeman's comments, I figured it out. Below is the function:
s_render <- function(graphs_list = graphs_list, meta = NULL, cacheable = NA){
currentDate <- Sys.Date()
rmd_file <- paste("/path/to/folder",currentDate,"/report.Rmd", sep="")
file.create(rmd_file)
graphs_list <- c(roc_plot, prc_plot, mp_boxplot, vi_plot, corr_plot)
c(Yaml file headers here, just like in a regular .Rmd) %>% write_lines(rmd_file)
rmarkdown::render(rmd_file,
params = list(
output_file = html_document(),
output_dir = rmd_file))}
First, create a simple Rmarkdown file, that takes a parameter. The only objective of this file is to create the report. You can for instance pass a file name:
---
title: "test"
author: "Axeman"
date: "24/06/2019"
output: html_document
params:
file: 'test.RDS'
---
```{r}
plot_list <- readRDS(params$file)
lapply(plot_list, print)
```
I saved this as test.Rmd.
Then in your main script, write the plot list to a temporary file on disk, and pass the file name to your markdown report:
library(ggplot2)
plot_list <- list(
qplot(1:10, 1:10),
qplot(1:10)
)
file <- tempfile()
saveRDS(plot_list, file)
rmarkdown::render('test.Rmd', params = list(file = file))
An .html file with the plots is now on your disk:
I teach a lab and I have my students write their answers in .Rmd files. For grading, I download and render them as pdfs in a batch. I use the following script to render everything and save in a file.
library(rmarkdown)
# Handy functions for concatenating strings because I want to do it like a Python
# programmer damnit!
`%s%` <- function(x,y) {paste(x,y)}
`%s0%` <- function(x,y) {paste0(x,y)}
# You should set the working directory to the one where the assignments are
# located. Also, make sure ONLY .rmd files are there; anything else may cause
# a problem.
subs <- list.files(getwd()) # Get list of files in working directory
errorfiles <- c() # A vector for names of files that produced errors
for (f in subs) {
print(f)
tryCatch({
# Try to turn the document into a PDF file and save in a pdfs subdirectory
# (you don't need to make the subdirectory; it will be created automatically
# if it does not exist).
render(f, pdf_document(), output_dir = getwd() %s0% "/pdfs")
},
# If an error happens, complain, then save the name in errorfiles
error = function(c) {
warning("File" %s% "did not render!")
warning(c)
errorfiles <- c(errorfiles, f)
})
}
This last assignment I forgot to set error=TRUE in the chunks, so documents will fail to compile if errors are found and I will have to go hunt those errors down and fix them. I tried to modify this code so that I set the parameter error=TRUE as default outside the document. Unfortunately, I've been working at this for hours and have found no way to do so.
How can I change this code so I can change this parameter outside the documents? (Bear in mind that I don't own the computer so I cannot install anything, but the packages knitr and rmarkdown are installed.)
I'm trying to write a report using the rmarkdown package and as it is, unfortunately, customary in my field reports are often submitted as MS Word documents. So I can't always rely on the power of LaTeX and have to be able convert my .Rmd to MS Word. Now, because I want to be able to create PDF and MS Word files from the same source file, I'm trying to find a general way to do this. I've got PDF working using the apa6 LaTeX-document class. The .Rmd will look something like this when creating a Word file:
---
title: My title
abstract: This is the abstract.
author: John Doe
affiliation: Unknown
note: Nothing to say.
output:
word_document:
reference_docx: myreference.docx
---
Lorem ipsum.
I can create a Word document from this but for obvious reasons my custom yaml-variables (e.g. abstract) will not be rendered in the document.
So basically, my problem is the following:
When creating a word document, how can I add a title page (including author names, affiliations, author notes, etc.) and another page with just the abstract before the document body ("Lorem ipsum")? The focus here is not to create pagebreaks (there are other open questions on this), but rather **is there a way to make pandoc use the custom yaml variables place them at the beginning of the document and assign styles to them?
The rmarkdown package provides an include() function but it only works with HTML and PDF documents.
I have found that it's possible to customize the content of the Markdown file (e.g. to add and modify a title page) generated by rmarkdown before submitting it to pandoc for the conversion to DOCX by using a preprocessor. Let's assume we are trying to add some information specified in a YAML parameter note just before the abstract (support for abstracts has in the meantime been added to pandoc).
To do so, we first need a preprocessor function that reads the input file and parses the YAML front matter, and customizes the input file:
my_pre_processor <- function(metadata, input_file, runtime, knit_meta, files_dir, output_dir, from) {
# Identify YAML front matter delimiters
input_text <- readLines(input_file, encoding = "UTF-8")
yaml_delimiters <- grep("^(---|\\.\\.\\.)\\s*$", input_text)
if(length(yaml_delimiters) >= 2 &&
(yaml_delimiters[2] - yaml_delimiters[1] > 1) &&
grepl("^---\\s*$", input_text[yaml_delimiters[1]])) {
yaml_params <- yaml::yaml.load(paste(input_text[(yaml_delimiters[1] + 1):(yaml_delimiters[2] - 1)], collapse = "\n"))
} else yaml_params <- NULL
# Modify title page
custom_lines <- c(
"NOTE:"
, metadata$note
, "\n\n"
, "# Abstract"
, "\n"
, metadata$abstract
, "\n"
)
## Add modified title page components after YAML front matter
augmented_input_text <- c(custom_lines, input_text[(yaml_delimiters[2] + 1):length(input_text)])
# Remove redundant default abstract
yaml_params$abstract <- NULL
# Add modifications to input file
augmented_input_text <- c("---", yaml::as.yaml(yaml_params), "---", augmented_input_text)
input_file_connection <- file(input_file, encoding = "UTF-8")
writeLines(augmented_input_text, input_file_connection)
close(input_file_connection)
NULL
}
Now we need to define a custom format that utilizes our preprocessor:
my_word_document <- function(...) {
config <- rmarkdown::word_document(...)
# Preprocessor functions are adaptations from the RMarkdown package
# (https://github.com/rstudio/rmarkdown/blob/master/R/pdf_document.R)
pre_processor <- function(metadata, input_file, runtime, knit_meta, files_dir, output_dir, from = .from) {
# save files dir (for generating intermediates)
saved_files_dir <<- files_dir
args <- my_pre_processor(metadata, input_file, runtime, knit_meta, files_dir, output_dir, from)
args
}
config$pre_processor <- pre_processor
config
}
Now, you can use the custom format when rendering R Markdown documents as follows:
rmarkdown::render("./foo/bar.Rmd", output_format = my_word_document())