How to show formatted R output with results='asis' in rmarkdown - r

Is there a way of showing formatter R output in rmarkdown/knitr when using results = 'asis'?
An example would be the following function:
myfun <- function() {
cat("hello!\n")
cat(c("one" = 1, "two" = 2))
}
Then, this chunk will print the second cat on a new row:
```{r}
myfun()
```
But this will ignore the formatting from myfun:
```{r, results = "asis"}
myfun()
```
Is there a way of keeping results='asis' but at the same time keep the output of myfun formatted as intended?

You can use the knitr chunk option results = "asis" if you are happy to add two or more spaces at the end of the line. That is, instead of "hello\n", you need to write "hello \n" to trigger the line break.
Example R Markdown code:
---
output: html_document
---
```{r}
myfun <- function() {
cat("hello! \n")
cat(c("one" = 1, "two" = 2))
}
```
```{r results = "asis"}
myfun()
```
Gives
Why the blank spaces? It's because two spaces at the end of a line are used to indicate a hard line break in markdown. For example, this quote is taken from Pandoc's Markdown (which is the default markdown flavour R Markdown uses):
Paragraphs
A paragraph is one or more lines of text followed by one or more blank lines. Newlines are treated as spaces, so you can reflow your paragraphs as you like. If you need a hard line break, put two or more spaces at the end of a line.

Related

RMarkdown collapse output in one chunk

By default RMarkdown tends to split the output. So that:
```{r, collapse = FALSE}
print(1)
print(2)
```
comes as:
Making collapse = TRUE should remove the breaks in the output but it doesn't. Does anyone know why?
You must use the results = "hold" option to include all text output from the evaluated chunk together in the document.
```{r, results = "hold"}
print(1)
print(2)
```
See the text output options of the knitr package for details.

Inline referencing of a code chunk in document

Suppose there is a code chunk as follows:
```{r mean diff}
(5-mean(dnorm(40,5,2))/5
```
I would like to be able to reference this code chunk with its label in inline form in a markdown document, so that the reference is replaced by the output of this chunk. Is there a way to do it?
" the difference is `r mean diff` %." ##something like this?
I think the answer to your question is "yes, but it's tricky". By default knitr doesn't save the last value computed in a code chunk. In regular code, the last value calculated is saved in .Last.value, but knitr doesn't simulate this.
However, a simple modification lets you do something very similar:
```{r}
meandiff <- 5-mean(dnorm(40,5,2))/5
meandiff # if you want the chunk to print its value
```
and then in the text, use
" the difference is `r meandiff` %."
If you really want to save the last value, it's possible by setting a "render hook". For example, the code below saves the last value, then calls the old hook:
```{r}
.Last.value <- NULL
old_hook <- knitr::opts_chunk$get("render")
knitr::opts_chunk$set(render = function(x, options, ...) {
.Last.value <<- x
if (!is.null(old_hook))
old_hook(x, options, ...)
else
knitr::knit_print(x, options, ...)
})
```
```{r mean diff}
5-mean(dnorm(40,5,2))/5
```
The value was `r .Last.value`.

How to generate rmarkdown chunk within a chunk

I'm trying to generate a rmarkdown chunk using code. I've read similar questions and their solutions, such as using pander or using cat. I just can't seem to generate it. I also tried knitting the output manually. Here's an example of a Rmd file:
---
title: "test"
output: pdf_document
---
## R Markdown
```{r, results='asis',echo=FALSE}
txt <- paste("```{r}",
"2+2",
"```")
pander::pander(txt)
```
When I knit this, I get a verbatim {r} 2+2. I would like to see the number four instead. In my real example, I'm using bookdown and trying to generate a block2 chunk.
Any ideas how to generate this chunk that gets evaluated as R code?
Does this do what you want?
## R Markdown
```{r, results='asis',echo=FALSE}
txt <- paste("```{r}",
2+2,
"```")
pander::pander(txt)
```
This evalutates to
```{r} 4 ```
in your markdown document.
You using a string literal "2+2" as opposed to the expression 2+2. This is the first issue, I guess.
If you want it correctly parsed you need to add an sep = "\n" argument to paste or manually add the newline breaks.
I.e.
## R Markdown
```{r, results='asis',echo=FALSE}
txt <- paste("```{r}\n",
2+2,
"\n```", sep = "")
pander::pander(txt)
```
This evalutates to
```{r}
4
```
which is interpreted as R code in the markdown document.

Generate both markdown comments and html wigets in a loop rmarkdown

I'm trying to generate a flexdashboard, creating each page from within a loop and with each of the generated pages containing a dygraph (although any HTML widget ought to behave the same).
I have looked extensively and it seems that rmarkdown comments can be generated using cat("title") (as per the solution here: generate markdown comments within for loop).
The HTML widgets on the other hand only behave nicely if you use htmltools::tagList() (as per the solution here:For loop over dygraph does not work in R).
I dont have working code to share, but this broadly gives the picture of what I am hoping to achieve:
for (i in 1:ncol(downloadedData)){
fund_NAVS <- downloadedData[,i] #this is an xts object
fund_NAVS <- fund_NAVS[!is.na(fund_NAVS)]
cat("pageTitle")
cat("===================================== \n")
cat("Row\n")
cat("------------------------------------- \n")
cat("### Page title")
dygraph(fund_NAVS)
}
I've been able to get this to partially work using pander::pandoc.header. However, getting content (plots and HTML objects) to actually show up in the final HTML file is a different story.
---
output:
flexdashboard::flex_dashboard:
orientation: columns
source: embed
vertical_layout: fill
---
```{r results='asis'}
library(pander)
pages <- 5
cols <- 2
sections <- 3
for (p in 1:pages) {
pandoc.header(paste("Page", p), level = 1)
for (c in 1:cols) {
pandoc.header(paste("Column", c), level = 2)
for (s in 1:sections) {
pandoc.header(paste("Section", s), level = 3)
cat("hi")
pandoc.p("")
}
}
}
```
I was able to autogenerate content by building r chunks explicitly then kniting them inline with r paste(knitr::knit(text = out)). This amazing line of code was found in an SO post.
In my case, I wanted to produce a series of graphs, each with a separate tab, with different content. Each graph was similar but there were numerous (about 15) and I didn't want to copy/paste all of the separate chunks.
Here is a gist you can download of a more simple example. (The code is also below but note that I add \ before each chunk so that it rendered as a single block of code so remove the \ before running.) I built a much more complicated function to build graphs, but the idea of the R chunks can be carried forward to any list object containing htmlwidgets as elements.
---
title: "Loop to Auto Build Tabs Containing htmlwidgets"
output: flexdashboard::flex_dashboard
---
\```{r setup, echo =FALSE, eval = TRUE}
library(tidyverse)
library(flexdashboard)
library(highcharter)
labels <- mtcars %>% names # these will serve as labels for each tab
# create a bunch of random, nonsensical line graphs
hcs <- purrr::map(.x = mtcars, ~highcharter::hchart(mtcars, y = .x, type = 'line')) %>%
setNames(labels) # assign names to each element to use later as tab titles
\```
Page
====================
Column {.tabset .tabset-fade}
-----------------------------
<!-- loop to build each tabs (in flexdashboard syntax) -->
<!-- each element of the list object `out` is a single tab written in rmarkdown -->
<!-- you can see this running the next chunk and typing `cat(out[[1]])` -->
\```{r, echo = FALSE, eval = TRUE}
out <- lapply(seq_along(hcs), function(i) {
a1 <- knitr::knit_expand(text = sprintf("### %s\n", names(hcs)[i])) # tab header, auto extracts names of `hcs`
a2 <- knitr::knit_expand(text = "\n```{r}") # start r chunk
a3 <- knitr::knit_expand(text = sprintf("\nhcs[[%d]]", i)) # extract graphs by "writing" out `hcs[[1]]`, `hcs[[2]]` etc. to be rendered later
a4 <- knitr::knit_expand(text = "\n```\n") # end r chunk
paste(a1, a2, a3, a4, collapse = '\n') # collapse together all lines with newline separator
})
\```
<!-- As I mentioned in the SO post, I don't quite understand why it has to be -->
<!-- 'r paste(knitr::knit(...)' vs just 'r knitr::knit(...)' but hey, it works -->
`r paste(knitr::knit(text = paste(out, collapse = '\n')))`

If-Else Statement in knitr/Sweave using R variable as conditional

I am currently using knitr in R and RStudio to produce a LaTeX output. My code is a .Rnw file (called, say, testKnitr.Rnw) that is compiled to a pdf file with:
knit("testKnitr.Rnw") // in RStudio
pdflatex testKnitr.tex // in terminal
I would like to use an if-else syntax in LaTeX so that, depending on the value of an R variable, one of two LaTeX text paragraphs are output. In these LaTeX paragraphs, I would like to use expressions like \Sexpr{} and and \ref.
I have a minimal-working-example that is based on the second answer to a similar question posted here:
How to write an if-then statement in LaTeX using the value of an R variable in knitr/Sweave
Here is the MWE:
\documentclass{article}
\begin{document}
<<include=FALSE>>=
library(knitr)
opts_chunk$set(
concordance=TRUE
)
#
<<condition, include=FALSE, echo=FALSE>>=
x<- rnorm(1)
if(x>0){
text <- "This means x value of \Sexpr{x} was greater than 0"
}else{
text <- "This means x value of \Sexpr{x} was less than 0"
}
#
Testing the code:
<<print, results='asis', echo=FALSE>>=
cat(text)
#
\end{document}
Ideally, the intended output of the above MWE would a report with one line that contained something like:
"This means x value of 0.87 was greater than 0"
or
"This means x value of -0.87 was less than 0"
Before answering this question, I would like to take a look at the meta-question of whether this should be done.
Should we do it?
I don't think so. What we are basically doing here is using knitr to insert \Sexpr{x} in a document and then interpret \Sexpr{x}. There are no (obvious) reasons why we should take this detour instead of inserting the value of x directly to the document.
How to do it?
The following minimal example shows how it could be done anyways:
\documentclass{article}
\begin{document}
<<setup, echo = FALSE>>=
library(knitr)
knit_patterns$set(header.begin = NULL)
#
<<condition, echo=FALSE>>=
x <- rnorm(1)
if (x > 0) {
text <- "This means x value of \\Sexpr{x} was greater than 0"
} else {
text <- "This means x value of \\Sexpr{x} was less than 0"
}
#
Testing the code:
<<print, results='asis', echo=FALSE>>=
cat(text)
#
\end{document}
Two things are important here:
We need to escape the backslash in \Sexpr, resulting in \Sexpr.
We need to set knit_patterns$set(header.begin = NULL).
To compile the document:
Save it as doc.Rnw.
Then execute:
knitEnv <- new.env()
knit(input = "doc.Rnw", output = "intermediate.Rnw", envir = knitEnv)
knit2pdf(input = "intermediate.Rnw", output = "doc_final.tex", envir = knitEnv)
What happens?
The first call of knit generates intermediate.Rnw with the following content:
\documentclass{article}
\begin{document}
Testing the code:
This means x value of \Sexpr{x} was less than 0
\end{document}
You should note that knitr didn't include any definitions, commands etc. as usual to the LaTeX code. This is due to setting header.begin = NULL and documented here. We need this behavior because we want to knit the resulting document again in the second step and LaTeX doesn't like it when the same stuff is defined twice.
Creating the new environment knitEnv and setting it as envir is optional. If we skip this, the variable x will be created in the global environment.
In the second step we use knit2pdf to knit intermediate.Rnw and immediately generate a PDF afterwards. If envir was used in the first step, we need to use it here too. This is how x and it's value are conveyed from the first to the second knitting step.
This time all the gory LaTeX stuff is included and we get doc_final.tex with:
\documentclass{article}\usepackage[]{graphicx}\usepackage[]{color}
%% maxwidth is the original width if it is less than linewidth
%% otherwise use linewidth (to make sure the graphics do not exceed the margin)
\makeatletter
\def\maxwidth{ %
\ifdim\Gin#nat#width>\linewidth
\linewidth
\else
\Gin#nat#width
\fi
}
\makeatother
%% more gory stuff %%
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
\begin{document}
Testing the code:
This means x value of \ensuremath{-0.294859} was less than 0
\end{document}

Resources