Hi @StasK ,
To make sure I understand the objective, the Rmd file will serve as the UI? If so, then the following example might help you get started.
tldr
ui.R
htmlOutput("renderedReport")
server.R
output$renderedReport <- renderUI({
includeMarkdown(knitr::knit('my_file.Rmd'))
})
my_markdown_file.Rmd
## Hello, World!
some text here
..
Overview
I pulled the librarians data set from 538's data repo as an example (1). In this app, I wanted to view the areas with the most employed librarians of chosen US state.
My initial thoughts were to render the report using a shiny input(s) and to trigger the rendering of the report once a button was clicked. I did it this way as it would save on valuable computing time if the app were to be hosted on AWS or Digital Ocean.
The rendering of the rmarkdown will take place on the server side (knitr::knit('my_file.Rmd')
and sent to the ui via renderUI
and includeMarkdown
. On the front end, the markdown output will be received using htmlOutput
.
Using the shinyjs
package, I smoothed the display of the content using hide
and show
.
ui.R
In this example, I'm using the sidebarLayout
and a selectInput
to filter the data by state (USA). After selection is made, the user clicks the View Report
button.
sidebarPanel(
# filter by state
selectInput(inputId = "state",
label = "Choose a state",
choices = c("Choose a state", unique(librarians$prim_state)),
multiple = FALSE),
# button
actionButton(inputId = "report",label="View Report")
)
The mainPanel
is fairly short. I added a loading...
message and wrapped the Rmarkdown output to ease the rendering of the content. Additional styling can be applied to the the report using tags$style
or in separate css file.
...
mainPanel(
# show loading screen
shinyjs::hidden(
tags$div(id="loading",
tags$style("#loading{position:absolute;}"),
tags$h1("Loading..."))
),
# report
tags$div(id="report-wrapper",
tags$style("#report-wrapper p{font-size:14pt;}"),
htmlOutput("renderedReport")
)
)
...
server.R
On the server side, everything is triggered by observeEvent(input$report,{...})
.
The first step is to hide the report div and show the loading message (For fun, the shinycustomloader
package can be used to make cool loading screens (2)).
Next, the data is filtered based on the input. If nothing is selected, the full dataset is returned.
The markdown file is rendered and sent the UI using the following code.
output$renderedReport <- renderUI({
includeMarkdown(knitr::knit("report_template.Rmd"))
})
The final step is to hide the loading message and show the report.
rmarkdown file
I wrote the Rmd file as normal. In the Rmd file, I'm calling the object defined by the filtering step.
Limitations
The beauty of this method is that markdown is fairly straightforward to write and the UI can be modified fairly easy. This could be useful if you are collaborating with non-R folks that are familiar with markdown.
The downsides is that the rendering of the report can be slow. Additional YAML configurations and adjusting the shinyjs hide/show speed might help with the lag. The ggplot outputs were pretty poor. I imagine that manually styling plots via theme(..)
, setting the dpi, and/or css will help make the objects readable.
I didn't test interactive visualizations. I would imagine the same methods for interactive documents would apply here.
I hope this helps!
I posted the full code on github: https://github.com/davidruvolo51/shinyAppTutorials/tree/master/rmarkdown-app
Sources
- 538 Librarian data: https://github.com/fivethirtyeight/data/tree/master/librarians
- Shinycustomloader pkg: https://github.com/emitanaka/shinycustomloader