When knitting R-Markdown in RStudio, I would like to all console outputs in one chunk to be placed together in one code block. How can this be done?
As a workaround, I write two code blocks of the same code and set eval=FALSE on the first block and echo=FALSE on the second.
```{r Vector Demo 2, eval=FALSE}
# examine the class and structure of vectors
class(nums)
class(char)
str(nums)
str(char)
```
```{r Vector Demo 2b, echo=FALSE}
# examine the class and structure of vectors
class(nums)
class(char)
str(nums)
str(char)
```
This however produces the following output:
# examine the class and structure of vectors
class(nums)
class(char)
str(nums)
str(char)
## [1] "numeric"
## [1] "character"
## num [1:5] 1 2 3 4 5
## chr [1:3] "A" "B" "C"
What I would like is to have the output of the second chunk (i.e. Vector Demo 2b) to be placed together in one code block just like the first chunk (i.e. Vector Demo 2).
This is a sample output of how I would prefer to have my result:
# examine the class and structure of vectors
class(nums)
class(char)
str(nums)
str(char)
## [1] "numeric"
## [1] "character"
## num [1:5] 1 2 3 4 5
## chr [1:3] "A" "B" "C"
Note to bounty hunters:
Better still, I would be grateful for a way to have one code chunk first print the input code, and then print the output code. That way I could avoid duplication and possible inconsistencies that could come with it.
Here is a solution to your problem. There are two things to do:
## Test
```{r echo = F, cache = F}
knitr::knit_hooks$set(document = function(x){
gsub("```\n*```r*\n*", "", x)
})
```
```{r VectoDemo, results = 'hold'}
nums = 1:5
char = LETTERS[1:5]
# examine the class and structure of vectors
class(nums)
class(char)
str(nums)
str(char)
```
I have done two things here
Set results = 'hold' to "hold" printing of output after source is printed.
Added a document hook to collapse successive code chunks with no text in-between.
With knitr >= 1.5.23
You can get quite a bit of variety from the built-in knitr options.
For instance... get the same results as Ramnath's hook using collapse=TRUE, results="hold" (no global document hook needed).
If you really want distinct source/output parts as shown in the question then you are already on the right path. Just make use of chunk reuse to get the output combo without having to repeat yourself...
```{r}
nums <- 1:5
char <- LETTERS[1:3]
```
```{r "Vector Demo", eval=FALSE}
# examine the class and structure of vectors
class(nums)
class(char)
str(nums)
str(char)
```
```{r "Vector Demo", echo=FALSE}
```
The last chunk is your basic chunk reuse pattern.
You can see a variety of the basic combinations here.
Since you aren't making a knitr tutorial ignore the source and use the rendered examples.
#Ramnath's solution appears a bit simpler than this one. His is likely better in many (most?) circumstances, but this alternate solution might be good in others:
Test.
```{r echo=F,cache=F}
knitr::knit_hooks$set(document=function(x) {
paste(rapply(strsplit(x, '\n'), function(y) Filter(function(z) !grepl('# HIDEME',z),y)), collapse='\n')
})
```
```{r Vector Demo 1, results='hold', tidy=FALSE}
nums = 1:5
chars = LETTERS[1:5]
# examine the class and structure of vectors
{ # HIDEME
print(class(nums))
print(class(chars))
str(nums)
str(chars)
} # HIDEME
```
Notes:
Use of the brackets ({ and }) around the code keeps the output together. However, commands that return things and don't print things will be silent (unless last), ergo my print addition to those lines. This may or may not be a factor depending on your actual commands.
In my install, for some reason, tidy defaults to TRUE which was shifting my first # HIDEME comment to before the left bracket (and I have since edited to code to reflect the definition of nums and chars). Odd, but likely a side-effect of source tidying. This is why I force tidy=FALSE. Since this might affect how you present your code, using it as a per-block option at least limits the pretty-printing problem.
The # HIDEME is really just "comment-character plus some obscure string" for easy greping.
The knit_hook I added is not "simple," but I find it less likely to have side-effects on other chunks within a document. This could likely be done with more specificity (I know #Ramnath has worked on other knitr problems with Yihui, so there could be more "correct" ways to do this with more specificity.) (I tried and failed to do this as an "output" hook instead of "document" hook. Homework.)
Related
Goal
In an R/Markdown document that I want to convert to LaTeX I want to set knitr options so that the entire document uses plain code chunks for all code inputs by default. Thus, for a .Rmd document with
```{r}
x <- 1 + 1
```
I want to obtain the output
```
x <- 1 + 1
```
Using the highlight option
I had hoped that the highlight=FALSE option could be used for this but this generates text-chunks rather than plain chunks. More precisely, for the simple example above, knit() produces an R-chunk by default (i.e., with highlight = TRUE):
```r
x <- 1 + 1
```
After setting knitr::opts_chunk$set(highlight = FALSE) a text-chunk is produced:
```text
x <- 1 + 1
```
But what I would like to have a plain chunk without any special language, see above.
Combination with lang option
I can obtain what I want via
knitr::opts_chunk$set(highlight = TRUE, lang = "")
Thus, I do enable highlighting but set the lang to an empty string. This indeed yields the plain code I want to have.
There is at least one disadvantage, though (apart from the rather hacky feel of this solution). Namely, if in the same document I do want to enable highlighting in the options of one specific chunk, I have to set lang = "r" now instead of highlight = TRUE, e.g.,
```{r, lang="r"}
x <- 1 + 1
```
So I wonder whether there is a better solution for this?
Background
In older versions of pandoc (I tried 2.9.x) text-chunks were converted to {verbatim} code chunks in LaTeX output.
However, more recent versions of pandoc (I tried 2.17.x) text-chunks are converted to {Shaded} instead and only plain chunks are converted to {verbatim}.
Another hacky solution is (I don't even dare to explain it):
```{r}
knitr::opts_hooks$set(highlight = function(options) {
if (!options$highlight) {
options$highlight = TRUE
options$lang = ''
}
options
})
knitr::opts_chunk$set(highlight = FALSE)
```
```{r}
1 + 1
```
```{r, highlight=TRUE}
2 + 2
```
The language name text when highlight = FALSE is currently hard-coded in knitr, so you cannot change it: https://github.com/yihui/knitr/blob/907184f82/R/hooks-md.R#L171 I'm open to making it configurable, but I'm not sure how (I hope not to add a new chunk option for setting the language in the case of highlight = FALSE).
I'm not sure I entirely understand what you want, but does this in the yaml header help?
---
output:
html_document:
theme: null
highlight: null
---
I have created a "book" using bookdown. I would love to be able to add interactive quizzes, without needing shiny etc.
Is it possible using R/exams (http://www.R-exams.org/) with bookdown? I'm mainly interested in the HTML output; PDF output a bonus but hardly essential. The web page offers promise:
Based on (potentially) dynamic exercise templates large numbers of personalized exams/quizzes/tests can be created for various systems: [...] and the possibility to create custom output (in PDF, HTML, Docx, ...).
Exercise types include multiple-choice or single-choice questions, numeric or text answers, or combinations of these. Formatting can be done either in Markdown or LaTeX with the possibility to generate dynamic content using R, e.g., random numbers, graphics, data sets, or shuffled text blocks.
It sounds great. Does anyone know if it is possible to use exams with bookdown (even if just some features)?
If it is possible: how? Any pointers?
If it is not possible: does anyone know a way to do something similar?
General remarks
R/exams is indeed extensible leveraging its building blocks is relatively easy. The workhorse function underlying all the exams2xyz() interfaces is called xexams(). It proceeds in four steps:
sweave: The exercise files are copied to a temporary directory and then run through R, by default using xweave() which provides a unified convenience interface to utils::Sweave() (for Rnw files) and knitr::knit() (for Rmd files).
read: The resulting weaved files are read into R, by default using read_exercise(). For each exercise this yields a list of question, questionlist, solution, solutionlist, metainfo, and supplements. All elements are always there but may be empty, e.g., when there is no solution environment provided in the exercise or when there are no supplementary files.
transform: By default this is empty but can be used to transform the exercise list elements above to a desired format, e.g., HTML.
write: By default this is empty, but can be used to write out results for each of the n replications of the exam.
Embedding exercise texts in Markdown
When you write your exercises in R/Markdown (Rmd) files you can easily run them through xexams() to get some randomized version of them. As an example, let's consider the numeric (num) and single-choice (schoice) version of the derivative exercise, see: deriv, deriv2. Using 1 as the random seed, the numeric exercise has the following question along with the correct solution and tolerance:
set.seed(1)
d1 <- xexams("deriv.Rmd")[[1]][[1]]
d1$question
## [1] "What is the derivative of $f(x) = x^{2} e^{2.3 x}$, evaluated at $x = 0.56$?"
d1$metainfo$solution
## [1] 6.68
d1$metainfo$tolerance
## [1] 0.01
The reason for the [[1]][[1]] index is that this is from the first (and only) exam, the first (and only) exercise. If you generate, say, xexams(..., n = 3) then the first index could be in 1, 2, 3. Similarly, you could inlude more than one exercise if you want.
The single-choice version has
set.seed(1)
d2 <- xexams("deriv2.Rmd")[[1]][[1]]
d2$question
## [1] "What is the derivative of $f(x) = x^{2} e^{2.3 x}$, evaluated at $x = 0.66$?"
## [2] ""
d2$questionlist
## [1] "$8.01$" "$14.09$" "$10.59$" "$15.35$" "$6.02$"
d2$metainfo$solution
## [1] FALSE FALSE TRUE FALSE FALSE
Both of these would be very easy to integrate as static text into any R/Markdown document.
Embedding exercise texts in webex
To turn the static text into a dynamic element in HTML, e.g., a text field where readers could enter a number which is then compared with the reference value from the solution, it is possible to employ Javascript for example. One lightweight R-based framework for generating such output is the webex package by Dale Barr and Lisa DeBruine.
In webex you can create fill-in-the-blank interactions via fitb() for numeric solutions with an optional tolerance (num in R/exams) or for character solutions (string in R/exams). Also, you can create drop-down menu interactions via mcq() for single-choice questions (schoice in R/exams). (Note: The jargon regarding choice questions is not unified: What R/exams calls single-choice is also referred to as multiple-choice. In this case multiple-answer is often used for what R/exams calls multiple-choice.)
At the moment, webex does not support radio buttons as an alternative to drop-down menus. Also, check-boxes for multiple-choice (aka multiple-answer) questions is not available.
Below, I illustrate how to embed simple schoice, num, and string questions in webex. For more elaborate examples with supplementary files, see the comments below. Also, cloze would also be doable but take some more work.
---
title: "Web Exercises with R/exams & webex"
output: webex::webex_default
---
```{r setup, include = FALSE}
knitr::opts_chunk$set(echo = TRUE)
library("webex")
library("exams")
```
`r style_widgets("#DF536B", "#61D04F")`
## `schoice`
```{r swisscapital, echo = FALSE, results = "asis"}
x <- xexams("swisscapital.Rmd")[[1]][[1]]
names(x$questionlist) <- ifelse(x$metainfo$solution, "answer", "")
x <- c(
x$question,
"",
mcq(x$questionlist),
"",
hide("Correct solution"),
"",
x$solution,
"",
paste("*", x$solutionlist),
"",
unhide()
)
writeLines(x)
```
## `num`
```{r deriv, echo = FALSE, results = "asis"}
x <- xexams("deriv.Rmd")[[1]][[1]]
x <- c(
x$question,
"",
fitb(x$metainfo$solution, tol = x$metainfo$tol,
width = min(100, max(20, nchar(x$metainfo$solution)))),
"",
hide("Correct solution"),
"",
x$solution,
"",
unhide()
)
writeLines(x)
```
## `string`
```{r function, echo = FALSE, results = "asis"}
x <- xexams("function.Rmd")[[1]][[1]]
x <- c(
x$question,
"",
fitb(x$metainfo$solution, width = min(100, max(20, nchar(x$metainfo$solution)))),
"",
hide("Correct solution"),
"",
x$solution,
"",
unhide()
)
writeLines(x)
```
Rendering this with rmarkdown::render() gives you a file like shown in the screenshot below. When embedding this in bookdown you need to make sure to embed the webex.css and webex.js from the package.
Further variations
Some extra work is involved when processing exercises that contain images such as boxplots. The default in xexams() is set up for PDF output but the driver$sweave can be tweaked to produce PNG output. In either case, the supplements is then a vector of file paths to the supplementary files:
set.seed(1)
b1 <- xexams("boxplots.Rmd", driver = list(sweave = list(png = TRUE)))[[1]][[1]]
b1$question
## [1] "In the following figure the distributions of a variable"
## [2] "given by two samples (A and B) are represented by parallel boxplots."
## [3] "Which of the following statements are correct? _(Comment: The"
## [4] "statements are either about correct or clearly wrong.)_"
## [5] "\\"
## [6] "![](boxplot-1.png)"
## [7] ""
b1$supplements
## boxplot-1.png
## "/tmp/RtmpA07Hau/file11d77d212e69bf/exam1/exercise1/boxplot-1.png"
## attr(,"dir")
## [1] "/tmp/RtmpA07Hau/file11d77d212e69bf/exam1/exercise1"
Additionally, you can set up a transform driver that converts the R/Markdown already to HTML (rather than having bookdown doing this later on). Here I'm selecting pandoc as the converter, using MathJax for the rendering of mathematical content (like bookdown does as well). Using base64 = TRUE instead of the FALSE below would embed the supplementary PNG image directly in the HTML code using a Base 64 encoding.
set.seed(1)
htmltrafo <- make_exercise_transform_html(converter = "pandoc-mathjax", base64 = FALSE)
b2 <- xexams("boxplots.Rmd", driver = list(sweave = list(png = TRUE), transform = htmltrafo))[[1]][[1]]
b2$question
## [1] "<p>In the following figure the distributions of a variable given by two samples (A and B) are represented by parallel boxplots. Which of the following statements are correct? <em>(Comment: The statements are either about correct or clearly wrong.)</em><br />"
## [2] "<img src=\"boxplot-1.png\" /></p>"
This is Great Achim. I was struggling to find a way to make bookdown talk to exam exercise files and found similar solution before reaching this post. The main difference is that I'm using bootstrap 4 (bookdown::bs4_book) in the html, which looks nicer.
This is how it looks in the Rmarkdown chapter file:
f_in <- fs::dir_ls('00-EOCE-Rmd/Cap08-Programação/',
type = 'file')
build_exercises(f_in, type_doc = my_engine)
The result:
I analyze survey results regularly and like to use Rmarkdown so I can make nice HTML output of the results.
The surveys can be many questions (like 40), so creating 40 code chunks, with highly repetitive code and headers, can be annoying. And I can easily do this with a loop in R, I think. However, I'm just stuck on how to combine these 2 processes!
This was close --
how to create a loop that includes both a code chunk and text with knitr in R
But in the end, it was just a loop, and not very flexible. So, I couldn't add a figure to question 22 (or whatever).
### Question 1
#### `r key$Question_Text[key$Question=="Q1"][1]`
```{r chunk1}
quest <- "Q1"
# code for question 1
```
### Question 2
#### `r key$Question_Text[key$Question=="Q2"][1]`
```{r chunk2}
quest <- "Q2"
# Identical code for question 2
```
....and so on....
### Question 35
#### `r key$Question_Text[key$Question=="Q35"][1]`
```{r chunk35}
quest <- "Q35"
# Identical code for question 35
```
Because sometimes, a question has a special type of figure or tweak, I want the output to be something I can paste into RMD and make all the changes there. I just want to skip ahead as much as possible... by making all the boring, identical steps, fully automated.
make strings that I can refer to in loop
question<-paste(rep("Question",20), 1:20, sep=" ")
qnum<-paste0(rep("Q",20), 1:20, sep="")
quest_text_code <- paste0("#### ","`r key$Question_Text[key$Question==", "\"",qnum[i],'"' ,"][1]`")
chunk <- paste(rep("chunk",20), 1:20, sep="")
use sink() to send to a text file
sink("outfile.txt")
loop and paste and output into the sink
for(i in 1:20){ cat(paste("###", question[i], "\n", "\n",
quest_text_code,"\n", "\n",
"```", "{r ", chunk[i], "}", "\n","\n",
"function.dat(", qnum[i], ")","\n", "\n",
"function.dat.nr(", qnum[i], ")","\n", "\n",
"```", "\n", "\n"))
}
dev.off() # ends sink
After that, I was able to copy to an RMD file and use find and replace on a few glitches (extra leading spaces) I also had trouble adding "" marks with paste.
I have an R Script that I would like to import from within a different R-script, manipulate it's content (search and replace) and save with a different extension (.rmd).
This is how the example.R File would look before manipulation:
# A title
# chunkstart
plot(1,1)
# chunkend
and this is how example.Rmd it would look after manipulation: replaced "# chunkstart" and "# chunkend" with ```{r} and ```, respectively.
# A title
```{r}
plot(1,1)
```
I've been searching for methods to do this, but so far have found none. Any ideas?
I'm sure that you can do it using regex with less lines of code.
However its should solve your problem.
library(magrittr)
readLines('example.R') %>%
stringr::str_replace("# chunkstart", "```{r}") %>%
stringr::str_replace("# chunkend", "```") %>%
writeLines("example.Rmd")
With the following lines of code you will be able to apply this "operation" in every .R file inside /path_to_some_directory
lapply(list.files('/path_to_some_directory', pattern = ".R$",
full.names = TRUE), function(data) {
readLines(data) %>%
stringr::str_replace("# chunkstart", "```{r}") %>%
stringr::str_replace("# chunkend", "```") %>%
writeLines(paste0(data, "md"))
})
Hope it helps!
I think ?knitr::spin is a relevant answer to the question (specifically asking for ideas), or at least a useful alternative to consider.
You'd have to slightly reformat the input, but the benefits would be a built-in, much richer and versatile way to deal with chunk options and formatting.
Here's what an annotated R script might look like (with spin's default regexs),
#' ## A title
#' first chunk
#- fig.width=10
plot(1,1)
# some text
#' another chunk
plot(2,2)
and the output Rmd reads,
## A title
first chunk
```{r fig.width=10}
plot(1,1)
# some text
```
another chunk
```{r }
plot(2,2)
```
Is there a standard way to include the computed values from variables early on in the written knitr report before those values are computed in the code itself? The purpose is to create an executive summary at the top of the report.
For example, something like this, where variable1 and variable2 are not defined until later:
---
title: "Untitled"
output: html_document
---
# Summary
The values from the analysis are `r variable1` and `r variable2`
## Section 1
In this section we compute some values. We find that the value of variable 1 is `r variable1`
```{r first code block}
variable1 <- cars[4, 2]
```
## Section 2
In this section we compute some more values. In this section we compute some values. We find that the value of variable 2 is `r variable2`
```{r second code block}
variable2 <- cars[5, 2]
```
A simple solution is to simply knit() the document twice from a fresh Rgui session.
The first time through, the inline R code will trigger some complaints about variables that can't be found, but the chunks will be evaluated, and the variables they return will be left in the global workspace. The second time through, the inline R code will find those variables and substitute in their values without complaint:
knit("eg.Rmd")
knit2html("eg.Rmd")
## RStudio users will need to explicitly set knit's environment, like so:
# knit("eg.Rmd", envir=.GlobalEnv)
# knit2html("eg.Rmd", envir=.GlobalEnv)
Note 1: In an earlier version of this answer, I had suggested doing knit(purl("eg.Rmd")); knit2html("eg.Rmd"). This had the (minor) advantage of not running the inline R code the first time through, but has the (potentially major) disadvantage of missing out on knitr caching capabilities.
Note 2 (for Rstudio users): RStudio necessitates an explicit envir=.GlobalEnv because, as documented here, it by default runs knit() in a separate process and environment. It default behavior aims to avoid touching anything in global environment, which means that the first run won't leave the needed variables lying around anywhere that the second run can find them.
Here is another approach, which uses brew + knit. The idea is to let knitr make a first pass on the document, and then running it through brew. You can automate this workflow by introducing the brew step as a document hook that is run after knitr is done with its magic. Note that you will have to use brew markup <%= variable %> to print values in place.
---
title: "Untitled"
output: html_document
---
# Summary
The values from the analysis are <%= variable1 %> and
<%= variable2 %>
## Section 1
In this section we compute some values. We find that the value of variable 1
is <%= variable1 %>
```{r first code block}
variable1 = cars[6, 2]
```
## Section 2
In this section we compute some more values. In this section we compute
some values. We find that the value of variable 2 is <%= variable2 %>
```{r second code block}
variable2 = cars[5, 2]
```
```{r cache = F}
require(knitr)
knit_hooks$set(document = function(x){
x1 = paste(x, collapse = '\n')
paste(capture.output(brew::brew(text = x1)), collapse = '\n')
})
```
This has become pretty easy using the ref.label chunk option. See below:
---
title: Report
output: html_document
---
```{r}
library(pixiedust)
options(pixiedust_print_method = "html")
```
### Executive Summary
```{r exec-summary, echo = FALSE, ref.label = c("model", "table")}
```
Now I can make reference to `fit` here, even though it isn't yet defined in the script. For example, a can get the slope for the `qsec` variable by calling `round(coef(fit)[2], 2)`, which yields 0.93.
Next, I want to show the full table of results. This is stored in the `fittab` object created in the `"table"` chunk.
```{r, echo = FALSE}
fittab
```
### Results
Then I need a chunk named `"model"` in which I define a model of some kind.
```{r model}
fit <- lm(mpg ~ qsec + wt, data = mtcars)
```
And lastly, I create the `"table"` chunk to generate `fittab`.
```{r table}
fittab <-
dust(fit) %>%
medley_model() %>%
medley_bw() %>%
sprinkle(pad = 4,
bg_pattern_by = "rows")
```
I work in knitr, and the following two-pass system works for me. I have two (invisible) code chunks, one at the top and one at the bottom. The one at the bottom saves the values of any variables I need to include in the text before they are actually computed in a file (statedata.R). The top chunk sets the variable values to something that stands out if they haven't been defined yet, and then (if it exists) it grabs the actual values from the stored file.
The script needs to be knit twice, as values will be available only after one pass through. Note that the second chunk erases the saved state file at the end of the second pass, so that any later changes to the script that affect the saved variables will have to be computed anew (so that we don't accidentally report old values from an earlier run of the script).
---
title: "Untitled"
output: html_document
---
```{r, echo=FALSE, results='hide'}
# grab saved computed values from earlier passes
if (!exists("variable1")) {
variable1 <- "UNDEFINED"
variable2 <- "UNDEFINED"
if (file.exists("statedata.R")) {
source("statedata.R")
}
}
# Summary
The values from the analysis are `r variable1` and `r variable2`
## Section 1
In this section we compute some values. We find that the value of variable 1 is `r variable1`
```{r first code block}
variable1 <- cars[4, 2]
```
## Section 2
In this section we compute some more values. In this section we compute some values. We find that the value of variable 2 is `r variable2`
```{r second code block}
variable2 <- cars[5, 2]
```
```{r save variables for summary,echo=FALSE,results='hide'}
if (!file.exists("statedata.R")) {
dump(c("variable1","variable2"), file="statedata.R")
} else {
file.remove("statedata.R")
}
```
Latex macros can solve this problem. See this answer to my related question.
\newcommand\body{
\section{Analysis}
<<>>=
x <- 2
#
Some text here
} % Finishes body
\section*{Executive Summary}
<<>>=
x
#
\body