问题
The shiny app below is taken out of gallery. It allow user to choose a variable, build a linear regression and download report.
What if I do not know in advance how many plots and models user wants to build and include into report. Is it possible to create a report with dynamically added plots?
Server.R
function(input, output) {
regFormula <- reactive({
as.formula(paste('mpg ~', input$x))
})
output$regPlot <- renderPlot({
par(mar = c(4, 4, .1, .1))
plot(regFormula(), data = mtcars, pch = 19)
})
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')
# 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', overwrite = TRUE)
library(rmarkdown)
out <- render('report.Rmd', switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
)
}
ui.R
fluidPage(
title = 'Download a PDF report',
sidebarLayout(
sidebarPanel(
helpText(),
selectInput('x', 'Build a regression model of mpg against:',
choices = names(mtcars)[-1]),
radioButtons('format', 'Document format', c('PDF', 'HTML', 'Word'),
inline = TRUE),
downloadButton('downloadReport')
),
mainPanel(
plotOutput('regPlot')
)
)
)
report.Rmd
Here is my regression model:
```{r model, collapse=TRUE}
options(digits = 4)
fit <- lm(regFormula(), data = mtcars)
b <- coef(fit)
summary(fit)
```
The fitting result is $mpg = `r b[1]` + `r b[2]``r input$x`$.
Below is a scatter plot with the regression line.
```{r plot, fig.height=5}
par(mar = c(4, 4, 1, 1))
plot(regFormula(), data = mtcars, pch = 19, col = 'gray')
abline(fit, col = 'red', lwd = 2)
```
回答1:
Well, it looks like I have found the answer. The problem was in local/global variables. I had to put list initialisation outside server function. Also I had to use <<-
instead of <-
to assign new element to the plot rather than create new plot every time.
Many thanks to Peter Ellis to support!
So, the solution is (I have slightly changed initial code to focus on the important part):
server.R
library(ggplot2); library(shiny); library(grid); library(gridExtra)
plist <- list() # IMPORTANT - outside server function
shinyServer(function(input, output) {
output$regPlot <- renderPlot({
p <- do.call("grid.arrange", c(plotList(),
ncol=floor(sqrt(length(plotList())+1)),
top = "test"))
})
plotList <- eventReactive(input$plt2rprt, {
p <- ggplot(data = mtcars, aes_string(x = input$x, y = "mpg")) +
geom_point()
# isolate(
plist[[length(plist)+1]] <<- p #IMPORTATNT <<- instead of <-
# )
return(plist)
})
output$lengthOfList <- renderText({length(plotList())})
output$lll <- renderText({length(plist)})
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)
library(rmarkdown)
out <- render('report.Rmd', switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
)
}) #ShinyServer
ui.R
fluidPage(
title = 'Download a PDF report',
sidebarLayout(
sidebarPanel(
helpText(),
selectInput('x', 'Build a regression model of mpg against:',
choices = names(mtcars)[-1]),
actionButton("plt2rprt", label = "Include into report"),
hr(),
radioButtons('format', 'Document format', c('PDF', 'HTML', 'Word'),
inline = TRUE),
downloadButton('downloadReport')
),
mainPanel(
plotOutput('regPlot'),
#verbatimTextOutput("count"),
hr(),
textOutput("lengthOfList"),
textOutput("lll"),
helpText("test-test-test")
)
)
)
report.Rmd
Length of list of plots `r length(plotList())`
```{r plot, fig.height=5}
do.call("grid.arrange", c(plotList(),
ncol=floor(sqrt(length(plotList())+1)),
top = "test"))
```
来源:https://stackoverflow.com/questions/41350835/is-it-possible-to-create-user-defined-report-from-shiny-app