11.18 Option hooks (*)
Sometimes you may want to change certain chunk options dynamically according to the values of other chunk options. You may use the object opts_hooks
to set up an option hook to do it. An option hook is a function associated with the option and to be executed when a corresponding chunk option is not NULL
. This function takes the list of options for the current chunk as the input argument, and should return the (potentially modified) list. For example, we can tweak the fig.width
option so that it is always no smaller than fig.height
:
knitr::opts_hooks$set(fig.width = function(options) {
if (options$fig.width < options$fig.height) {
options$fig.width <- options$fig.height
}
options
})
Because fig.width
will never be NULL
, this hook function is always executed before a code chunk to update its chunk options. For the code chunk below, the actual value of fig.width
will be 6 instead of the initial 5 if the above option hook has been set up:
```{r fig.width = 5, fig.height = 6}
plot(1:10)
```
As another example, we rewrite the last example in Section 11.12 so we can use a single chunk option console = TRUE
to imply comment = ""
and prompt = TRUE
. Note that console
is not a built-in knitr chunk option but a custom and arbitrary option name instead. Its default value will be NULL
. Below is a full example:
```{r, include=FALSE}
knitr::opts_hooks$set(console = function(options) {
if (isTRUE(options$console)) {
options$comment <- ''; options$prompt <- TRUE
}
options
})
```
Default output:
```{r}
1 + 1
if (TRUE) {
2 + 2
}
```
Output with `console = TRUE`:
```{r, console=TRUE}
1 + 1
if (TRUE) {
2 + 2
}
```
The third example is about how to automatically add line numbers to any output blocks, including source code blocks, text output, messages, warnings, and errors. We have mentioned in Section 5.7 how to use chunk options such as attr.source
and attr.output
to add line numbers. Here we want to use a single chunk option (numberLines
in this example) to control the blocks to which we want to add line numbers.
knitr::opts_hooks$set(
numberLines = function(options) {
attrs <- paste0("attr.", options$numberLines)
options[attrs] <- lapply(options[attrs], c, ".numberLines")
options
}
)
knitr::opts_chunk$set(
numberLines = c(
"source", "output", "message", "warning", "error"
)
)
Basically, the option hook numberLines
appends the attribute .numberLines
to output blocks, and the chunk option numberLines
set via opts_chunk$set()
makes sure that the option hook will be executed.
With the above setup, you can use the chunk option numberLines
on a code chunk to decide which of its output blocks will have line numbers, e.g., numberLines = c('source', 'output')
. Specifying numberLines = NULL
removes line numbers completely.
You may wonder how this approach differs from setting the chunk options directly, e.g., just knitr::opts_chunk$set(attr.source = '.numberLines')
like we did in Section 5.7. The advantage of using the option hooks here is that they only append the attribute .numberLines
to chunk options, which means they will not override existing chunk option values, e.g., the source code block of the chunk below will be numbered (with the above setup), and the numbers start from the second line:
```{r, attr.source='startFrom="2"'}
# this comment line will not be numbered
1 + 1
```
It is equivalent to:
```{r, attr.source=c('startFrom="2"', '.numberLines'}
# this comment line will not be numbered
1 + 1
```