Reuse r code with knitr in rnw / sweave files - r

I'm searching for a way to reuse r-code in latex using knitr. I have multiple excel documents, that I want to import, analyze and plot in the same way throughout my thesis. Right now I am making a new .rnw file for each excel document that I have. This means, that if I want to change anything, I have to do it in every .rnw file - which seems like the wrong approach. Is there a way, where I can call one .rnw file from the parent .rnw and providing it with an excel filename to import and work with.

Yes there is. You can use both the params and render function to help with this. If you are unfamiliar with parameters look here params and here for render. I wrote iris and mtcars to excel for the examples below. In the markdown below I call the excel parameter in the chunk which is the excel file and just print the first 10 rows.
---
title: "iris"
output: pdf_document
params:
excel: "G:/iris2.xlsx"
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r cars}
head(xlsx::read.xlsx(params$excel,sheetIndex = 1))
```
Now to change the excel file you can use lapply and the render function in a .R file.
#create list of excel files
exldocs <- c("G:/mtcars2.xlsx", "G:/iris2.xlsx")
#call the renders.rmd (above), pass the list of excel files to overwrite the #default param field, output a new pdf (call it whatever you want)
lapply(exldocs, function(x){
rmarkdown::render("G:/renders.Rmd", params = list(excel = x),
output_file =paste0(substr(x,1,nchar(x)-4),"pdf")
)})

You can use knitr::knit and use the envir argument as follows. Here is the .Rnw file
% parameterized_reports.Rnw
\documentclass{article}
\begin{document}
<<>>=
foo
#
\end{document}
Here is the R code
tmp <- environment()
tmp$foo <- "xyz"
knitr::knit("parameterized_reports.Rnw", envir = tmp, output = "output.tex")
tools::texi2pdf("output.tex")
system('open output.pdf')
The result is

Related

Run R markdown (.Rmd) from inside other R script to produce HTML

As the example, if you create a new R markdown file and save it as 'test'. Can one then run or deploy this test.Rmd file from within a normal R script. The purpose being to generate the output in HTML, without having to open the .Rmd file.
I'm hoping to create one master file to do this for many markdown files in one go; which would save considerable time as you then don't have to open many markdown files and wait for each one to complete.
You are looking for rmarkdown::render().
Contents of "test.Rmd"
---
title: "Untitled"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
This is an R Markdown document. 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>.
When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
```{r cars}
summary(cars)
```
Contents of script.R
# provided test.Rmd is in the working directory
rmarkdown::render("test.Rmd")
A Way to Render Multiple Rmd
cwd_rmd_files <- list.files(pattern = ".Rmd$")
lapply(cwd_rmd_files, rmarkdown::render)
Thanks the-mad-statter, your answer was very helpful. The issue I faced, required me to prepare markdown dynamically. By adapting your code, that's easily possible:
Contents of "test_dyn.rmd"
---
title: "Untitled"
output: html_document
---
The chunk below adds formatted text, based on your inputs.
```{r text, echo=FALSE, results="asis"}
cat(text)
```
The chunk below uses your input in as code.
```{r results}
y
```
Contents of "script_dyn.r"
in_text <- c("**Test 1**", "*Test 2*")
in_y <- 1:2
lapply(1:2, function(x) {
text <- in_text[[x]]
y <- in_y[[x]]
rmarkdown::render(input = "test_dyn.rmd", output_file = paste0("test", x))
})
Like this you can create files with different text and different variables values in your code.

Dynamically building RMarkdown

I have a non-fixed List of *.Rmd files and want to dynamically render them into a single html File with RMarkdown.
Like this:
reportFiles <- list()
reportFiles[[1]] <- "F:\\report1.Rmd"
reportFiles[[2]] <- "F:\\report2.Rmd"
outputPath <- "F:\\report.html"
rmarkdown::render(input = reportFiles, output_file = outputPath)
But that doesnt work and i couldnt find a solution on how to do something like this. In all scenarios it either creates multiple files or you have to know what files yuo want to render beforehand or you have to create a temporary *.Rmd file.
One can combine multiple Rmd files into a single output document by modifying the code posted with the question.
First, the documents must be combined into a single Rmd before processing with rmarkdown::render(). Second, all files combined must take account of the following constraints.
Only the first Rmd file can contain document header information
Section labels must be unique across all Rmd files combined into a single Rmd for rendering.
The general approach is to read the files into a character vector, write the vector to a temporary Rmd file, then render the combined document.
library(rmarkdown)
# list of files to be combined
reports <- c("report1.Rmd","report2.Rmd")
# read the files & combine into a single character vector
theReports <- unlist(lapply(reports,readLines))
# use writeLines() to combine into single Rmd
tmpFile <- writeLines(theReports,"tmpReport.Rmd")
# render the combined document
render(input = "tmpReport.Rmd")
When rendered to an HTML document, the output looks like this:
Additional Considerations
We used a character vector instead of a list() to store the file names because the additional complexity of a list() was not needed to drive lapply() in this situation.
Use of a character vector allows the solution to be modified to potentially retrieve a list of files from a subdirectory with list.files(), as in:
reports <- list.files(path="./myReportDir/",
pattern="report[[:digit:]]+.Rmd",full.names=TRUE)
Also, one can segregate the header information into a file that contains only header info, such as report_header.Rmd.
Next, in order to automate retrieval of the files from a directory, one must ensure that the sort order of the file names matches the intended order of inclusion in the output document. H/T to Petr Kajzar for the regular expression to extract only files with a numbered report name from list.files().
Finally, also as suggested by Petr Kajzar in the comments, one can use a truly temporary file to drive rmarkdown::render() as follows.
tmpfile <- tempfile(fileext=".Rmd")
writeLines(theReports,tmpfile)
render(input = tmpfile)
Appendix
To make the example completely reproducible, we include the text of report1.Rmd and report2.Rmd. These files must be copied & saved to a local computer in order for the script above to read, write, and render them.
report1.Rmd
---
title: "report 1"
author: "lg"
date: "7/6/2020"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
This is an R Markdown document. 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>.
When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
```{r cars}
summary(cars)
```
## Including Plots
You can also embed plots, for example:
```{r pressure, echo=FALSE}
plot(pressure)
```
Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.
report2.Rmd
Notice that the content in the second report conforms to the two constraints listed above.
## Report number 2
This is some text for the second markdown document. Considerations to make concatenation of multiple Rmd files into a single output document work:
1. Files 2 thru N must not have Rmd header information
2. Files that are combined into a single Rmd must not have duplicate section labels
```{r cars2}
summary(cars)
```
## Including Plots
You can also embed plots, for example:
```{r pressure2, echo=FALSE}
plot(pressure)
```
Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.

r-exams Questions about the same data on 2 separate xxx.Rmd files

Using R exams, I am developing a pdf exam with several questions (hence several Rmd files) but the questions are connected and would use a dataset created in the first question file. Questions would not be amenable to a cloze format.
Is there a way to write the exercises so that the second exercise can access the data generated by the first exercise ?
The easiest solution is to use a shared environment across the different exercises, in the simplest case the .GlobalEnv. Then you can simply do
exams2pdf(c("ex1.Rmd", "ex2.Rmd"), envir = .GlobalEnv)
and then both exercises will create their variables in the global environment and can re-use existing variables from there. Instead of the .GlobalEnv you can also create myenv <- new.env() and use envir = myenv.
For Rnw (as opposed to Rmd) exercises, it is not necessary to set this option because Sweave() Rnw exercises are always processed in the current environment anyway.
Note that these approaches only work for those exams2xyz() interfaces, where the n-th random draw from each exercise can be assured to end up together in the n-the exam. This is the case for PDF output but not for many of the learning management system outputs (Moodle, Canvas, etc.). See: Sharing a random CSV data set across exercises with exams2moodle()
Is it an option to save the data you need to disk in one Rmd file
```{r, echo=FALSE}
saveRDS(df, "my_stored_data.rds")
```
and then load it in the other one
```{r, echo=FALSE}
readRDS(df, "my_stored_data.rds")
```
Another option could be to knit the Rmd files from an R script and then knit them from this R script. If you do that, the Rmd files use the environment of the R script (!) instead of creating their own. Hence you can use the same objects (and therefore of course let one Rmd script store the data, while the other uses it as input.
In this thread: Create sections through a loop with knitr
there is a post from me about doing this. It's basically this:
The first Rmd file:
---
title: "Script 1"
output: html_document
---
```{r setup, include=FALSE}
a_data_frame_created_in_script_1 <- mtcars
```
saved as rmd_test.Rmd
The second one:
---
title: "Script 1"
output: html_document
---
```{r setup}
a_data_frame_created_in_script_1
```
saved as rmd_test_2.Rmd.
And then you have an R-script that does this:
rmarkdown::render("rmd_test.Rmd", output_file = "rmd_test.html")
rmarkdown::render("rmd_test_2.Rmd", output_file = "rmd_test_2.html")

Show PNG images consecutively with loop in R Markdown chunk (HTML)

Can one use an R Markdown chunk loop to show multiple graphics files (e.g., PNG) consecutively (one above the other) in HTML output? This loop would identify the files in a vector, such as via list.files().
I have experimented with no avail to uses of writeLines("\n"), cat('\r\n\r\n') per this SO.
This R Markdown code (formatted below but link is .Rmd) is a reproducible example with an attempt using writeLines("\n") and cat('\r\n\r\n'). Please note this copies 5 R logo PNG (only 12kb) file copies into your working directory.
---
title: "Stack Overflow Consecutive PNG"
author: "Rick Pack"
date: "11/20/2019"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## Copy a PNG file as multiple files
```{r png_copy, echo=FALSE}
for (q in 1:5) {
file.copy(list.files(system.file("img", package = "png"),
full.names = TRUE),
getwd())
file.rename("Rlogo.png", paste0("Rlogo_",q,".png"))
}
```
# Only one R logo shown instead of the five available
```{r png_show, echo=FALSE}
library(png)
# Providing the folder so you can delete the png files
# created above
print(getwd())
all_img <- list.files(full.names = TRUE)[grepl(
"Rlogo", list.files())]
for (j in 1:length(all_img)) {
grid::grid.raster(readPNG(all_img[j]))
writeLines("\n")
cat('\r\n\r\n')
cat("\n\n\\pagebreak\n")
}
```
You can use R Markdown syntax within the for loop instead of the png package. Given you have the images in the same directory as your Rmd, the following should work:
```{r, results = "asis"}
filelist <- c("Rlogo_1", "Rlogo_2", "Rlogo_3")
for(i in filelist) {
cat(paste0("![](", i, ".png)"), "\n")
cat("\n\n\\pagebreak\n")
}
```
Output:
See this related question for more info: Insert images using knitr::include_graphics in a for loop

Remove Markdown Default Code

In RStudio, whenever I make a new Markdown it always has default code. How do I remove it?
Here's the code that shows up.
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
This is an R Markdown document. 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>.
When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
```{r cars}
summary(cars)
```
## Including Plots
You can also embed plots, for example:
```{r pressure, echo=FALSE}
plot(pressure)
```
Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.
Every time, when creating a Rmd file, Rstudio will open a Rmd template:
https://github.com/rstudio/rstudio/blob/822e558c7a274de464f992f69e3acee2fde5ab04/src/cpp/session/modules/SessionRMarkdown.R
# given a path to a folder on disk, return information about the R Markdown
# template in that folder.
.rs.addFunction("getTemplateDetails", function(path) {
# check for required files
templateYaml <- file.path(path, "template.yaml")
skeletonPath <- file.path(path, "skeleton")
if (!file.exists(templateYaml))
return(NULL)
if (!file.exists(file.path(skeletonPath, "skeleton.Rmd")))
return(NULL)
# load template details from YAML
templateDetails <- yaml::yaml.load_file(templateYaml)
# enforce create_dir if there are multiple files in /skeleton/
if (length(list.files(skeletonPath)) > 1)
templateDetails$create_dir <- TRUE
templateDetails
})
Hence the simplest solution would be:
go to xxx\RStudio\resources\templates folder, where your
Rstudio installed
open r_markdown_v2.Rmd file, and delete
everthing
save it
Now, everytime, when you open a rmarkdown, you can have just the yaml part.

Resources