wrapping figure with latex environment in knitr/rmarkdown with hooks - r

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).

Related

Any way to set rmarkdown::paged_table() as the deafult way to printing table?

I have seen a tutorial by which one can change the way tables are printed to knitr::kable() format. Is it possible to do the same with the rmarkdown::paged_table() format, so that all tables by default will be printed in paged_table() format as in the {rmarkdown} package in R?
I had the same problem in Quarto and the solution is to use df-print: paged (note df-print not df_print) in the yaml file.
Eg.
---
title: "Untitled"
editor: visual
format:
html:
df-print: paged
---
```{r}
data.frame(
x = 1:10,
y = rnorm(10)
)
```
which results in this
In case of Rmarkdown the answer offered by #VishalKatti is IMHO the way to go. For Quarto (or RMarkdown), adapting the example in the R Markdown Cookbook one option to achieve your desired result may look like so:
---
title: Use a custom `knit_print` method to print data frames
format: html
---
First, we define a `knit_print` method, and register it:
```{r}
knit_print.data.frame = function(x, ...) {
res = rmarkdown::paged_table(x)
rmarkdown:::knit_print.data.frame(res)
}
registerS3method(
"knit_print", "data.frame", knit_print.data.frame,
envir = asNamespace("knitr")
)
```
Now we can test this custom printing method on data frames.
Note that you no longer need to call `rmarkdown::paged_table()`
explicitly.
```{r}
head(iris)
```
```{r}
head(mtcars)
```
Put this in the yaml.
output:
html_document:
df_print: paged
To complete the answer shared above, here are several ways to achieve this
Using a printing function for knitr
For paged table this would be this function: (which is used internally by rmarkdown for the df_print feature)
paged_print <- function(x, options) {
knitr::asis_output(
rmarkdown:::paged_table_html(x, options = attr(
x,
"options"
)),
meta = list(dependencies = rmarkdown::html_dependency_pagedtable())
)
}
This is similar to the function in the other answer, it is just that rmarkdown:::knit_print.data.frame does more than juts handling paged tables.
Then you could register it in a document so that it is applied by default for any data.frame printing.
registerS3method(
"knit_print", "data.frame", paged_print,
envir = asNamespace("knitr")
)
or use it on chunk basis where you need to print a data.frame in a single value chunk. (
```{r, render = paged_print}
iris
```
More on custom printing method for knitr its vignette
Using option hooks for knitr
A df_print chunk option can also be simulated this way using a option hook
knitr::opts_hooks$set(df_print = function(options) {
if (options$df_print == "paged") {
options$render = paged_print
}
options
})
this will allow something like
```{r, df_print = "paged"}
iris
```
```{r}
iris
```
First table will be shown as paged table
Second table will be show as usual data.frame

Toggle chunk output using "details" HTML tag

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"}
```

How to syntax highlight inline R code in R Markdown?

This question is similar to consistent code html inline and in chunks with knitr. Instead of .Rhtml documents, I want to highlight inline R code in R Markdown documents, e.g., after `r "plot(cars, main = 'A scatterplot.')"` is compiled through rmarkdown, the tokens like plot should be highlighted. By default, R code chunks are syntax highlighted, but there is no way to highlight inline R code.
Here is one solution using the development version of the highr package (devtools::install_github('yihui/highr')). Basically you just define your custom LaTeX commands to highlight the tokens. highr:::cmd_pandoc_latex is a data frame of LaTeX commands that Pandoc uses to do syntax highlighting.
head(highr:::cmd_pandoc_latex)
## cmd1 cmd2
## COMMENT \\CommentTok{ }
## FUNCTION \\NormalTok{ }
## IF \\NormalTok{ }
## ELSE \\NormalTok{ }
## WHILE \\NormalTok{ }
## FOR \\NormalTok{ }
Then you can redefine the inline hook of knitr:
---
output:
pdf_document:
keep_tex: yes
---
```{r include=FALSE}
local({
hi_pandoc = function(code) {
if (knitr:::pandoc_to() != 'latex') return(code)
if (packageVersion('highr') < '0.6.1') stop('highr >= 0.6.1 is required')
res = highr::hi_latex(code, markup = highr:::cmd_pandoc_latex)
sprintf('\\texttt{%s}', res)
}
hook_inline = knitr::knit_hooks$get('inline')
knitr::knit_hooks$set(inline = function(x) {
if (is.character(x) && inherits(x, 'AsIs')) hi_pandoc(x) else hook_inline(x)
})
})
```
Test inline R code: `r I("plot(cars, main = 'A scatterplot.')")`.
Normal inline code `r pi`.
A code block:
```r
plot(cars, main = 'A scatterplot.')
1 + 2 # a comment
```
I used I() as a convenient marker to tell the character strings to be syntax highlighted from normal character strings. It is just an arbitrary choice. PDF output:
This is not a perfect solution, though. You will need to tweak it in some cases. For example, most special LaTeX characters are not escaped, such as ~. You may need to process the LaTeX code returned by hi_pandoc() by gsub().
Personally I find multiple colors in inline output distracting, so I would not syntax highlighting it, but this is entirely personal taste.
Now-a-days:
Here is some `plot(cars, main = 'A scatterplot.')`{.R} inline R code
Well, I don't know specifically about R and the way you're using it, but for most languages (pandoc uses the skylighting pkg to do this), you can do inline code blocks with the above syntax.

set fig.cap to options$label

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()
```

Chunk reference using knitr, r markdown and pandoc (pander)

I am having trouble trying to reference chunks within a r markdown document which I am trying to convert to .pdf using pandoc.convert.
If I include \label{mylabel} within the text - I can reference this by \ref{mylabel}. However, I thought I might be able to refer to a chunk (or table / figure within a chunk) similarly - but am having no luck.
For instance, for the chunk:
```{r myplot, echo=FALSE, warning=FALSE}
plot(cars)
```
I though I might be able to put \ref{myplot} or \ref{fig:myplot} or even an internal markdown reference [car plot](myplot). The documentation seems to mention that labels are created based on the name of the chunk and these are the formats suggested in relation to similar questions. But none seem to work.
Similarly for tables (which I create using pander) - I have chunks like:
```{r car_sum}
library(pander)
car_summary<-summary(cars)
pander(car_summary, caption = "This is a summary of cars")
```
When converting to .pdf from the .md file using 'pandoc.convert' the tables are given a nice title 'Table 3 This is a summary of cars' and are numbered but I cannot seem to use the label as a reference \ref{car_sum} and it always shows as '??'. Some forums seem to mention that you have to include 'tab:' or 'fig:' before the label name but this still does not work for me.
Can chunk referencing within text be done? If so, what needs to be typed to do this correctly so it works in the final document showing something like 'see Table 2'.
Anything is possible!!
Please see this gist which does what you describe. Just save and knit it to see it in action... For some reason Rpub didn't want to publish it (unknown error).
Testing with converting the knitr generated .html to .pdf via pandoc resulted in working links as well, which is a nice bonus!
The workhorse is::
```{r setup, echo=FALSE, results='hide'}
chunkref <- local({
function(chunklabel) {
sprintf('[%s](#%s)', chunklabel, chunklabel )
}
})
secref <- local({
function(seclabel) {
sprintf('[%s](#%s)', seclabel, seclabel )
}
})
pgref <- local({
function(n)
sprintf('[Page-%i](#Page-%i)', n, n)
})
sec <- local({
function(seclabel) {
sprintf('# <a name="%s"/> %s', seclabel, seclabel )
}
})
pgcount <- local({
pg <- 0
function(inc=T) {
if( inc ) { pg <<- pg + 1 }
return( pg )
}
})
pganchor <- local({
function(doLabel=T) {
if( doLabel) {
sprintf('\n-----\nPage-%i\n<a name="Page-%i"/>\n', pgcount(inc=F), pgcount() )
} else {
sprintf('\n<a name="Page-%i"/>\n', pgcount() )
}
}
})
knit_hooks$set( anchor = function(before, options, envir) {
if ( before ) {
sprintf('<a name="%s"/>\n', options$label )
}
})
knit_hooks$set( echo.label = function(before, options, envir) {
if ( before ) {
sprintf('> %s', options$label )
}
})
knit_hooks$set( pgbreak = function(before, options, envir) {
if ( !before ) {
pganchor();
}
})
````
Which allows for multiple types of references to be created...
Inline: `r sec("Introduction")` then `r secref("Introduction")`
Or
As chunk options:
```{r car-summary, echo=T, warning=FALSE, anchor=T, pgbreak=T, echo.label=F}`
then
`r chunkref("car-summary")`
Even 'top of page' links and 'bottom of page' markers and labels...
Easier solution to referring to figures: put this in the fig.cap field (double \\ to escape the first \):
fig.cap="\\label{mylabel}Caption of my figure."
Then, use \autoref{mylabel} to refer to the figure in the main text.
I am using RStudio with Rmarkdown. Full RMD document:
---
output: pdf_document
---
```{r fig.cap="\\label{mylabel}Caption of my figure."}
plot(1)
```
The generated figure is \autoref{mylabel}.

Resources