Open jrowen opened 8 years ago
No, that's not possible right now.
On Fri, Aug 5, 2016 at 10:25 AM, Jonathan Owen notifications@github.com wrote:
Is it possible to dynamically build a page using a loop? I've tried the approach below in an 'asis' block, but it doesn't seem to work.
cat(title, ' {data-icon="fa-line-chart"}\n') cat("=====================================\n") cat('\n')
for (i in seq_along(fields)) { if (i %% col_no != 0) { cat("Row\n") cat("-------------------------------------\n") cat('\n') }
cat("### ", fields[[i]], "\n") cat('\n')
create_plot(fields[i]) cat('\n') }
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/rstudio/flexdashboard/issues/80, or mute the thread https://github.com/notifications/unsubscribe-auth/AAGXx17aOQKm-b462HvT1AZ4gxZ9BxaSks5qc0fogaJpZM4Jdu5d .
I think you could take workaround by writing additional script which generates the markdown file dynamically and then render it.
My colleague @eamcvey pointed me here. I was able to autogenerate content by building r chunks explicitly then kniting them inline with r paste(knitr::knit(text = out))
. This amazing line of code was found in an SO post.
In my case, I wanted to produce a series of graphs, each with a separate tab, with different content. Each graph was similar but there were numerous (about 15) and I didn't want to copy/paste all of the separate chunks.
Here is a gist you can download of a more simple example. (The code is also below but note that I add \
before each chunk so that it rendered as a single block of code.) I built a much more complicated function to build graphs, but the idea of the R chunks can be carried forward to any list object containing htmlwidgets as elements.
---
title: "Loop to Auto Build Tabs Containing htmlwidgets"
output: flexdashboard::flex_dashboard
---
\```{r setup, echo =FALSE, eval = TRUE}
library(tidyverse)
library(flexdashboard)
library(highcharter)
labels <- mtcars %>% names # these will serve as labels for each tab
# create a bunch of random, nonsensical line graphs
hcs <- purrr::map(.x = mtcars, ~highcharter::hchart(mtcars, y = .x, type = 'line')) %>%
setNames(labels) # assign names to each element to use later as tab titles
\```
Page
====================
Column {.tabset .tabset-fade}
-----------------------------
<!-- loop to build each tabs (in flexdashboard syntax) -->
<!-- each element of the list object `out` is a single tab written in rmarkdown -->
<!-- you can see this running the next chunk and typing `cat(out[[1]])` -->
\```{r, echo = FALSE, eval = TRUE}
out <- lapply(seq_along(hcs), function(i) {
a1 <- knitr::knit_expand(text = sprintf("### %s\n", names(hcs)[i])) # tab header, auto extracts names of `hcs`
a2 <- knitr::knit_expand(text = "\n```{r}") # start r chunk
a3 <- knitr::knit_expand(text = sprintf("\nhcs[[%d]]", i)) # extract graphs by "writing" out `hcs[[1]]`, `hcs[[2]]` etc. to be rendered later
a4 <- knitr::knit_expand(text = "\n```\n") # end r chunk
paste(a1, a2, a3, a4, collapse = '\n') # collapse together all lines with newline separator
})
\```
<!-- source: https://goo.gl/fnfXuO -->
<!-- As I mentioned in the SO post, I don't quite understand why it has to be -->
<!-- 'r paste(knitr::knit(...)' vs just 'r knitr::knit(...)' but hey, it works -->
`r paste(knitr::knit(text = paste(out, collapse = '\n')))`
This was very helpful, thanks.
@jrowen If you want to have less ugly code (not all of your statements wrapped in knitr::knit_expand()
, and you are willing to have multiple files, you can do this just as you would in a typical markdown document.
For complicated pages, I find a separate document easier to manage.
In your dashboard, you might have this:
```{r run-out, include=FALSE} out = NULL options(knitr.duplicate.label = 'allow') for (i in seq_along(fields)) { out = c(out, knit_expand('mychild.Rmd')) } ```
`r paste(knit_child(text = out), collapse = '')`
and then mychild.Rmd could be (no header information)
`` \### \
r fields[[i]]`
```{r}
create_plot(fields[i])
```
@EMIjess thx for your comment. I used parts of it for a project at work were we needed to dynamically create flexdashboard pages depending on the data for the report.
I basically used a subpage.RMD
template file similar to your mychild.RMD
.
Although the issue was opened some time ago, I want to share a small example with you which might help others: https://somtom.github.io/post/using-dynamically-rendered-r-markdown-childs-for-reports/
@dantonnoriega passed along some good advice. Here is some code that will allow you to produce an arbitrary number of charts side-by-side AKA multiple (2) charts per Row. There doesn't seem to be a lot of info on doing it so here is what I did. I use purrr map over lapply because it is more for-loopy. Note the flexdashboard scroll setting is important for this to work. I'm also converting the ggplots to plotly interactive graphs (that auto-size with flexdashboard).
I'm using this method with my spark_hist function to build a dashboard of histograms for hive tables with sparklyR. Here is my R package if you are interested, hope to have it on CRAN soon. https://github.com/GabeChurch/sparkedatools
---
title: "CC Fraud Distributions"
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: scroll
---
\```{r setup, echo =FALSE, eval = TRUE}
library(flexdashboard)
library(tidyverse)
library(sparklyr)
library(dplyr)
library(plotly)
library(sparkedatools)
Sys.setenv(SPARK_HOME="/usr/hdp/3.1.0.0-78/spark2")
conf = spark_config()
conf$'sparklyr.jars.default'= "/home/gchurch/R/sparkeda_2.11-1.0.0.jar"
conf$spark.default.parallelism=10
sc = spark_connect(master = "yarn-client", config = conf, version = '2.3.2')
\```
\```{r, echo = FALSE, eval = TRUE}
tbl_cache(sc, "sample_data.cc_fraud")
cc_fraud = tbl(sc, sql("select * from sample_data.cc_fraud"))
returned = spark_hist(cc_fraud, 10L, FALSE) %>% map(function(x){
ggplotly(x)
})
out = (1:length(returned)) %>% map(function(i){
a1 = knitr::knit_expand(text = "\nRow \n--------------------------------------------")
a2 <- knitr::knit_expand(text = sprintf("\n### Chart %s\n```{r Chart%s}", i, i)) # start r chunk
a3 <- knitr::knit_expand(text = sprintf("\n returned[[%d]]", i))
a4 <- knitr::knit_expand(text = "\n```\n") # end r chunk
#If i is not divisible by two we will create a new flexdashboard "row"
if (i %% 2) { #odds
paste(a1, a2, a3, a4, collapse = '\n')
}else{ #evens
paste(a2, a3, a4, collapse = '\n')
}
})
\```
`r paste(knitr::knit(text = paste(out, collapse = '\n')))`
Great suggestions and thank you for the answers so far. However, I am currently trying to do the exact same thing in a reactive environment. The plots I am trying to display in each tab depend on user input. The plots are 18 ggplotly-histograms stored in one reactiveValues()-variable named 'plots'. I am able to access each histogram using plots$histogram_10 for example. However, when I try to make these tabs they should be run in a reactive environment. For simplicity I am not trying to run the plots yet but print 'hi' in each tab. I am afraid that knitting the results from the out-variable to Rmd is blocked due to the reactive environment. This is the code I am (partly) using:
```{r, echo = FALSE, eval = TRUE}
out <- reactiveValues()
reactive(out$tab <- lapply(seq_along(plots), function(i) {
a1 <- knitr::knit_expand(text = sprintf("### %s\n", names(plots)[i])) # tab header, auto extracts names of `hcs`
a2 <- knitr::knit_expand(text = "\n```{r}") # start r chunk
a3 <- knitr::knit_expand(text = print('hi')) # extract graphs by "writing" out `hcs[[1]]`, `hcs[[2]]` etc. to be rendered later
a4 <- knitr::knit_expand(text = "\n```\n") # end r chunk
paste(a1, a2, a3, a4, collapse = '\n') # collapse together all lines with newline separator
})
)
```## Aantal patienten per specialisme per jaar {.tabset}
}
<!-- source: https://goo.gl/fnfXuO -->
<!-- As I mentioned in the SO post, I don't quite understand why it has to be -->
<!-- 'r paste(knitr::knit(...)' sometimes vs 'r knitr::knit(...)' but oh well -->
`r reactive({knitr::knit(text = paste(out$tab, collapse = '\n'))})`
I assume the last line is where it goes wrong:
r reactive({knitr::knit(text = paste(out$tab, collapse = '\n'))})
The output I get is, but no new tabs
### Histogram_10 ```{r} hi ``` ### Histogram_11 ```{r} hi ``` ### Histogram_12 ```{r} hi ```
The dashboard also prints 'hi'
three times, but not in seperate tabs.
Help would be much appreciated!!
Great suggestions and thank you for the answers so far. However, I am currently trying to do the exact same thing in a reactive environment. The plots I am trying to display in each tab depend on user input. The plots are 18 ggplotly-histograms stored in one reactiveValues()-variable named 'plots'. I am able to access each histogram using plots$histogram_10 for example. However, when I try to make these tabs they should be run in a reactive environment. For simplicity I am not trying to run the plots yet but print 'hi' in each tab. I am afraid that knitting the results from the out-variable to Rmd is blocked due to the reactive environment. This is the code I am (partly) using:
```{r, echo = FALSE, eval = TRUE} out <- reactiveValues() reactive(out$tab <- lapply(seq_along(plots), function(i) { a1 <- knitr::knit_expand(text = sprintf("### %s\n", names(plots)[i])) # tab header, auto extracts names of `hcs` a2 <- knitr::knit_expand(text = "\n```{r}") # start r chunk a3 <- knitr::knit_expand(text = print('hi')) # extract graphs by "writing" out `hcs[[1]]`, `hcs[[2]]` etc. to be rendered later a4 <- knitr::knit_expand(text = "\n```\n") # end r chunk paste(a1, a2, a3, a4, collapse = '\n') # collapse together all lines with newline separator }) )
```## Aantal patienten per specialisme per jaar {.tabset} } <!-- source: https://goo.gl/fnfXuO --> <!-- As I mentioned in the SO post, I don't quite understand why it has to be --> <!-- 'r paste(knitr::knit(...)' sometimes vs 'r knitr::knit(...)' but oh well --> `r reactive({knitr::knit(text = paste(out$tab, collapse = '\n'))})`
I assume the last line is where it goes wrong:
r reactive({knitr::knit(text = paste(out$tab, collapse = '\n'))})
The output I get is, but no new tabs
### Histogram_10 ```{r} hi ``` ### Histogram_11 ```{r} hi ``` ### Histogram_12 ```{r} hi ```
The dashboard also prints
'hi'
three times, but not in seperate tabs.Help would be much appreciated!!
I am trying to do the same thing. I can't get it to work. It seems the last line "r reactive({knitr::knit(text = paste(out$tab, collapse = '\n'))})
" would not take renderPlotly. Any help would be much appreciated!
Has anyone subsequently worked out how to knit as above within a reactive environment?
Is it possible to dynamically build a page using a loop? I've tried the approach below in an 'asis' block, but it doesn't seem to work.
There's a similar question on Stack Overflow.