I have a large Shiny application that has a number of prompts, then generates tables and plot based on those inputs. I don't use rmarkdown or knitr or anything to format the output. I just use the standard Shiny elements (sidebarPanel, mainPanel, etc.). For the plots and tables I use the standard reactive renderPlot and renderTable objects. I'm looking for an easy way to have a button called "Export to PDF" that exports the elements on the page to a PDF document.
I've looked into using knitr and rmarkdown to generate a document with some fancy formatting (see here and here for examples). The problem is that it appears that I'll need to regenerate the tables and plots either within the Rmd file or the server.R within a downloadHandler object, and I'd like to avoid that.
Is there any way to output the page as a pdf more easily. More specifically, is there any way to directly reference the output tables and plots (i.e. the output$ objects) from within the Rmd file so that plots and tables don't need to be generated twice.
Edit: Here is some simplified code. Note getDataset() is a reactive function that queries a database based on the inputs. My goal is to simply add an "Export" button that exports the already-generated plots and table. (Also as a side note, is there any way I can get a reactive dataset that is shared among all reactive elements? i.e. not need to have ds <- getDataset() in every object?)
Server
output$hist <- renderPlot({
ds <- getDataset()
# do data transformations
ggplot(ds, aes(val)) +
geom_histogram(binwidth = binSize, aes(fill = ..count..)) +
labs(title = "val dist", x = "val", y = "Count") +
scale_fill_gradient("Count", low = "green", high = "red", guide = FALSE) +
scale_x_continuous(limits = c(min(ds$val), quantile(ds$val, 0.99))) +
geom_hline(yintercept=maxY, linetype=3)
})
output$time <- renderPlot({
ds <- getDataset()
# do data transformations
ggplot(ds, aes(as.POSIXlt(unixTime, origin="1970-01-01", tz="UTC"), val), colour = val) +
scale_y_continuous(limits = c(min(ds$val), quantile(ds$val, 0.99))) +
labs(title = "Val Over Time", x = "Time (UTC)", y = "val (ms)") +
geom_point(alpha = 0.3, size = 0.7) +
geom_smooth()
})
output$stats <- renderTable({
statsDf = getDataset()
# do data transformations
statsDf
})
UI
ui <- fluidPage(
titlePanel("Results"),
sidebarLayout(
sidebarPanel(
dateInput("startDateTime", "Start Date:", value = "2016-10-21"),
textInput("startTime", "Start Time", "00:00:00"),
br(),
dateInput("endDateTime", "End Date:", value = "2016-10-21"),
textInput("endTime", "End Time", value = "02:00:00"),
br(),
submitButton("Submit")
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Plots",
plotOutput("hist"),
plotOutput("time"),
tabPanel("Statistics", tableOutput("stats"))
)
)
)
)
First of all , you should really produce a reproducible example not just a sample of your code. We should copy and paste your code and it will run.
Since you are using ggplot2
which is king of grid
plots, I think one easy option to save plots/tables is to use gridExtra
package. Using grid.arrange
or arrangeGrobs
you can save your grobs to predefined device. Then, downloadhandler will do the download.
To not regenerate all the plots each time, I think one solution is to save them in a global variable that you update each time you change the plot. Here reactiveValues
come in rescue to store plots and tables ad dynamic variable.
library(shiny)
shinyUI(fluidPage(
# Application title
titlePanel("Save ggplot plot/table without regenration"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
downloadButton('export')
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("p1"),
plotOutput("p2"),
tableOutput("t1")
)
)
))
library(shiny)
library(ggplot2)
library(gridExtra)
shinyServer(function(input, output) {
## vals will contain all plot and table grobs
vals <- reactiveValues(p1=NULL,p2=NULL,t1=NULL)
## Note that we store the plot grob before returning it
output$p1 <- renderPlot({
vals$p1 <- qplot(speed, dist, data = cars)
vals$p1
})
output$p2 <- renderPlot({
vals$p2 <- qplot(mpg, wt, data = mtcars, colour = cyl)
vals$p2
})
## same thing for th etable grob
output$t1 <- renderTable({
dx <- head(mtcars)
vals$t1 <- tableGrob(dx)
dx
})
## clicking on the export button will generate a pdf file
## containing all grobs
output$export = downloadHandler(
filename = function() {"plots.pdf"},
content = function(file) {
pdf(file, onefile = TRUE)
grid.arrange(vals$p1,vals$p2,vals$t1)
dev.off()
}
)
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With