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 fromx1
,x2
andx3
. The figures are produced but not included into the document because offig.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 callinginclude_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:
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
When Writing My Own R Package, I Can't Seem to Get Other Packages to Import Correctly
How to Replace Numeric Codes with Value Labels from a Lookup Table
Use a Factor Column in "By" and Do Not Drop Empty Factors
Object.Size() Reports Smaller Size Than .Rdata File
Error in Unserialize(Socklist[[N]]):Error Reading from Connection on Unix
Ellipse Containing Percentage of Given Points in R
R, Deep VS. Shallow Copies, Pass by Reference
R Ggplot2 Center Align a Multi-Line Title
How to Insert Pictures into Each Individual Bar in a Ggplot Graph
What/Where Are the Attributes of a Function Object
Produce an Inset in Each Facet of an R Ggplot While Preserving Colours of the Original Facet Content
Shade (Fill or Color) Area Under Density Curve by Quantile
How to Preprocess Features When Some of Them Are Factors
Dplyr Count Number of One Specific Value of Variable
Plot Probability Heatmap/Hexbin with Different Sized Bins
Fill Area Between Two Lines, with High/Low and Dates