Reputation: 45
My intention is to explore some data visually using a shiny app and then to pass the resulting plot to a Markdown document. My question is similar to these two I found on stackoverflow.
How to pass reactive data as a R markdown parameter?
How to pass table and plot in Shiny app as parameters to R Markdown?
Unfortunately I am not able to figure out how to use the answers provided to solve my problem. I assume I do not understand the functionality of reactive values enough.
In the MWE I use an input slider in order to create some random numbers that should be displayed in the shiny app. Once the plot has been created in the shiny app I need it to be embedded into the Markdown document. Passing the plot as a parameter to the Markdown does not create an error, however the parameter can not be accessed (seems not to exist) in the Markdown document. But if I cancel out the code in the shiny app to display the plot in the app directly, the plot can be passed to the Markdown document as a parameter and be displayed there.
I understand that I could recreate the plot in the Markdown document, as explained in How to pass a plot (renderPlot) from shiny app as parameter to R Markdown?. Still I would like to understand if there is a solution to pass the plot without recreating it.
In order to do so I must understand why displaying the plot in the shiny app prevents it to be passed to the Markdown document. What is it that I do not understand? Please help! Thank you!
MWE: server.R
library(shiny)
shinyServer(function(input, output) {
# create a scatter plot of random numbers
# based on value of input slicer
chart <- reactive({
plot(x = 1:input$dots, y = rnorm(n = input$dots),
xlab = "Numbers", ylab = "Random")
})
# Display the scatter plot in shiny app
# in reaction to actionButton display
observeEvent(eventExpr = input$display,
output$dotPlot <- renderPlot({
chart()
})
)
# Create R-Markdown Report with plot and
# value of input slider as paramters
output$report <- downloadHandler(
filename = "Dot_Report.html",
content = function(file) {
tempReport <- file.path(tempdir(), "Dot_Report.Rmd")
file.copy(from = "Dot_Report.Rmd",
to = tempReport,
overwrite = TRUE)
pars <- list(n = input$dots,
random_plot = reactive(chart()))
rmarkdown::render(input = tempReport,
output_file = file,
params = pars,
envir = new.env(parent = globalenv()))
})
})
MWE: ui.R
library(shiny)
# Define UI for application that displays a Scatter Plot
shinyUI(fluidPage(
# Title
titlePanel("Simple Plot Export"),
# Sidebar with a slider input for number of random numbers
sidebarLayout(
sidebarPanel(
sliderInput("dots",
"Number of Random dots:",
min = 1,
max = 50,
value = 30)
,
actionButton("display", "Display Plot"),
downloadButton("report", "Generate Report")
),
mainPanel(
plotOutput("dotPlot")
)
)
))
MWE: Dot_Report.Rmd
---
title: "Simple Scatter Plot"
output: html_document
params:
n: NA
random_plot: NA
---
```{r, echo = F}
params$random_plot()
Upvotes: 1
Views: 979
Reputation: 33540
The problem here is, that base plots directly draw on a device.
Please see this related answer for workarounds.
Your code is working fine once we switch to e.g. ggplot (only server.R needs to be modified):
library(shiny)
library(ggplot2)
shinyServer(function(input, output) {
# create a scatter plot of random numbers
# based on value of input slicer
chart <- reactive({
DF <- data.frame(x = 1:input$dots, y = rnorm(n = input$dots))
ggplot(data = DF, aes(x = x, y = y)) + geom_point() + xlab("Numbers") + ylab("Random")
})
# Display the scatter plot in shiny app
# in reaction to actionButton display
observeEvent(eventExpr = input$display,
output$dotPlot <- renderPlot({
chart()
})
)
# Create R-Markdown Report with plot and
# value of input slider as paramters
output$report <- downloadHandler(
filename = "Dot_Report.html",
content = function(file) {
tempReport <- file.path(tempdir(), "Dot_Report.Rmd")
file.copy(from = "Dot_Report.Rmd",
to = tempReport,
overwrite = TRUE)
pars <- list(n = input$dots,
random_plot = reactive(chart()))
rmarkdown::render(input = tempReport,
output_file = file,
params = pars,
envir = new.env(parent = globalenv()))
})
})
Edit: Using base plot()
along with recordPlot()
server.R:
# create a scatter plot of random numbers
# based on value of input slicer
chart <- reactive({
plot(x = 1:input$dots, y = rnorm(n = input$dots),
xlab = "Numbers", ylab = "Random")
recordPlot()
})
Some related information - see ?dev.new
and ?dev.copy
:
Only one device is the ‘active’ device: this is the device in which all graphics operations occur. There is a "null device" which is always open but is really a placeholder [...]
Upvotes: 1