I have 2 questions about knitr chunk options:
1) Is it possible to override knitr chunk options from inside a chunk of code so that the options were applied in the same chunk? e.g. write something like the following lines and get result as-is:
```{r, results= "markup"}
knitr::opts_chunk$set(results= "asis")
for (i in 1:5)
print("# This text should be printed 'as-is'")
```
p.s. I'm familiar with knitr::asis_output.
2) Is it possible to get chunk options from inside a chunk? E.g., to use code like:
```{r}
knitr::opts_chunk$get("results")
```
And get string markup.
```{r, results='asis'}
knitr::opts_chunk$get("results")
```
And get string asis.
Unfortunately, knitr::opts_chunk$get("results") gets global options, and not the ones of a current chunk.
1) Printings can be customized using functions knitr::normal_print and knitr::asis_output (as you mentionned). For instance :
```{r, results='markup'}
knitr::asis_output(replicate(5, "# This text should be printed 'as-is'\n"))
print("# This text should be printed 'normal'")
```
and alternatively
```{r, results='asis'}
for (i in 1:5)
cat("# This text should be printed 'as-is'\n")
knitr::normal_print("# This text should be printed 'normal'\n")
```
2) Current chunk options can be retrieved using knitr::opts_current$get(). Use :
```{r, results='asis'}
knitr::opts_current$get("results")
```
and get string asis
Related
I have a .Rmd file which I am converting to PDF. For layout reasons, I want to display the generated output plot of my code chunk on the next page even though it would just fit in underneath.
Normally with text etc. one would use
\pagebreak
But how can I signalize the code chunk that it should display its output on the next page?
Thanks for helping!
You can write a knitr hook to set up a chunk option to do this.
So here I have modified the source chunk hook and created a chunk option next_page which, if TRUE, the output of that chunk will be on the next page.
---
title: "Chunk Output in Next page"
output: pdf_document
date: "2022-11-25"
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
```{r, include=FALSE}
library(knitr)
default_source_hook <- knit_hooks$get('source')
knit_hooks$set(
source = function(x, options) {
if(isTRUE(options$next_page)) {
paste0(default_source_hook(x, options),
"\n\n\\newpage\n\n")
} else {
default_source_hook(x, options)
}
}
)
```
```{r, next_page=TRUE}
plot(mpg ~ disp, data = mtcars)
```
I would recommend you to save the output in the file (png/jpeg/pdf) and then load it with the markdown or knitr.
Such solution gives you a full control.
Automatic
I found alternative solution in rmarkdown-cookbook.
We generate a plot in this code chunk but do not show it:
```{r cars-plot, dev='png', fig.show='hide'}
plot(cars)
```
\newpage
![A nice plot.](\`r knitr::fig_chunk('cars-plot', 'png')\`)
Manual
```{r}
png("NAME.png")
# your code to generate plot
dev.off()
```
then load image with
![LABEL](PATH/NAME.png) or with
```{r echo=FALSE, out.width='100%', ...}
knitr::include_graphics('PATH/NAME.png')
```
I am wondering how we can define a hyperlink for R markdown outside Rmd file. Defining a hyperlink inside Rmd file is as easy as typing [hyperlink lable](actual link); but, if on the Rmd file, I am calling some other r-file (e.g., a function) that generates an address to a file, is there a way to transfer this information back to Rmd file to generate a hyperlink there?
Please see example below for more clarification:
Inside Rmd file:
myFun( with some input)
Inside myFun:
myFun <- function( with some input)
some calculations...
return("[click here](C:/myFile.docx)")
The output on the generated html page is:
[1] "[click here] (C:/myFile.docx)"
Which is not a hyperlink!
To define the links outside the rmd file you can use a parameterized report. This allows you to pass values into the rmarkdown document when you compile it. To do this, first create an rmarkdown document that includes the desired parameters, which are declared in the yaml header and then used later in the report. Then, in a separate R script, run the render command (from the rmarkdown package) and pass the desired parameter values.
Here's an example that uses cat or paste to generate the links. For comparison, I've also added a second set of parameters that add different links using the methods in #JohnCoene's answer. I've saved the rmarkdown document as "test.rmd", which is how the document is identified in the render command.
rmarkdown document
---
output: html_document
params:
text1: "add text"
link1: "add URL"
text2: "add text"
link2: "add URL"
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r}
# Function to add link
myFun <- function(text, link, inline=TRUE) {
if(inline) {
paste("[", text, "](", link, ")", sep="")
} else {
cat("[", text, "](", link, ")", sep="")
}
}
```
Blah, blah, blah, more text. And here's the link:
```{r, results="asis"}
myFun(params$text1, params$link1, inline=FALSE)
```
Blah, blah, blah, more text. And here's a way to `r myFun(params$text1, params$link1)`.
Or, using the examples from `#JohnCoene's` answer:
With an HTML tag:
```{r, results="asis"}
tg <- function (link, text){
paste0("<a href='", link, "'>", text, "</a>")
}
tg(params$link2, params$text2)
```
With `htmltools`:
```{r}
# install.packages("htmltools")
library(htmltools)
tags$a(
href = params$link2,
params$text2
)
```
Separate R script to render the rmarkdown document
library(rmarkdown)
render(input="test.rmd",
params=list(text1="link to Stackoverflow",
link1="https://stackoverflow.com/questions/52745926/r-markdown-hyperlink-outside-rmd-file",
text2="link to google",
link2="https://google.com"))
Here's what the output html document looks like:
There are multiple solutions, return an html tag or use the htmltools package.
HTML tag
```{r, results="asis"}
tg <- function (link, text){
paste0("<a href='", link"'>", text, "</a>")
}
tg("http://google.com", "link to Google")
```
htmltools
Definitely recommend this way over the other.
```{r}
# install.packages("htmltools")
library(htmltools)
tags$a(
href = "https://google.com",
"Link to Google"
)
```
As mentioned in the question, assuming the output of 'myFun' function is the hyperlink string, here is what worked best for me:
Inside myFun:
myFun <- function()
...some calculations to generate a csv file...
return("C:/myFile.csv")
Inside Rmd file:
```{r, echo=FALSE}
myHyperlink <- myFun()
hyperlink_exists = !is.null(myHyperlink)
```
```{r, eval=hyperlink_exists, results="asis", echo=FALSE}
cat(paste0("The file is saved ","[", "Here", "](", myHyperlink, ")","\n"))
```
I'm writing some tutorials using blogdown. For a pedagogical reason, I want my students to think before seeing the solution. Here's my current code.
Original
---
title: "Toggle Chuck Output Using details Tag"
output: html_document
---
```{r calc, prompt=TRUE, eval=FALSE}
90 + 30
```
<details>
<summary>Toggle output</summary>
```{r, ref.label='calc', echo=FALSE, prompt=TRUE}
```
</details>
Here's my attempt:
To avoid repeatedly writing the HTML tags, I think I need to define a function similar to ...
togglable <- function(label, summary = "Toggle output"){
cat('<details>')
cat(' <summary>', summary, '</summary>', sep = '')
# Code to print output using 'ref.label' should go here.
# The following doesn't work.
knitr::knit_print(knitr:::knit_code$get(label))
cat('</details>')
}
.... then replace the <detals>...</details> block with a R code chunk similar to the following:
Use case 1 (better)
```{r usecase1, echo=FALSE, results='asis'}
togglable(label = "calc")
```
I tried to make it work, but in vain.
One more thing. If possible, I'd like this togglable() function to override the chunk options so that I don't even need to write echo=FALSE, results='asis', because the following chunk would look nicer.
Use case 2 (best)
```{r usecase2}
togglable(label = "calc")
```
In summary, I would like to ask the following questions.
How can I define this togglable() function so that it behaves in the same way as the original <detals>...</details> block?
Is it possible that this function overrides the options (echo and results in particular) for the chunk where this function is called? If yes, how?
Alternatively, is there any other idea how to produce the result of the original code without repeatedly writing the HTML tags?
Thank you very much!
This can be done by a combination of the chunk option ref.label (to reuse chunks), a chunk hook (to print the <details> tag) and a option hook (to change the chunk options when displaying the results.
---
title: "Toggle Chuck Output Using details Tag"
output: html_document
---
```{r setup, include=FALSE}
library(knitr)
knit_hooks$set(showDetails = function(before, options, envir) {
if (before) {
return("<details>\n")
} else {
return("\n</details>")
}
})
opts_hooks$set(showDetails = function(options) {
if(options$showDetails) {
options$echo = FALSE
options$results = "asis"
}
return(options)
})
```
```{r calc, prompt=TRUE, eval=FALSE}
90 + 30
```
```{r, ref.label="calc", showDetails = TRUE}
```
How it works:
The chunk hook is executed before and after each chunk where the option showDetails is not NULL. It prints (returns) the respective HTML.
The option hook adjusts the other options (echo and results) for each chunk there showDetails is TRUE.
The code could be further improved by globally setting the options of the calc chunk, such that you do not have to repeat them for all other "show code only" chunks: add opts_chunk$set(prompt = TRUE, eval = FALSE) to the setup chunk and options$eval = TRUE to the option hook.
Besides, if you want <detail> tags by default whenever using ref.label, you could use ref.label as option hook:
```{r setup, include=FALSE}
library(knitr)
opts_chunk$set(prompt = TRUE, eval = FALSE)
knit_hooks$set(showDetails = function(before, options, envir) {
if (before) {
return("<details>\n")
} else {
return("\n</details>")
}
})
opts_hooks$set(ref.label = function(options) {
options$echo = FALSE
options$results = "asis"
options$eval = TRUE
options$showDetails = TRUE
return(options)
})
```
```{r calc}
90 + 30
```
```{r, ref.label="calc"}
```
I'd like to wrap figures created with knitr and rmarkdown in a "wrapfigure" environment using hooks. However, when running the minimal example below, the figure chunk only gets compiled into a markdown picture:
\begin{wrapfigure}{R}{0.3\textwidth}
![](test_files/figure-latex/unnamed-chunk-2-1.pdf)
\end{wrapfigure}
and not the expected:
\begin{wrapfigure}{R}{0.3\textwidth}
\includegraphics{test_files/figure-latex/unnamed-chunk-2-1.pdf}
\end{wrapfigure}
Minimal example:
---
header-includes:
- \usepackage{wrapfig}
output:
pdf_document:
keep_tex: TRUE
---
```{r}
library(knitr)
knit_hooks$set(wrapf = function(before, options, envir) {
if(before) {
"\\begin{wrapfigure}{R}{0.3\\textwidth}"
} else {
"\\end{wrapfigure}"
}
})
```
```{r, wrapf=TRUE}
library(ggplot2)
qplot(cars$speed, cars$dist)
```
pandoc is responsible for converting the markdown document to a TEX document. As pandoc doesn't touch between \begin{…} and \end{…} the markdown syntax for the image is not being converted to TEX syntax.
You could …
Hide the plot (fig.show = 'hide') and use something along the lines of cat("\includegraphics{figure/unnamed-chunk-2-1.pdf}").
Hide the plot as above and include some magic in the hook that saves the cat.
Write RNW instead of RMD if you want PDF output.
Here's an example for option 2:
knit_hooks$set(wrapf = function(before, options, envir) {
if(before) {
return("\\begin{wrapfigure}{R}{0.3\\textwidth}")
} else {
output <- vector(mode = "character", length = options$fig.num + 1)
for (i in 1:options$fig.num) {
output[i] <- sprintf("\\includegraphics{%s}", fig_path(number = i))
}
output[i+1] <- "\\end{wrapfigure}"
return(paste(output, collapse = ""))
}
})
This hook can be used with wrapf = TRUE and fig.show = "hide". (Moreover, you need to add \usepackage{graphics} to header-includes.)
But note that I would not do it! Too many things can go wrong in more complex settings. Think of cache, captions, labels, cache (again!) …
Therefore, if it is really necessary to control the typesetting of the PDF, I recommend writing RNW (option 3).
How can I programmatically set a figure caption in a knitr hook?
I'd like to set the figure caption, if not explicitly defined, to the chunk label. I've read the knitr docs on options, options, and hooks, and though I think I understand the mechanisms at play, I can't get it to work.
My use-case that perhaps justifies this behavior: my work-flow recently adapted to start my data and visualization exploration in Rmd files. I'll use chunks for cleaning, subsetting, etc, and then a sample chunk for each visualization. This is quick and dirty, meaning minimal markdown. When I look over the report (typically rendered into PDF), I'll look at a figure and want to go straight to the source for it. Though text before/after the figure can provide insight, due to LaTeX figure rules it is not a sure thing. Counting figure numbers is feasible, but not "easy" (and becomes problematic with many figures). Captions are always with the figure, so it'd be great if I can default to filling the caption with the chunk label. (Yes, it's a little lazy of me.)
The MWE is below.
The hook code ran just fine; the returned strings in the hook appeared correctly. However, the figure caption did not change. Exception: when there is a chunk with an undefined fig.cap, all subsequent chunks have their caption set to the first un-captioned chunk name; this doesn't surprise me due to the global nature of opts_chunk, so that's out.
I suspect it might be related to "output hooks" vice "chunk hooks," but this really is a per-chunk thing and I do not want to modify the plot, just set the caption.
MWE:
---
title: "Document Title"
author: "My Name"
output:
pdf_document:
fig_caption: yes
---
# Header
```{r setup}
knit_hooks$set(autocap = function(before, options, envir) {
if (before) {
if (is.null(options$fig.cap)) {
options$fig.cap <- options$label
knitr::opts_current$set(fig.cap = options$label)
knitr::opts_chunk$set(fig.cap = options$label) # wrong!
paste('Set: `', options$label, '`, `',
knitr::opts_current$get('fig.cap'), '`', sep = '')
} else {
paste('Kept: `', options$fig.cap, '`', sep = '')
}
}
})
opts_chunk$set(autocap = TRUE)
```
## No Plot
```{r textOnly}
1+1
```
## Caption Already Set
```{r someplot, fig.cap='someplot caption'}
plot(0)
```
## Caption Not Set
```{r anotherPlot}
plot(1)
```
Is it ok like this ? I simply modify the knitr internal function .img.cap function which can be found here.
```{r}
.img.cap = function(options) {
if(is.null(options$fig.cap)) options$label else options$fig.cap
}
assignInNamespace(".img.cap", .img.cap, ns="knitr")
```
Does it help ?
```{r}
library(knitr)
knit_hooks$set(htmlcap = function(before, options, envir) {
if(!before) {
caption <- ifelse(is.character(options$htmlcap), options$htmlcap, options$label)
paste('<p class="caption">', caption, "</p>", sep="")
}
})
```
```{r Hello, htmlcap=TRUE}
library(ggplot2)
ggplot(diamonds,aes(price,carat)) + geom_point()
```
```{r, htmlcap="Hello again"}
ggplot(diamonds,aes(price,carat)) + geom_point()
```