I have a function that reports progress via message(). Under normal use, this is desirable, and the messages can be suppressed via suppressMessages() if desired.
However, I'm writing a vignette (in Rmarkdown) that calls this function, and the results include a full page of these progress updates. I'd like to include the first few lines of messages, but not waste a whole page on them. Is there a way to configure this?
I've tried passing the chunk option R.options=list(max.print=10), as suggested in another answer here, but that doesn't appear to apply to messages. Or at least, not in this context, where the actual messages are generated one or two at a time within each function, but that function is called as part of a loop.
The general structure I'm working with is:
function1 <- function(file.list){
res <- list()
for(i in seq_along(file.list)){
message("processing ", file.list[i])
res[i] <- function2(file.list[i])
}
}
function2 <- function(file){
message("analyzing ", file)
tryVal <- try(res <- analysisFunction(file), silent = TRUE)
if(inherits(tryVal, "try-error")){
message("*** problem with ", file, " ***")
} else {
## additional processing
}
return(res)
}
The markdown chunk looks like this:
```{r batchFlowHist, R.options=list(max.print=10)}
batch1 <- function1(flowPloidyFiles)
```
I'd like my vignette to display the messages from the first few files that are processed, but not the entire loop. Is there some way to do this?
Turns out this is already supported in knitr via the message argument. The linked answer suggested it didn't work, but since that was posted it must have been added. So the following solves my problem:
```{r batchFlowHist, message = 1:10}
batch1 <- function1(flowPloidyFiles)
```
Related
I want to modify the LaTeX environment for figures from \begin{figure}...\end{figure} to \begin{figure*}..\end{figure*} using a custom chunk option (in this case, fullwidth=TRUE ) as a switch. The environment definition is provided by my LaTeX class (sn-jnl).
I came across this example of the hook (modified to suit my case):
hook_plot_output <- knitr::knit_hooks$get("plot")
knitr::knit_hooks$set(plot = function(x, options) {
out <- hook_plot_output(x, options)
if(!is.null(options$fullwidth) && options$fullwidth) {
out <- gsub("\\begin{figure}", "\\begin{figure*}",
gsub("\\end{figure}", "\\end{figure*}", out, fixed=TRUE),
fixed=TRUE)
}
out
})
Here I am capturing the whole output of the function (out) and modifying it. The recommended approach in the book is to only modify the content of x and return the output of the function.
hook_plot_output <- knitr::knit_hooks$get("plot") # save the old hook
knitr::knit_hooks$set(plot = function(x, options) {
if(!is.null(options$fullwidth) && options$fullwidth) {
x <- gsub("\\begin{figure}", "\\begin{figure*}",
gsub("\\end{figure}", "\\end{figure*}", x, fixed=TRUE),
fixed=TRUE)
}
hook_plot_output(x, options)
})
Can someone explain to me why the first approach works and the second one doesn't? It has something to do with the evaluation of the captured hook_plot_output(x, options) in the function's environment, but I can't wrap my head around how to test the difference in behavior between the two cases.
As explained in the book you mentioned, x means a vector of (plot) file paths. There is no LaTeX code like \begin{figure} in x. The LaTeX code is added only after the default plot has been applied.
In your case, you could use the chunk option fig.env = 'figure*', which would be much more simpler than modifying the plot hook. But you didn't provide a minimal reproducible example, and I don't know which type of knitr document you were working on, so I'm not entirely sure if fig.env would work in your case. If it's an Rnw document, this option will work. If it's Rmd, you may need a chunk option out.extra = ''.
I want to create a footer within the float for a figure created with ggplot2 in an rmarkdown document that is generating a .pdf file via LaTeX.
My question: Is there a way within rmarkdown/knitr to add more LaTeX commands within the figure environment?
Specifically, I'd like to find a way to insert custom LaTeX using either the floatrow or caption* macro as described in https://tex.stackexchange.com/questions/56529/note-below-figure within the figure environment.
When I looked at the chunk options (https://yihui.org/knitr/options/#plots), something like out.extra seems close to what I want, but that is used as an extra option to \includegraphics while I want access to put extra LaTeX within the figure environment, outside of any other LaTeX command.
The solution to your question is perhaps quite similar to this one. However, I believe yours is a bit more general, so I'll try to be a bit more general as well...
As far as I know, there's no simple solution to add extra LaTeX code within the figure environment. What you can do is update the knit (or output) hook (i.e. the LaTeX code output generated by the figure chunk).
The source code for the LaTeX figure output hook can be found here (hook_plot_tex). The output generated can be found starting at line 159. Here we can see how the output is structured and we're able to modify it before it reaches the latex engine.
However, we only want to modify it for relevant figure chunks, not all. This is where Martin Schmelzer's answer comes in handy. We can create a new chunk option which allows for control over when it is activated. As an example enabling the use of caption* and floatrow we can define the following knit hook
defOut <- knitr::knit_hooks$get("plot")
knitr::knit_hooks$set(plot = function(x, options) {
#reuse the default knit_hook which will be updated further down
x <- defOut(x, options)
#Make sure the modifications only take place when we enable the customplot option
if(!is.null(options$customplot)) {
x <- gsub("caption", "caption*", x) #(1)
inter <- sprintf("\\floatfoot{%s}\\end{figure}", options$customplot[1]) #(2)
x <- gsub("\\end{figure}", inter, x, fixed=T) #(3)
}
return(x)
})
What we're doing here is (1) replacing the \caption command with \caption*, (2) defining the custom floatfoot text input, (3) replacing \end{figure} with \floatfoot{custom text here}\end{figure} such that floatfoot is inside the figure environment.
As you can probably tell, sky's the limit for what you can add/replace in the figure environment. Just make sure it is added inside the environment and is in the apropriate location. See the example below how the chunk option is used to enable floatfoot and caption*. (You can also split the customplot option into e.g. starcaption and floatfoot by simply dividing up the !is.null(options$customplot) condition. This should allow for better control)
Working example:
---
header-includes:
- \usepackage[capposition=top]{floatrow}
- \usepackage{caption}
output: pdf_document
---
```{r, echo = F}
library(ggplot2)
defOut <- knitr::knit_hooks$get("plot")
knitr::knit_hooks$set(plot = function(x, options) {
x <- defOut(x, options)
if(!is.null(options$customplot)) {
x <- gsub("caption", "caption*", x)
inter <- sprintf("\\floatfoot{%s}\\end{figure}", options$customplot[1])
x <- gsub("\\end{figure}", inter, x, fixed=T)
}
return(x)
})
```
```{r echo = F, fig.cap = "Custom LaTeX hook chunk figure", fig.align="center", customplot = list("This is float text using floatfoot and floatrow")}
ggplot(data = iris, aes(x=Sepal.Length, y=Sepal.Width))+
geom_point()
```
PS
The example above requires the fig.align option to be enabled. Should be fairly easy to fix, but I didn't have the time to look into it.
#henrik_ibsen gave the answer that got me here. I made some modifications to the code that I ended up using to make it work a bit more simply:
hook_plot_tex_footer <- function(x, options) {
x_out <- knitr:::hook_plot_tex(x, options)
if(!is.null(options$fig.footer)) {
inter <- sprintf("\\floatfoot{%s}\n\\end{figure}", options$fig.footer[1])
x_out <- gsub(x=x_out, pattern="\n\\end{figure}", replacement=inter, fixed=TRUE)
}
x_out
}
knitr::knit_hooks$set(plot=hook_plot_tex_footer)
Overall, this does the same thing. But, it uses knitr:::hook_plot_tex() instead of defOut() so that if rerun in the same session, it will still work. And, since it's going into a \floatfoot specifically, I named the option fig.footer. But, those changes are minor and the credit for the answer definitely goes to #henrik_ibsen.
Is there any way when using the str() function in R to start at the beginning of the output provided rather than the end after the function is run?
Basically I'd like a faster way to get to the beginning of the output rather than scrolling manual back up through the output. This would be especially useful when looking at the structure of larger objects like spatial data.
A variation of the answer linked to by Dason (https://stackoverflow.com/a/3837885/1017276) would be to redirect the output to a browser.
view_str <- function(x)
{
tmp <- tempfile(fileext = ".html")
x <- capture.output(str(x))
write(paste0(x, collapse = "<br/>"),
file = tmp)
viewer <- getOption("viewer")
if (!is.null(viewer)) # If in RStudio, use RStudio's browser
{
viewer(tmp)
}
else{ # Otherwise use the system's default browser
utils::browseURL(tmp)
}
}
view_str(mtcars)
Is there a way to test-out and peek at the output of a selected portion of markdown in RStudio? It seems you either run R code or have to compile the entire RMD page in order to see the output.
This is a Windows-only solution and it uses the clipboard instead of the current selection:
Define the following function:
preview <- function() {
output <- tempfile(fileext = ".html")
input <- tempfile(fileext = ".Rmd")
writeLines(text = readClipboard(), con = input)
rmarkdown::render(input = input, output_file = output)
rstudioapi::viewer(output)
}
Then, copy the markdown you want to preview and run preview(). Note that the output might be different from the output in the final document because
the code is evaluated in the current environment
only the copied markdown is evaluated, meaning that the snippet has no context whatsoever.
A solution without using the clipboard will most likely employ rstudioapi::getActiveDocumentContext(). It boils down to something along the lines of a modified preview function
preview2 <- function() {
code <- rstudioapi::getActiveDocumentContext()$selection
# drop first line
# compile document (as in preview())
# stop execution (THIS is the problem)
}
which could be used by running preview() followed by the markdown to render:
preview2()
The value of pi is `r pi`.
The problem is, I don't see how the execution could be halted after calling preview2() to prevent R from trying to parse The value of …. See this related discussion.
Using knitr and R Markdown, I can produce a tabularised output from a matrix using the following command:
```{r results='asis'}
kable(head(x))
```
However, I’m searching for a way to make the kable code implicit since I don’t want to clutter the echoed code with it. Essentially, I want this:
```{r table=TRUE}
head(x)
```
… to yield a formatted tabular (rather than the normal output='markdown') output.
I actually thought this must be pretty straightforward since it’s a pretty obvious requirement, but I cannot find any way to achieve this, either via the documentation or on the web.
My approach to create an output hook fails because once the data arrives at the hook, it’s already formatted and no longer the raw data. Even when specifying results='asis', the hook obtains the output as a character string and not as a matrix. Here’s what I’ve tried:
default_output_hook <- knit_hooks$get('output')
knit_hooks$set(output = function (x, options)
if (! is.null(options$table))
kable(x)
else
default_output_hook(x, options)
)
But like I said, this fails since x is not the original matrix but rather a character string, and it doesn’t matter which value for the results option I specify.
Nowadays one can set df_print in the YAML header:
---
output:
html_document:
df_print: kable
---
```{r}
head(iris)
```
I think other answers are from a time when the following didn't work, but now we can just do :
```{r results='asis', render=pander::pander}
head(x)
```
Or set this for all chunks in the setup chunk, for instance :
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, render=pander::pander)
```
Lacking a better solution I’m currently re-parsing the character string representation that I receive in the hook. I’m posting it here since it kind of works. However, parsing a data frame’s string representation is never perfect. I haven’t tried the following with anything but my own data and I fully expect it to break on some common use-cases.
reparse <- function (data, comment, ...) {
# Remove leading comments
data <- gsub(sprintf('(^|\n)%s ', comment), '\\1', data)
# Read into data frame
read.table(text = data, header = TRUE, ...)
}
default_output_hook <- knit_hooks$get('output')
knit_hooks$set(output = function (x, options)
if (is.null(options$table))
default_output_hook(x, options)
else {
extra_opts <- if (is.list(options$table)) options$table else list()
paste(kable(do.call(reparse, c(x, options$comment, extra_opts))),
collapse = '\n')
}
)
This will break if the R markdown comment option is set to a character sequence containing a regular expression special char (e.g. *), because R doesn’t seem to have an obvious means of escaping a regular expression.
Here’s a usage example:
```{r table=TRUE}
data.frame(A=1:3, B=4:6)
```
You can pass extra arguments to the deparse function. This is necessary e.g. when the table contains NA values because read.table by default interprets them as strings:
```{r table=list(colClasses=c('numeric', 'numeric'))}
data.frame(A=c(1, 2, NA, 3), B=c(4:6, NA))
```
Far from perfect, but at least it works (for many cases).
Not exactly what you are looking for, but I am posting an answer here (that could not fit in a comment) as your described workflow is really similar to what my initial goal and use-case was when I started to work on my pander package. Although I really like the bunch of chunk options that are available in knitr, I wanted to have an engine that makes creating documents really easy, automatic and without any needed tweaks. I am aware of the fact that knitr hooks are really powerful, but I just wanted to set a few things in my Rprofile and let the literate programming tool its job without further trouble, that ended to be Pandoc.brew for me.
The main idea is to specify a few options (what markdown flavour are you using, what's your decimal mark, favorite colors for your charts etc), then simply write your report in a brew syntax without any chunk options, and the results of your code would be automatically transformed to markdown. Then convert that to pdf/docx/odt etc. with Pandoc.