Conditionally display markup formatted text based on shiny input - r

I'm trying to create an Rmarkdown that displays different amounts of text based on user input into a shiny application. I've made an basic example below. There are 2 text inputs and a checkbox. If the checkbox is false only the 1st text box value is printed to the markdown. If the checkbox is true then both values are printed. I want the output for both text boxes to appear like the 1st textbox output.
Ui:
library(shiny)
library(shinyjs)
ui <- fluidPage(
titlePanel("Hello Shiny!"),
sidebarLayout(
sidebarPanel(
textInput(inputId = "text1",
label = "1st text", value = "1st text"),
checkboxInput(inputId = "checkBox", label = "Checkbox"),
textInput(inputId = "input2",
label = "2nd text", value = "2nd text"),
downloadButton("download", "Download button")
),
mainPanel(
verbatimTextOutput("checkBoxValue")
)
)
)
Server:
library(shiny)
library(shinyjs)
server <- function(input, output) {
output$checkBoxValue <- renderText(input$checkBox)
Text1Value <- reactive({input$text1})
BoxValue<- reactive(input$checkBox)
Input2Value <- reactive({input$input2})
output$download <- downloadHandler(
filename = "Test.docx",
content = function(file) {
tempReport <- file.path(tempdir(), "TestRMD.Rmd")
file.copy("TestRMD.Rmd", tempReport, overwrite = TRUE)
params = list(
Text1Value = Text1Value(),
BoxValue = BoxValue(),
Input2Value = Input2Value()
)
rmarkdown::render(
tempReport,
output_file = file,
params = params,
envir = new.env(parent = globalenv()),
quiet = FALSE
)
})
}
Rmarkdown:
---
title: "Test"
output: word_document
params:
Text1Value: NA
BoxValue: NA
Input2Value: NA
---
```{r echo= FALSE, message = FALSE, include = FALSE}
library(shiny)
library(knitr)
library(latex2exp)
Text1Value<- params$Text1Value
BoxValue<- params$BoxValue
Input2Value<- params$Input2Value
```
# Value for text 1 is `r Text1Value`
```{r, echo=FALSE}
if(BoxValue == TRUE){
"Value for input 2 is `r Input2Value`"
}
```
Currently I can get the text from the second text output to appear conditionally, however it renders looking like R code. I want it to appear in the same format as the output for the 1st text input.
How would I accomplish this?

The the following in your Rmd file. You already are in a code block and don't need to have additional inline r formatting. You can use results = 'asis' in your block and also add the header (#) for identical formatting if you'd like:
```{r, echo=FALSE, results='asis'}
if(BoxValue == TRUE){
cat("# Value for input 2 is", Input2Value)
}
```

Related

How to pass a variable from Shiny app to R Markdown?

In my toy example, I am trying to render Rmd file in the shiny app while passing a variable from Shiny to Rmd. Somehow, the Rmd file is not able to pick the input input$selectInput passed to Rmd file. Can someone show me how to pass a variable from Shiny to Rmd file and print it there?
My intent is to use Rmd file as a template which will be filled by variables from Shiny App at runtime. There may be better alternatives to this approach to render HTML templates in Shiny, do let me know if you know any better approches.
library(shiny)
library(shinydashboard)
library(knitr)
sidebar <- dashboardSidebar(
collapsed = FALSE,
sidebarMenu(
id = "menu_sidebar",
conditionalPanel(
condition = "input.main_tab == 'tab 1'",
selectizeInput(inputId = "selectInput", label = "Choose an option", choices = c("a", "b", "c"), selected = "a", multiple = FALSE),
radioButtons(inputId = "buttons", label = "Choose one:",
choices=c(
"A" = "a",
"B" = "b"))
)
)
)
body <- dashboardBody(
fluidRow(
tabsetPanel(
id = "main_tab",
selected = "tab 1",
tabPanel(title = "tab 1", "Tab content 1",
conditionalPanel("input.buttons == 'a'",
{
knit("text1.Rmd", envir = globalenv(), quiet = T)
withMathJax(includeMarkdown("text1.md"))
},
tags$style("html, body {overflow: visible !important;")),
conditionalPanel("input.buttons == 'b'", htmlOutput("plot_overview_handler"))
)
)
)
)
shinyApp(
ui = dashboardPage(
dashboardHeader(title = "tabBoxes"),
sidebar,
body
),
server = function(input, output) {
output$tabset1Selected <- output$tabset2Selected <- renderText({
input$main_tab
})
output$plot_overview_handler <- renderUI({
pars <- list(variable_1 = input$selectInput)
includeMarkdown(rmarkdown::render(input = "text2.Rmd",
output_format = "html_document",
params = pars,
run_pandoc = FALSE,
quiet = TRUE,
envir = new.env(parent = globalenv())))
})
}
)
Rmd File 1 - text1.Rmd
---
title: "tst2"
output: html_document
runtime: shiny
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
#``` # Uncomment this to run code
## R Markdown
```{r cars}
print(input$selectInput)
#``` # Uncomment this to run code
Rmd File 2 - text2.Rmd
---
title: "tst2"
output: html_document
runtime: shiny
params:
variable_1: NA
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
#``` # Uncomment this to run code
## R Markdown
```{r cars}
print(params$variable_1)
#``` # Uncomment this to run code

How to pass a reactive plot generated in Shiny to Rmarkdown to generate dynamic reports

In short I would like to be able to generate a dynamic Rmarkdown report file (pdf or html) from my shiny app with a button click. For this I thought I will use parameterized Report for Shiny. But somehow I can not transfer the single puzzles to the desired aim:
With this code we can generate and download a reactive radarchart in R Shiny:
library(shiny)
library(radarchart)
js <- paste0(c(
"$(document).ready(function(){",
" $('#downloadPlot').on('click', function(){",
" var el = document.getElementById('plot1');",
" // Clone the chart to add a background color.",
" var cloneCanvas = document.createElement('canvas');",
" cloneCanvas.width = el.width;",
" cloneCanvas.height = el.height;",
" var ctx = cloneCanvas.getContext('2d');",
" ctx.fillStyle = '#FFFFFF';",
" ctx.fillRect(0, 0, el.width, el.height);",
" ctx.drawImage(el, 0, 0);",
" // Download.",
" const a = document.createElement('a');",
" document.body.append(a);",
" a.download = 'radarchart.png';",
" a.href = cloneCanvas.toDataURL('image/png');",
" a.click();",
" a.remove();",
" cloneCanvas.remove();",
" });",
"});"
), collapse = "\n")
ui <- pageWithSidebar(
headerPanel('Radarchart Shiny Example'),
sidebarPanel(
checkboxGroupInput('selectedPeople', 'Who to include',
names(radarchart::skills)[-1], selected="Rich"),
actionButton('downloadPlot', 'Download Plot'),
downloadButton('report', 'Generate Report')
),
mainPanel(
tags$head(tags$script(HTML(js))),
chartJSRadarOutput("plot1", width = "450", height = "300"), width = 7
)
)
server <- function(input, output) {
output$plot1 <- renderChartJSRadar({
chartJSRadar(skills[, c("Label", input$selectedPeople)],
maxScale = 10, showToolTipLabel=TRUE)
})
}
shinyApp(ui, server)
What I would like to do is to implement: Generating downloadable reports https://shiny.rstudio.com/articles/generating-reports.html
The code from this site looks like:
app.R
shinyApp(
ui = fluidPage(
sliderInput("slider", "Slider", 1, 100, 50),
downloadButton("report", "Generate report")
),
server = function(input, output) {
output$report <- downloadHandler(
# For PDF output, change this to "report.pdf"
filename = "report.html",
content = function(file) {
# Copy the report file to a temporary directory before processing it, in
# case we don't have write permissions to the current working dir (which
# can happen when deployed).
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
# Set up parameters to pass to Rmd document
params <- list(n = input$slider)
# Knit the document, passing in the `params` list, and eval it in a
# child of the global environment (this isolates the code in the document
# from the code in this app).
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
)
report.Rmd
---
title: "Dynamic report"
output: html_document
params:
n: NA
---
```{r}
# The `params` object is available in the document.
params$n
```
A plot of `params$n` random points.
```{r}
plot(rnorm(params$n), rnorm(params$n))
```
I have tried a lot like here:
How to pass table and plot in Shiny app as parameters to R Markdown?
Shiny: pass a plot variable to Rmarkdown document when generating a downloadable report
BUT for me it is not possible to transform my code to the provided example code above! The desired output would be something like this after clicking a "Generate Report" button:
Basically your question already included all the building blocks. I only updated the report template to include the code to plot the radar chart. As a parameter I decided to pass the filtered dataset. In the server I only adjusted the specs for the params:
server <- function(input, output) {
output$plot1 <- renderChartJSRadar({
chartJSRadar(skills[, c("Label", input$selectedPeople)],
maxScale = 10, showToolTipLabel=TRUE)
})
output$report <- downloadHandler(
filename = "report.html",
content = function(file) {
tempReport <- file.path(tempdir(), "report.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(scores = skills[, c("Label", input$selectedPeople)])
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
Report.Rmd
---
title: "Dynamic report"
output: html_document
params:
scores: NA
---
```{r}
chartJSRadar(params$scores, maxScale = 10, showToolTipLabel=TRUE)
```

Render rmarkdown to character variable

I am fairly new to R markdown. I have built an app that requires the user to provide multiple inputs to generate a table, which can then be saved locally.
I have been now asked to implement a sort of report to list all the variables inserted by the user (in a sort of formatted document), so that before generating the table one can review all the settings and change them in case of errors.
To avoid major UI restructure, I thought about using a r markdown document and visualize it inside a modal. My problem is that rmarkdown::render renders to an output, while bs_modal takes for the argument body a character (HTML) variable.
Is there a way to make this work? Or are there better way to accomplish this?
A minimal example:
my .Rmd
---
title: "Dynamic report"
output:
html_document: default
pdf_document: default
params:
n : NA
---
A plot of `r params$n` random points.
```{r, echo=FALSE}
plot(rnorm(params$n), rnorm(params$n))
```
My App.R
library(shiny)
library(bsplus)
library(rmarkdown)
shinyApp(
ui = fluidPage(
selectInput(
inputId = "numb",
label = "Label with modal help",
choices = 50:100
),
actionButton(inputId = "mysheet",
label = "Open modal") %>% bs_attach_modal(id_modal = "modal1"),
textOutput("result")
),
server = function(input, output) {
observeEvent(input$mysheet, {
params <- input$numb
md_out <-
rmarkdown::render(
"report.Rmd",
params = params,
envir = new.env(parent = globalenv())
)
bs_modal(
id = "modal1",
title = "Equations",
body = md_out,
size = "medium"
)
})
output$result <- renderText({
paste("You chose:", input$numb)
})
}
)
bs_modal does not work like this, it must be in the UI. Below is a solution using the classical Shiny modal, no bsplus or other package.
library(shiny)
shinyApp(
ui = fluidPage(
selectInput(
inputId = "numb",
label = "Label with modal help",
choices = 50:100
),
actionButton(inputId = "mysheet",
label = "Open modal"),
textOutput("result")
),
server = function(input, output) {
observeEvent(input$mysheet, {
params <- list(n = input$numb)
md_out <-
rmarkdown::render(
"report.Rmd",
params = params,
envir = new.env(parent = globalenv())
)
showModal(modalDialog(
includeHTML(md_out),
title = "Equations",
size = "m"
))
})
output$result <- renderText({
paste("You chose:", input$numb)
})
}
)
Use html_fragment as the Rmd output:
---
title: "Dynamic report"
output:
html_fragment
params:
n : NA
---
A plot of `r params$n` random points.
```{r, echo=FALSE}
plot(rnorm(params$n), rnorm(params$n))
```

R Shiny - Pass user input (text and uploaded image) as parameter to generate report

I am trying to create a shiny application that allows users to enter text and upload an image. I would then like the text inputted by the user and image uploaded by the user to be downloaded as an html report in a similar format only with the headings, text, and image. My aim is to have multiple text boxes and associated images in a report that is downloaded.
I have the following code:
library(shiny)
library(rmarkdown)
ui <-
fluidPage(
titlePanel("QA Template"),
sidebarLayout(
sidebarPanel(
radioButtons('format', 'Document format', c('HTML'),
inline = TRUE),
downloadButton('downloadReport')
)),
mainPanel(
fluidRow(
h2("Presentation"),
column(5,h4("Titles"),
textAreaInput("inText", "Do titles properly convey
content?",height='100px',width='400px')),
column(1,h4("Upload Image"),
fileInput("file1",label="",
accept = c('image/png', 'image/jpeg','image/jpg')
)),
column(4,offset = 1,imageOutput('p1')))))
server <- function(input, output, session) {
inText<-reactive({textAreaInput()})
output$inText<-renderText({textAreaInput()})
file1 <- reactive({gsub("\\\\", "/", input$file1$datapath)})
output$p1<-renderImage({list(src = file1())})
downloadHandler(
filename =
paste("QA_report","file",".html",sep=""),
content = function(file) {
tempReport<-file.path(tempdir(),"QA_report.Rmd")
file.copy('QA_report.Rmd', tempReport,overwrite = TRUE)
##Parameters to pass
params <- list(text1=inText,pic1=file1)
rmarkdown::render(tempReport,output_file=file, params=params,
envir = new.env(parent = globalenv()))
}
)
}
shinyApp(ui = ui, server = server)
I also have this in the .Rmd:
---
title: "QA Template"
output: html_document
params:
text1: NA
pic1: NA
---
```{r include=FALSE}
library(knitr)
```
### Presentation
## Titles
# Do titles properly convey content?
```{r, results='asis',echo=FALSE,warning=FALSE}
print(params[["text1"]])
```
```{r, results='asis',echo=FALSE,warning=FALSE}
knitr::include_graphics(params[["pic1"]])
```
There is a small quirk with using renderImage() we need to set the deleteFile flag to FALSE. Otherwise, the file is read into the temp directory, displayed for the user and then deleted.
Not sure what you were trying to do here but it looks wrong textAreaInput is a UI function. You need to refer to the text flowing into the server with input$inText not output$inText or textAreaInput()
inText<-reactive({textAreaInput()})
output$inText<-renderText({textAreaInput()})
Here is the working code,
library(shiny)
library(rmarkdown)
ui <-fluidPage(
titlePanel("QA Template"),
sidebarLayout(
sidebarPanel(
radioButtons('format', 'Document format', c('HTML'),
inline = TRUE),
downloadButton('downloadReport')
),
mainPanel(
fluidRow(
h2("Presentation"),
column(5,h4("Titles"),
textAreaInput("inText", "Do titles properly convey
content?",height='100px',width='400px')),
column(1,h4("Upload Image"),
fileInput("file1",label="",
accept = c('image/png', 'image/jpeg','image/jpg')
)),
column(4,offset = 1,imageOutput('p1'))
)
)
)
)
server <- function(input, output, session) {
file1 <- reactive({gsub("\\\\", "/", input$file1$datapath)})
output$p1<-renderImage({
req(file1())
browser()
list(src = file1())
},deleteFile = FALSE)
output$downloadReport <- downloadHandler(
filename =
paste("QA_report","file",".html",sep=""),
content = function(file) {
tempReport<-file.path(tempdir(),"QA_report.Rmd")
file.copy('QA_report.Rmd', tempReport,overwrite = TRUE)
##Parameters to pass
params <- list(text1=input$inText,pic1=file1())
rmarkdown::render(tempReport,output_file=file, params=params,
envir = new.env(parent = globalenv()))
}
)
}
shinyApp(ui = ui, server = server)

Shiny: RMarkdown If-statement inside Shiny App

I have a tough time to figure out how i can use if statement inside the .Rmd file or so. I could not find anything on stackoverflow...
I am going explain on the example of this shiny app:
library(shiny)
library(markdown)
library(knitr)
server <- function(input, output) {
output$downloadReport <- downloadHandler(
filename = function() {
paste('my-report', sep = '.', switch(
input$format, PDF = 'pdf', HTML = 'html', Word = 'docx'
))
},
content = function(file) {
src <- normalizePath('report.Rmd')
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'report.Rmd', overwrite = TRUE)
out <- rmarkdown::render('report.Rmd',
params = list(text = input$text),
switch(input$format,
PDF = pdf_document(),
HTML = html_document(),
Word = word_document()
))
file.rename(out, file)
}
)
}
ui <- fluidPage(
tags$textarea(id="text", rows=20, cols=155,
placeholder="Some placeholder text"),
tabPanel("Data",
radioButtons('filter', h3(strong("Auswahlkriterien:")),
choices = list("WerkstoffNr" = 1,
"S-Gehalt" = 2),
selected = 1,inline=TRUE),
conditionalPanel(
condition = "input.filter == '1'",
column(6,
h4("WerkstoffNr auswaehlen:"),
selectInput("select", " ",
choices = seq(1,100,10))),
column(6,
h4("Abmessung auswaehlen:"),
selectInput("abmfrom", "Von:",choices=as.list(seq(20,110,10))),
selectInput("abmto", "Bis:",choices=as.list(seq(20,110,10))),
actionButton("button1", "Auswaehlen"))),
conditionalPanel(
condition = "input.filter == '2' ",
column(6,h4("S-Gehalt auswaehlen:"),
selectInput("sgehalt", "Von:",choices=seq(1,100,10)),
selectInput("sgehalt2", "Bis:",choices=seq(1,100,10))),
column(6,h4("Abmessung auswaehlen:"),
selectInput("abmfrom2", "Von:",choices=as.list(seq(20,110,10))),
selectInput("abmto2", "Bis:",choices=as.list(seq(20,110,10)))))
),
flowLayout(radioButtons('format', 'Document format', c('PDF','HTML', 'Word'),
inline = TRUE),
downloadButton('downloadReport'))
)
shinyApp(ui = ui, server = server)
report.Rmd (it is just this at the moment):
---
title: "Parameterized Report for Shiny"
output: html_document
params:
text: 'NULL'
---
# Some title
`r params[["text"]]`
I would like to inside of my RMarkdown Report to have the input from this part of shiny app:
tabPanel("Data",
radioButtons('filter', h3(strong("Auswahlkriterien:")),
choices = list("WerkstoffNr" = 1,
"S-Gehalt" = 2),
selected = 1,inline=TRUE),
conditionalPanel(
condition = "input.filter == '1'",
column(6,
h4("WerkstoffNr auswaehlen:"),
selectInput("select", " ",
choices = seq(1,100,10))),
column(6,
h4("Abmessung auswaehlen:"),
selectInput("abmfrom", "Von:",choices=as.list(seq(20,110,10))),
selectInput("abmto", "Bis:",choices=as.list(seq(20,110,10))),
actionButton("button1", "Auswaehlen"))),
conditionalPanel(
condition = "input.filter == '2' ",
column(6,h4("S-Gehalt auswaehlen:"),
selectInput("sgehalt", "Von:",choices=seq(1,100,10)),
selectInput("sgehalt2", "Bis:",choices=seq(1,100,10))),
column(6,h4("Abmessung auswaehlen:"),
selectInput("abmfrom2", "Von:",choices=as.list(seq(20,110,10))),
selectInput("abmto2", "Bis:",choices=as.list(seq(20,110,10)))))
)
As we can see there is an If statement inside (concerning filtering option). So it depends on the user which option would like to use to filter the data. I would like to have this option inside of my Report. Just smthg easily like:
if input.filter == 1
Werkstoffnummer: input$select
Abmessung: von input$abmfrom bis input$abmto
else
S : von sgehalt bis sgehalt2
Abmessung: von input$abmfrom2 bis input$abmto2
So in the report will be only printed (if input.filter ==1):
Werkstoffnummer: 1
Abmessung: von 20 bis 30
Thanks so much!
May be I not fully understand you but you can use something like
(example print different text insist on input filter)
---
title: "Untitled"
runtime: shiny
output: html_document
---
```{r eruptions, echo=FALSE}
radioButtons('filter', h3(strong("Auswahlkriterien:")),
choices = list("WerkstoffNr" = 1,
"S-Gehalt" = 2),
selected = 1,inline=TRUE)
conditionalPanel(
condition = "input.filter == '1'",
column(6,
h4("WerkstoffNr auswaehlen:")
))
conditionalPanel(
condition = "input.filter == '2' ",
column(6,h4("S-Gehalt auswaehlen:")))
```
Or use server side ( render UI , like here )
but you cant shared it like static html file :
*"Note: If you are familiar with R Markdown, you might expect RStudio to save an HTML version of an interactive document in your working directory. However, this only works with static HTML documents. Each interactive document must be served by a computer that manages the document. As a result, interactive documents cannot be shared as a standalone HTML file."
Update
If you want download static html
example
report.rmd
---
title: "Untitled"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r ,echo=FALSE}
if(input$filter==1){
h1(paste("1",input$ii))
}else{
h1(paste("2",input$ii))
}
```
Shiny
library(shiny)
ui=shinyUI(fluidPage(
radioButtons('filter', h3(strong("Auswahlkriterien:")),
choices = list("WerkstoffNr" = 1,
"S-Gehalt" = 2),
selected = 1,inline=TRUE),
numericInput("ii","1",0),
downloadButton('downloadReport')
))
server=shinyServer(function(input, output) {
output$downloadReport <- downloadHandler(
filename = function() {
paste('my-report', sep = '.', 'html' )
},
content = function(file) {
src <- normalizePath('report.Rmd')
# temporarily switch to the temp dir, in case you do not have write
# permission to the current working directory
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'report.Rmd')
library(rmarkdown)
out <- render('report.Rmd', html_document())
file.rename(out, file)
}
)
})
shinyApp(ui,server )
Report will contain 1 or 2 insist on radio button and ii input
It sounds like what you want is a template to generate the report. R Markdown is a format for pretty-printing reports rather than generating them.
For report generation, there’s ‹brew›. It lets you generate any file (including R Markdown) using a simple template language. In your case, you could do something like:
<% if (input.filter == 1) { %>
… normal R Markdown code here!
<% } %>
Save this as report.rmd.brew or similar; then, in your report generation code, you need to brew the template before rendering it:
brew::brew('report.rmd.brew', 'report.rmd')
It finds the variables from the current environment by default (this can be configured).

Resources