a current workaround is:
```{r, results="asis"}
for(i in 1:3) {
fig <- list(data=list(list(x=rnorm(100), type="histogram")), layout=list(title=paste(c('plot', i, sep=" "))))
cat(knit_print.offline(fig %>% offline))
}
```
maybe there is an easier way?
It looks like ggvis suffers from the same problem. I have a feeling it's because knitr can only call knit_print() once per chunk. I suppose my advice would be to use subplot() instead
```{r}
n <- 10
df <- data.frame(
x = c(replicate(3, rnorm(n))),
plot = rep(1:3, each = n)
)
df %>%
plot_ly(x = x, group = plot, xaxis = paste0("x", plot),
type = "histogram") %>%
subplot() %>% offline()
```
Looks like @yihui will provide a solution for us :blush:
Here is the easy way:
```{r}
res <- lapply(1:3, function(i) {
fig <- list(data=list(list(x=rnorm(100), type="histogram")), layout=list(title=paste(c('plot', i, sep=" "))))
fig %>% offline
})
htmltools::tagList(res)
```
offline() was deprecated when plotly.js went open source.
Here is the current way to do this:
```
{r}
library(plotly)
htmltools::tagList(lapply(1:3, function(x) { plot_ly(x = rnorm(10)) }))
``````
Or, if you prefer a for loop:
``````
```{r}
l <- htmltools::tagList()
for (i in 1:3) {
l[[i]] <- plot_ly(x = rnorm(10))
}
l
``````
Nice workarround. Unfortunately, I'm not able to use it in my current automated analysis where in each iteration of for loop plotly graphs are followed by tables, results of some statistical tests, etc. Printing all plots in one place would be confusing and not using for loop would mean, that analysis is not automated.
Now it is not clear for me is it a bug/limitation in knitr or in plotly, as I noticed that result of pander() also does not print from inside for loop in .Rmd file?
@GegznaV, what are you using to make the tables? Do you have a small code sample? This can still be made to work with a combination of plotly and tables.
simple example of .Rmd document:
title: "Untitled"
output: html_document
---
``` r, include=FALSE
library(ggplot2)
library(plotly)
library(magrittr)
library(pander)
``` r, warning=FALSE
for(i in c("vs", "am", "gear", "carb")){
print(i)
mtcars$am <- as.factor(mtcars[[i]])
# plot 1
{ggplot(mtcars,aes(x = mpg, y = disp, color = am)) + geom_point()} %>%
ggplotly
# plot 2
{ggplot(mtcars,aes(x = mpg, fill = am)) + geom_density(alpha = .3)} %>%
ggplotly
# table 1
summary(mtcars[,c("mpg","disp",i)]) %>% pander
# table 2: Kruskal-Wallis test
kruskal.test(mtcars$mpg, mtcars[[i]]) %>% pander
}
May be it's possible to save images as .html files and insert them as in this example (section "Slidify"):
https://github.com/garthtarr/pairsD3#slidify
@GegznaV, this is a hack in the ugliest of forms, but it does work. Perhaps, @jcheng5, @ramnath_vaidy, or @yihui can demonstrate an easier way.
``````
---
title: "Untitled"
output: html_document
---
```{r results='asis'}
library(ggplot2)
library(plotly)
library(magrittr)
library(htmltools)
library(pander)
# turn off pander auto asis
pander::panderOptions('knitr.auto.asis', FALSE)
# create a container for our output
output <- list()
# loop through columns
for(i in c("vs", "am", "gear", "carb")){
# get column
mtcars$am <- as.factor(mtcars[[i]])
# plot 1
output[[length(output) + 1]] <- {
ggplot(mtcars,aes(x = mpg, y = disp, color = am)) + geom_point()
} %>% ggplotly %>% as.widget
# plot 2
output[[length(output) + 1]] <- {
ggplot(mtcars,aes(x = mpg, fill = am)) + geom_density(alpha = .3)
} %>% ggplotly %>% as.widget
output[[length(output) + 1]] <- paste0(
capture.output(summary(mtcars[,c("mpg","disp",i)]) %>% pander),
collapse="\n"
)
}
# now cat/print all of the content
for(j in 1:length(output)){
x <- output[[j]]
# we know only character and htmlwidget in this case
# if more need to handle appropriately
if(inherits(x,"character")){
# noquote critical here
# also turn off auto.asis very important
cat(noquote(paste0(x,collapse="\n")))
} else {
# print the html piece of the htmlwidgets
cat(renderTags(x)$html)
}
}
```
```{r echo=FALSE, messages=FALSE, warning=FALSE}
# attach the Dependencies
# since the do not get included with renderTags(...)$html
deps <- lapply(
Filter(function(x){inherits(x,"htmlwidget")},output),
function(hw){
renderTags(hw)$dependencies
}
)
attachDependencies(
tagList(),
unlist(deps,recursive=FALSE)
)
```
``````
https://github.com/ropensci/plotly/issues/273#issuecomment-217982315
@timelyportfolio For printing out html widgets and other things created in a for loop, this process is incredibly involved. Still, it is the closest fit to how I've been using rmarkdown to create dynamic documents. If I want to extend the example given to new options, like datatables or character output without a table in it, what's the best way to figure out what I should looking to put into the print statement? How do you debug such things when testing them out.
Edit: Ok, I think I have datatables figured out. They work the same as ggplotly objects when stored as widgets. By the way thanks for posting this solution.
Thank you @timelyportfolio for your solution. I was trying to get some ggplotly outputs rendered as tabsets from an rmarkdown to html_output, but couldn't figure it out. It was driving me mad. I was able to plot everything with modified form to your solution. Cheers!
Quite an easy way to add tables and plots (and more plots and titles etc.) in a loop in RMarkdown is:
{r, results="asis"}
{r, results='asis'}
htmltools::tagList(plot_ly(x = rnorm(10), type = "histogram"))
for (i in 1:3) {
cat(summary(mtcars[,i]) %>% pander::pander())
cat("\n\n")
print(htmltools::tagList(plot_ly(x = rnorm(10), type = "histogram")))
cat("\n\n")
}
```
You only need to watch out that the plotly libs get included. Therefore I first create a plot outside the loop.
Most helpful comment
Quite an easy way to add tables and plots (and more plots and titles etc.) in a loop in RMarkdown is:
{r, results="asis"}{r, results='asis'}htmltools::tagList(plot_ly(x = rnorm(10), type = "histogram"))
for (i in 1:3) {
cat(summary(mtcars[,i]) %>% pander::pander())
cat("\n\n")
print(htmltools::tagList(plot_ly(x = rnorm(10), type = "histogram")))
cat("\n\n")
}
```
You only need to watch out that the plotly libs get included. Therefore I first create a plot outside the loop.