I am very new to Knitr and I am trying to do the following in a R markdown file.
I have a set of names, for each name I make two plots. I need to get a HTML file for each name, containing the respective plots.
{r, echo=FALSE}
for name in setofNames{
barplot(xx)
barplot(yy)
}
I am quite lost on how to do this. Does any one have any ideas?
EDIT:
I am able to generate different HTML files now for each name, using stitch(). However, I don't get all the plots, the code I've retains only the last iteration. I've also explored the opts_chunk() feature, but in vain. It probably has something to clear the cache with, but I am not sure.
Below is the piece of code:
for name in setofNames{
opts_chunk$set(echo=FALSE, fig.keep='all', fig.show='asis')
fname=paste(name,".html")
stitch_rhtml("../testSub.r",output=fname,envir=globalenv())
}
===testSub.r file===
barplot(xx)
barplot(yy)
Would appreciate some inputs.
You could use the par function to get what you need. Also, I usually remove the "echo=FALSE" because it messes up my knitted html.
http://www.statmethods.net/advgraphs/layout.html.
Here is an example of text that gets entered together for the knitr:
```{r}
df<- replicate(100, runif(n=20))
par(mfrow=c(2,3))
for (i in 2:7) hist(df[,i],main=colnames(df)[i])
```
Let me know if you need more specific help and I'll edit this post.
One solution is to use a "control" file that calls knitr several times (once per name). Each time knitr processes the same Rmd-template but with different data.
In the code below I exploited the fact that knitr by default uses the objects in the calling environment (see ?knit: envir = parent.frame()). Hence it is possible to modify an object in the "control" file and a subsequent call of knitr will use that object when processing the template.
(Of course, global variables could be avoided. Then, the control file would need to assign objects in a specific environment and pass this environment to knitr.)
The "control" file (control.R) could look like this:
library(knitr)
## Generate data
set.seed(1)
n <- 1000
dat <- data.frame(
name = sample(x = LETTERS, size = n, replace = TRUE),
value = rnorm(n))
## knit the template once per "name"
lapply(X = levels(dat$name), FUN = function(name) {
currentSubset <- dat[dat$name == name, ]
knit2html(input = "template.Rmd", output = sprintf("output_%s.html", name))
})
template.Rmd:
```{r}
op <- par(mfrow = c(1, 2))
plot(currentSubset$value, col = "green", main = name)
plot(currentSubset$value, col = "red", main = name)
par(op)
```
This generates a separate HTML file (output_[Letter].html) for each letter in levels(dat$name).
Note that each call to knit2html overrides the plots in the figure directory. However, this does not matter because the HTML files do not reference external figures but contain the figures in data URIs. This is due to markdown::markdownToHTML() which is called from knitr::knit2html():
Any local images linked using the <img> tag will be base64 encoded and included in the output HTML.
(Source: markdownToHTML)
Related
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'm attempting to make my code more modular: data loading and cleaning in one script, analysis in another, etc. If I were using R scripts, this would be a simple matter of calling source on data_setup.R inside analysis.R, but I'd like to document the decisions I'm making in an Rmarkdown document for both data setup and analysis. So I'm trying to write some sort of source_rmd function that will allow me to source the code from data_setup.Rmd into analysis.Rmd.
What I've tried so far:
The answer to How to source R Markdown file like `source('myfile.r')`? doesn't work if there are any repeated chunk names (a problem since the chunk named setup has special behavior in Rstudio's notebook handling). How to combine two RMarkdown (.Rmd) files into a single output? wants to combine entire documents, not just the code from one, and also requires unique chunk names. I've tried using knit_expand as recommended in Generate Dynamic R Markdown Blocks, but I have to name chunks with variables in double curly-braces, and I'd really like a way to make this easy for my colaborators to use as well. And using knit_child as recommended in How to nest knit calls to fix duplicate chunk label errors? still gives me duplicate label errors.
After some further searching, I've found a solution. There is a package option in knitr that can be set to change the behavior for handling duplicate chunks, appending a number after their label rather than failing with an error. See https://github.com/yihui/knitr/issues/957.
To set this option, use options(knitr.duplicate.label = 'allow').
For the sake of completeness, the full code for the function I've written is
source_rmd <- function(file, local = FALSE, ...){
options(knitr.duplicate.label = 'allow')
tempR <- tempfile(tmpdir = ".", fileext = ".R")
on.exit(unlink(tempR))
knitr::purl(file, output=tempR, quiet = TRUE)
envir <- globalenv()
source(tempR, local = envir, ...)
}
I need to produce a report that is composed of several sections, all sections look similar, with only some differences in data. The number of sections is also dependent on the data. What I ultimately want to have is something like this:
```{r}
section_names = c("A","B","C")
section_data = c(13,14,16)
```
# some looping mechanism here with variable i
This is section `r section_names[i]`
This section's data is `r section_data[i]`
#more things go here for the section
#end of loop should go here
The result should be a single html/document with all the sections one after the other.
Can you point me to a way for producing such an Rmd file with the loop?
Ideally I would have hoped to see something like in PHP:
<$php for(i=0;i<10;i++) { ?>
## some html template + code chunks here
<$php } ?>
This question is similar to that one, although it is LateX/RNW based. Besides, this answer demonstrates how to generate a rmarkdown document dynamically. However, neither of the questions is a exact duplicate of this one.
Basically, there are two mental steps to take:
Figure out the markdown markup needed per section. This could be something along the lines of
## This is section <section_name>
Section data is `<section_data>`.
Additional section text is: <section_text>.
Write R code that generates this markup, replacing the placeholders with the appropriate values.
For step 2, using sprintf is a natural candidate to combine static and dynamic text. Don't forget to use the chunk options results = "asis" to prevent knitr from adding formatting to your output and use cat (instead of print) to prevent R from adding additional stuff like quotes and element numbers.
I changed the input data structure a little bit for the sake of clarity (using a data.frame instead of independent vectors section_names and section_data).
```{r echo = FALSE, results = "asis"}
input <- data.frame(
name = LETTERS[1:4],
data = runif(n = 4),
text = replicate(4, paste(sample(x = LETTERS, size = 100, replace = TRUE), collapse = "")),
stringsAsFactors = FALSE)
template <- "## This is section %s
Section data is `%0.2f`.
Additional section text is: %s.
" # dont't forget the newline
for (i in seq(nrow(input))) {
current <- input[i, ]
cat(sprintf(template, current$name, current$data, current$text))
}
```
Output:
This is section A
Section data is 0.83.
Additional section text is: PUFTZQFCYJFNENMAAUDPTWIKLBSVKWMJWODFHSPRJRROTVDGNEROBVQPLLMVNPOUUHGVGRPMKAOAOMVYXKMGMUHNYWZGPRAWPYLU.
This is section B
Section data is 0.49.
Additional section text is: PFTYCGFSGSMAYSSCZXWLNLDOQEBJYEVSJIYDJPEPSWQBNWJVRUKBTYIUSTOICFKJFEJCWCAYBCQSRTXUDEQLLXCZNPUKNLJIQJXE.
This is section C
Section data is 0.58.
Additional section text is: FCJDDDMNLBUSJMCZVSBPYWCKSFJEARBXXFPAGBTKCWKHPEDGYWYTNGLVGQGJAFZRUMNSDCHKTTMGRFNSUZKFLOUGNWHUBNLVMGDB.
This is section D
Section data is 0.52.
Additional section text is: YQIXHABFVQUAAYZNWTZXJDISSLTZJJAZOLJMJSXEENFTUOFOTYKDNNUMFDXLJSWZEVDLCLSYCTSMEXFLBVQYRTBEVZLCTEBPUGTT.
Just sharing the approach I've used eventually.
I wrote a markdown file for the section. prepared the data for each section in the master document, and looped over all the sections I needed, each time calling to knit_child() with the section Rmd.
I know this is late, but I used this in my code to make numbered sections and it works a treat.
for (k in 1:length(listcsv)){ #Begin Loop at pdf file one and continue until all have been completed
subsection <- paste("5", k, sep = ".")}
this uses the loop number (k) to create the subsection number and then paste it against the section number. This happens to be in section 5, but you could use the same principle to make sections and subsections ad infinitum.
For teaching purposes, I would like to purl the chunks of my .Rnw file into separate files. This answer explains how to do it:
How to purl each chunks in .Rmd file to multiple .R files using Knitr
BUT the method does not preserve the chunk options. Since the chunks I have produce plots, it's important to preserve the fig.width and fig.height options. Ideally I would like a chunk that looks like this:
<<plot, fig.width = 3, fig.height = 5, outwidth = '.75\\textwidth'>>=
plot (1,1)
#
to become a file named plot.R that looks like this:
#+ fig.width = 3, fig.height = 5
plot (1,1)
That is, turn the chunk options fig.width and fig.height into a format that will be recognized by spin(), as purl() does, and get rid of the chunk options that are irrelevant, or create problems for spin() into Word, such as out.width. All in the spirit of creating code files that are user-friendly.
Since the answer you refer to doesn't copy the header line from the results of purl, you lose everything besides the chunk name. While you could adapt it to paste in the headers, it's actually not hard to build a function to parse the output of purl—much easier than trying to parse a Rmd or Rnw document, anyway, and easier than sorting out exactly how knitr does so.
purl_chunks <- function(input_file){
purled <- knitr::purl(input_file) # purl original file; save name to variable
lines <- readLines(purled) # read purled file into a character vector of lines
starts <- grep('^## ----.*-+', lines) # use grep to find header row indices
stops <- c(starts[-1] - 1L, length(lines)) # end row indices
# extract chunk names from headers
names <- sub('^## ----([^-]([^,=]*[^,=-])*)[,-][^=].*', '\\1', lines[starts])
names <- ifelse(names == lines[starts], '', paste0('_', names)) # clean if no chunk name
# make nice file names with chunk number and name (if exists)
file_names <- paste0('chunk_', seq_along(starts), names, '.R')
for(chunk in seq_along(starts)){ # loop over header rows
# save the lines in the chunk to a file
writeLines(lines[starts[chunk]:stops[chunk]], con = file_names[chunk])
}
unlink(purled) # delete purled file of entire document
}
A couple notes:
While the regex works for what I've thrown at it, it may yet be fallible. Tested:
no chunk name
no name but chunk settings
name with hyphens
single character names
names with spaces, including after (before the comma/brace)
As .Rnw and .Rmd files both purl the same, it works for either.
It uses the default setting (1L) for purl's documentation parameter. 0L wouldn't have chunk headers and is thus pointless here anyway, but it would handle 2L (which would include text chunks as roxygen comments) stupidly. It could be rebuilt for such, though, if you wanted text chunks with the following code chunk.
While the output header lines of purl don't look exactly like your example above (they start with ## ---- and are filled with hyphens), they spin properly; results obey chunk options.
I am using tableNominal{reporttools} to produce frequency tables. The way I understand it, tableNominal() produces latex code which has to be copied and pasted onto a text file and then saved as .tex. But is it possible to simple export the table produced as can be done in print(xtable(table), file="path/outfile.tex"))?
You may be able to use either latex or latexTranslate from the "Hmisc" package for this purpose. If you have the necessary program infrastructure the output gets sent to your TeX engine. (You may be able to improve the level of our answers by adding specific examples.)
Looks like that function does not return a character vector, so you need to use a strategy to capture the output from cat(). Using the example in the help page:
capture.output( TN <- tableNominal(vars = vars, weights = weights, group = group,
cap = "Table of nominal variables.", lab = "tab: nominal") ,
file="outfile.tex")