Datatable Is Not Printed in Combination with Cat Command in Rmd/Rstudio

Datatable is not printed in combination with cat command in Rmd / RStudio

This is essentially the same issue as knitr#1137. HTML widgets, including DT/DataTables, only work when they are generated from top-level R expressions. This is because only top-level expressions are actually printed. Expressions that are not at the top level are only evaluated. There is a big difference between the two cases. Printing involves calling a printing function. In most cases, this function is, not surprisingly, print() (or show() for S4 objects). In the knitr world, it is more complicated than that: the default printing function is knitr::knit_print, which is very similar to print(), but it does one more thing besides generating the text output, which is collecting the metadata (e.g. HTML dependencies) of the objects being printed. After knitting is done, rmarkdown will resolve the meta data into appropriate HTML code (e.g. <script src="dataTables.js"></script> in <head>).

To sum up, if the expression is not at the top level, neither printing nor metadata collection is done, so there is no way for the widget to be actually rendered.

A simple example to illustrate this:

if (TRUE) {

1:10 # not printed

11:20 # printed because this is the visible value returned by if()

}

How can I embed a plot within a RMarkdown table?

You could do the following (for base plots, not for ggplot2 plots – see comment at the very bottom):

```{r mychunk, fig.show = "hide", echo = FALSE, fig.height=3, fig.width=5}
library(knitr)
# sample data
dat <- data.frame(
text = sapply(1:10, FUN = function(x) { paste0(sample(x = LETTERS, size = 15), collapse = "") }),
x1 = rnorm(10),
x2 = rnorm(10, mean = 3),
x3 = rnorm(10, mean = 5))

# generate plots
invisible(apply(dat[, 2:4], MARGIN = 1, FUN = boxplot))

out <- cbind(row.names(dat),
as.character(dat$text),
sprintf("![](%s%s-%s.png)", opts_current$get("fig.path"), opts_current$get("label"), 1:nrow(dat)))
kable(out, col.names = c("ID", "Text", "Boxplot"))
```
  • apply(dat[, 2:4], MARGIN = 1, FUN = boxplot) generates boxplots using the data from x1, x2 and x3. The figures are produced but not included into the document because of fig.show="hide".
  • sprintf("![](%s%s-%s.png)", opts_current$get("fig.path"), opts_current$get("label"), 1:nrow(dat)) generates the markdown syntax to include the plots. This is similar to calling include_graphics but has the advantage that we get the markdown as character vector.
  • Finally, kable produces the table.

Alternatively, you could produce the table manually, using Pandoc's pipe_table as shown here which gives some more flexibility.

Output of the code above:

Figure in table

Gregor's answer here shows how to apply this to ggplot2 plots: Print the list returned by apply element by element, i.e. invisible(apply(...)) becomes invisible(lapply(apply(...), print)).

Issue plotting multiple d3heatmaps in conditional with knitr

The underlying issue is explained in this answer by Yihui: HTML widgets "only work when they are generated from top-level R expressions". This explains why wrapping the plots in an if statement doesn't work. The second plot is visible nevertheless because if returns the value of the last expression evaluated, thus "raising" the last plot to the top level.

As a solution, the plots can be collected in a list and printed via htmltools::tagList as suggested here:

```{r}
require(d3heatmap)
myVar = TRUE
res <- list()
if (myVar == TRUE) {
res[[1]] <- d3heatmap(mtcars, col = "Spectral")
res[[2]] <- d3heatmap(mtcars, col = "Blues")
}

htmltools::tagList(res)
```

in R, can I stop print(cat()) from returning NULL? and why does cat(foo) return foo

All your answers are in the documentation for ?cat. The portions that answer your specific question are:

Arguments:

fill: a logical or (positive) numeric controlling how the output is
broken into successive lines. If ‘FALSE’ (default), only
newlines created explicitly by ‘"\n"’ are printed.
Otherwise, the output is broken into lines with print width
equal to the option ‘width’ if ‘fill’ is ‘TRUE’, or the value
of ‘fill’ if this is numeric. Non-positive ‘fill’ values
are ignored, with a warning.

... and ...

Value:

 None (invisible ‘NULL’).

So you can't stop print(cat(...)) from returning NULL because that's what cat returns. And you need to explicitly add newlines like cat("foo\n").

How can I get Rmarkdown to include a plot from a window opened by a sourced script?

If you add dev.print() after the source call, it should print the current device (which should, in your case) be the one called by source. This will then be captured by knit and included in the document. So, the chunk should look like this:

```{r}
writeLines( "windows() ; plot(0,0,main='From File')" ,
con="openWindowScript.R" )
source("openWindowScript.R")

dev.print()
```

I tested this on Linux, which uses X11 for both opening a device and printing it, but the documentation appears to imply that it should work the same on Windows (as long as the Windows specific version of dev.print is correctly installed, which it should be by default).

If the dev.print is causing issues when run interactively (either just a nuisance or causing a crash), you can block it from running outside of a knit document by checking the name of the file being knit. This returns NULL when run interactively, so can be used as a condition in if to block execution outside of knitting.

Using the example from the comment about this error, the code chunk becomes:

```{r echo=1:2}
writeLines( "windows() ; plot(0,0,main='Ta-Da!')" ,
con="theScript.R" )
source("theScript.R")

if(!is.null(knitr::current_input())){
deviceInfo <- dev.print()
}
```

A separate approach is to over-write the behavior of windows() (and/or x11). At the top of your Rmd document, add

x11 <- windows <- function(...){invisible(NULL)}

Which should catch all of the calls to windows or x11 and essentially ignore them (the ... ensures that you shouldn't get "unused argument" errors). If you are using those calls to set size and/or aspect ratio, you would need to use fig.width or fig.height instead. This may break other things where you actually want the behavior of x11/windows, but using grDevices::x11 (or similar for windows) would get you the right function. So, if you are in a pinch, and willing to forgo the reason you used windows in the first place, this should work.

Align multiple tables side by side

Just put two data frames in a list, e.g.

t1 <- head(mtcars)[1:3]
t2 <- head(mtcars)[4:6]
knitr::kable(list(t1, t2))

Note this requires knitr >= 1.13.

Using flextable in r markdown loop not producing tables

I'm not sure if this is the correct answer but I used this to solve my problem:

Looping through code in knitr and rmarkdown

Suppress output of a function

It isn't clear why you want to do this without sink, but you can wrap any commands in the invisible() function and it will suppress the output. For instance:

1:10 # prints output
invisible(1:10) # hides it

Otherwise, you can always combine things into one line with a semicolon and parentheses:

{ sink("/dev/null"); ....; sink(); }


Related Topics



Leave a reply



Submit