I'm working on a Shiny app, in which the user uploads a file, which is then processed to generate a report, which the user can download as an editable Word .doc.
It works as intended, other than that although a "Save As" dialogue window appears which seems to allow you to choose the destination directory, the resulting .doc file ends up being saved to a temporary directory with a randomly-generated name (this is under Windows).
I suspect this is due to the use of the tempdir command, which is part of using rmarkdown to generate the downloaded file.
How should the below code be amended to allow the destination folder to be chosen?
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(shiny)
library(knitr)
# Define UI for application that draws a histogram
ui <- fluidPage(
uiOutput('markdown'),
# Application title
titlePanel("Apptitle"),
# Sidebar with file input
sidebarLayout(
sidebarPanel(
fileInput(
inputId = "file1",
label = "Select file(s)",
multiple = TRUE,
accept = NULL,
width = NULL,
buttonLabel = "Browse...",
placeholder = "No file(s) selected"
),
downloadButton("report", "Generate report")
),
)
)
server <- function(input, output) {
output$report <- downloadHandler(
reactive(file <- input$file1),
filename = "wordreport.doc",
content = function(file) {
tempReport <- file.path(tempdir(), "wordreport.Rmd")
file.copy("wordreport.Rmd", tempReport, overwrite = TRUE)
params <- list(report.data = input$file1)
rmarkdown::render(tempReport, output_file = "wordreport.doc",
params = params,
envir = new.env(parent = globalenv()))
})
}
shinyApp(ui = ui, server = server)
Thank you for your help!
EDIT: Fixed, using the solution below, and the code edits suggested here: Passing a dataframe as a parameter from Shiny app to RMarkdown
You're passing reactive(file <- input$file1) as the contentType argument to downloadHandler(), which can't be good. Also, you're not writing anything to the file given as an argument to the content function.
Remove the reactive(file <- input$file1) line, and specify output_file = file in rmarkdown::render(), and your download should work.
As discussed in the comments, you won't be able to have control over the download path though -- that's something the user's web browser and their settings there will decide.
Here's a somewhat more minimal app with a functioning file download, for reference:
library(shiny)
ui <- fluidPage(
sliderInput("value", "Some value", 1, 5, 2),
downloadButton("report", "Generate report")
)
server <- function(input, output) {
output$report <- downloadHandler(
filename = "wordreport.doc",
content = function(file) {
params <- list(value = input$value)
rmarkdown::render(
system.file("examples/knitr-minimal.Rmd", package = "knitr"),
output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
shinyApp(ui, server)
Related
Hi and thanks for reading me. Im working on a shiny app that renders a markdown report and I discover some html templates that I think look great, but when I tried to make a connection between the shiny app and the markdown document, I get an error message like: Warning in file.create(to[okay]) : cannot create file '/var/folders/9t/w6t7k1zj0_bf2wsqktgnmb1r0000gn/T//RtmpoXq8XC//ejemplo reporte/ejemplo reporte.Rmd', reason 'No such file or directory'. Basically I have the shiny project, and then inside I have another folder with the markdown and their template components, that looks like:
and inside the folder "ejemplo reporte" I have the markdown files, that looks like:
For the shiny app code, is the following:
shinyApp(
ui = fluidPage(
add_busy_spinner(spin = "cube-grid"),
sliderInput("slider", "Slider", 1, 100, 50),
numericInput("perro", "perro", value = 4, min = 1, max = 10),
downloadButton("report", "Generate report")
),
server = function(input, output) {
output$report <- downloadHandler(
filename = "report.pdf",
content = function(file) {
tempReport <- file.path(tempdir(), "ejemplo reporte/ejemplo reporte.Rmd")
file.copy("report.Rmd", tempReport, overwrite = TRUE)
params <- list(n = input$slider,
plot = input$perro
)
rmarkdown::render(tempReport, output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}
)
Is there a way to connect this shiny app to the markdown folder and the markdown file?
Thanks for the help
I'm building a little applet that will run locally, where people can upload a csv and a fillable pdf and the tool will execute a loop that will fill out the pdfs with names from the csv and save them as png files in an /output directory.
I am having trouble with the pdf portion. Using shinyFiles they navigate to the pdf and get its path, but am getting an invalid path error trying to get the pdf fields (staplr). I think it is happening with get_fields but I can't think of another way to get the pdf location.
Warning: Error in path.expand: invalid 'path' argument
[No stack trace available]
Code snip below. Any ideas welcome!
library(tidyverse)
library(staplr)
library(DT)
library(shinyFiles)
library(pdftools)
ui <- fluidPage(
titlePanel(p("Award PDF Creation App", style = "color:#3474A7")),
sidebarLayout(
sidebarPanel(
p("Award Creation Tool"),
# Horizontal line ----
tags$hr(),
fileInput(inputId = "filedata",
label = "Choose your CSV file",
accept = c(".csv")),
shinyFilesButton("pdf", "PDF select", "Please select a PDF", multiple = TRUE, viewtype = "detail"),
tags$p(),
tags$p('Please choose the fillable PDF for award creation.'),
tags$hr()
),
mainPanel(h3("Review your CSV format before you Create PDFs"),
DTOutput(outputId = "table"),
tableOutput("contents"),
actionButton("go", "Create PDFs")
)
)
)
server <- shinyServer(function(input, output, session){
volumes <- c(Home = fs::path_home(), "R Installation" = R.home(), getVolumes()())
shinyFileChoose(input, "pdf", roots = volumes, session = session,
filetypes = c('', 'pdf'))
# by setting `allowDirCreate = FALSE` a user will not be able to create a new directory
pdf <- reactive(input$pdf)
data <- reactive({
req(input$filedata)
read.csv(input$filedata$datapath)
})
pdfpath <- reactive({
req(input$pdf)
as.character(parseFilePaths(volumes,pdf())$datapath)
})
output$table <- renderDT(
data()
)
observeEvent(input$go,{
req(input$filedata)
req(input$pdf)
data <- data()
pdffields <-get_fields(input_filepath = pdfpath, convert_field_names = F)
withProgress(message = 'Making PDFs', value = 0, {
for(i in 1:nrow(data)){
pdffields$`Date`$value <- paste(format(data$AWARD_DATE[i], "%B %d, %Y"))
pdffields$`First Name Last Name`$value <- paste0(data$FIRST_NAME[i], " ", data$LAST_NAME[i])
filename <- paste0('./output/', Sys.Date(),
'_', data$LAST_NAME[i],
'_', data$AWARD[i], '.png')
set_fields(pdf, filename, pdffields)
bitmap <- pdf_render_page(filename, page = 1, dpi = 300)
png::writePNG(bitmap, filename)
# Increment the progress bar, and update the detail text.
incProgress(1/nrow(data), detail = paste("Processing"))
# Pause
Sys.sleep(0.1)
}
})
})
})
shinyApp(ui = ui, server = server)
I have a set of scripts which are run from below, with aspects of the final output influenced by lines 2-4
setwd()
inputyear = ""
inputmonth = ""
dataType = ""
source("1.R")
source("2.R")
source("3.R")
source("4.R")
source("5.R")
#input required file name
saveWorkbook(wb, "Workbook.xlsx", overwrite = TRUE)
I'd like to be able to change the input year, input month, dataType and the name of the workbook produced by the source() 1-5, from a shiny app, and then run the respective files and generate the excel file.
So far I have the following code, which does not produce any errors, but does not function as desired.
I have only included the 'server' section of the code to save space, and this is the part I need help with if possible;
ui<-shinyUI(fluidPage(theme = shinytheme("flatly"),
tags$head(
tags$style(HTML(
".shiny-output-error-validation {
color; green;
}
"))
),
basicPage(
headerPanel("Workbook"),
sidebarPanel(
selectInput("inputmonth","Select Publication Month",c("JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC")),
selectInput("inputyear","Select Year",c("2018/19","2019/20","2020/21")),
selectInput("dataType","Select Version",c("provisional","final"))),
textInput("WorkBookName","Enter File Name (include .xlsx)"),
actionButton("Generate", "Generate Workbook"))
))
server <- function(input, output, session){
observeEvent(input$Generate, {
validate(need(input$WorkBookName != "", "Please enter file name"))
req(input$inputmonth, input$inputyear, input$dataType, input$WorkBookName)
inputyear = input$inputmonth
inputmonth = input$inputyear
dataType = input$dataType
source("1.R",local = TRUE)
source("2.R", local = TRUE)
source("3.R", local = TRUE)
source("4.R", local = TRUE)
source("5.R", local = TRUE)
saveWorkbook(wb, paste0(input$WorkBookName, ".xlsx"), overwrite = TRUE)
})
}
shinyApp(ui, server)
How can I alter the server script to get the desired functionality?
edit: Full script added, sourced names removed
You'll somehow need to trigger the execution of your reactive code. Reactive code only is executed if it was invalidated. Please see this for further information.
In the following app the code will be executed once the Save Workbook button is clicked.
I don't know your UI and sourced R-scripts, so you might want to replace here accordingly:
library(shiny)
library(openxlsx)
library(shinythemes)
ui <- shinyUI(fluidPage(
theme = shinytheme("flatly"),
tags$head(tags$style(
HTML(".shiny-output-error-validation {
color; green;
}
")
)),
basicPage(
headerPanel("Workbook"),
sidebarPanel(
selectInput(
"inputmonth",
"Select Publication Month",
toupper(month.abb)
),
selectInput("inputyear", "Select Year", c("2018/19", "2019/20", "2020/21")),
selectInput("dataType", "Select Version", c("provisional", "final"))
),
textInput("WorkBookName", "Enter File Name (include .xlsx)"),
actionButton("Generate", "Generate Workbook"),
uiOutput("test")
)
))
server <- function(input, output, session) {
observeEvent(input$Generate, {
req(input$inputmonth,
input$inputyear,
input$dataType,
input$WorkBookName)
inputyear = input$inputmonth
inputmonth = input$inputyear
dataType = input$dataType
# source("1.R", local = TRUE)
# source("2.R", local = TRUE)
# source("3.R", local = TRUE)
# source("4.R", local = TRUE)
# source("5.R", local = TRUE)
#
# saveWorkbook(wb, paste0(input$WorkBookName, ".xlsx"), overwrite = TRUE)
output$test <- renderUI("Everything fine...")
})
}
shinyApp(ui, server)
I want a user to download a file which is in tabular format with header along with two search widgets on top. The output is forecasted values along with 80%(High-low) and 95%(High-low) confidence interval.So there are five columns, five rows(default). However, i am having two challenges here.
Challenge 1:
When I run the app, after clicking on "Download the file" filename is coming as download data with no extension whereas I have mentioned filename should be "forecasted" with png extension and it should come as forecated.png
Challenge 2: After typing png as extension while saving the file, the file is saved but nothing gets printed.
I have searched in various forums and try to replicate them but nothing seems to be working.
Please suggest.
shiny UI
library(shiny)
downloadButton(outputId = "downloaddata" ,label ="Download the file"),
shiny server
output$downloaddata<-downloadHandler(
filename = function(){
paste("forecasted","png",sep=",")
},
content = function(file){
png(file)
h <-input$fst
tab<-forecast(Model_mape(),h)
datatable(as.data.frame(tab), options = list(
columnDefs = list(list(targets = c(1, 3), searchable = FALSE)),
pageLength = 10))
dev.off()
}
)
Maybe it could help you (it's a simple instance):
Ui :
library(shiny)
shinyUI(fluidPage(
mainPanel(plotOutput("plot1"),
downloadButton("downloadplot","Download your plot"))
))
Server :
library(shiny)
shinyServer(function(input, output) {
your_plot = function(){
(plot(rnorm(1000,0,1)))
}
output$plot1 <- renderPlot({
your_plot()
})
output$downloadplot <- downloadHandler(
filename = "plot_exemple.png",
content = function(file) {
png(file, width = 1200, height = 800)
print(your_plot())
dev.off()
})
})
With this, you can easily download a png (open it in a browser).
I have created an R shiny application to download dynamic reports using R Markdown. Previously I was downloading one report at a time by selecting the row in the data table in r shiny and clicking on download button, the selected row's column values would get filled in the report, this was working perfectly fine.
But now i am trying to download multiple reports, so that if I select multiple rows in a datatable in r shiny and click on download, the number of reports downloaded should be equal to number of rows selected.
For this I am trying to create a zip file which contains all my individual report but I am getting this
error: pandoc document conversion failed with error 1
I had researched for this error but couldn't find anything. Please help!
ui <- {
tagList(
div(id = "downloadBtn",
downloadButton("downloadData", "Download")),
DT::dataTableOutput('myTable1')
)
}
dataJ <- read.csv(file = "iris.csv", header = TRUE, stringsAsFactors =
FALSE)
server <- function(input, output)
{
output$myTable1 <- DT::renderDataTable({
DT::datatable(dataJ, options = list(orderClasses = TRUE), filter = 'top')})
output$downloadData <- downloadHandler(
filename = function()
{
paste("output", "zip", sep = ".")
},
content = function(file)
{
k = list(input$myTable1_rows_selected)
fs <- c()
for ( i in k)
{
params <- list(j=i)
path <- paste(i,".docx")
rmarkdown::render("R_markdown_script.Rmd", rmarkdown::word_document(),
output_file = path , params = params,
envir = new.env(parent = globalenv()))
fs <- c(fs,path)
}
zip(zipfile = file, files = fs)
if (file.exists(paste0(file, ".zip")))
file.rename(paste0(file, ".zip"), file)
},
contentType = "application/zip" )
}
runApp(list(ui = ui, server = server))
Here is a reproducible example (to make it work, create an rmarkdown file with the default content using RStudio, and save it as "test.rmd" in the same folder as your Shiny app).
Important:
You need to run the app externally inside your web browser. Somehow it does not work in the viewer pane or RStudio window (you get the download window but then no file is saved).
If you are on Windows, you need to make sure that you install RTools first, and also put the rtools/bin folder in your system path.
app.R
library(shiny)
ui <- shinyUI(fluidPage(
titlePanel("Old Faithful Geyser Data"),
sidebarLayout(
sidebarPanel(
downloadButton("downloadData", "Download")
),
mainPanel(
DT::dataTableOutput('myTable1')
)
)
))
server <- shinyServer(function(input, output) {
output$myTable1 <- DT::renderDataTable(iris)
output$downloadData <- downloadHandler(
filename = function() {
paste0("output", ".zip")
},
content = function(file) {
k <- input$myTable1_rows_selected
fs <- c()
for (i in k) {
path <- paste0(i, ".docx")
rmarkdown::render("test.rmd", rmarkdown::word_document(), output_file = path)
fs <- c(fs, path)
}
zip(file, fs)
},
contentType = "application/zip"
)
})
shinyApp(ui = ui, server = server)
Hello I also installed Rtools/bin and was running the code on the web browser, but when I click on download button, download window doesn't comes up and shows '404 Not Found', but when I check the directory, the doc files report are saving directly to directory, no zip file is produced. Please see below code.
ui <- {
tagList(
div(id = "downloadBtn",
downloadButton("downloadData", "Download")),
DT::dataTableOutput('myTable1')
)
}
dataJ <- read.csv(file = "iris.csv", header = TRUE, stringsAsFactors =
FALSE)
server <- function(input, output)
{
output$myTable1 <- DT::renderDataTable({
DT::datatable(dataJ, options = list(orderClasses = TRUE), filter = 'top')})
output$downloadData <- downloadHandler(
filename = ("output.zip"),
content = function(file)
{
k <- (input$myTable1_rows_selected)
fs <- c()
for ( i in k)
{
path <- paste0(i,".docx")
rmarkdown::render("R_markdown_script.Rmd", output_file = path ,
params = list(j=i), envir = new.env(parent = globalenv()))
fs <- c(fs,file)
}
zip(zipfile = file, files = fs)
},
contentType = "application/zip" )
}
runApp(list(ui = ui, server = server))`