I've run into a problem with downloadHandler() in Shiny:
If I want to download any file via this function, the filename in the download window is the same as the name of the output-variable (in the example: "downloadData"), but not as it is declared in "filename=" in downloadHandler() (which should be "data-2017-02-13.csv").
Note that the following example is from the downloadHandler() - help page, so I guess there is a general problem with R or RStudio in which I write R scripts.
Additionally when I open the shiny app in a web browser, the problem vanishes.
This partially solves it, but I would still like to know why shiny is behaving differently inside RStudio and a web browser.
## Only run examples in interactive R sessions
if (interactive()) {
ui <- fluidPage(
downloadLink("downloadData", "Download")
)
server <- function(input, output) {
# Our dataset
data <- mtcars
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(data, file)
}
)
}
shinyApp(ui, server)
}
and here the download window I get:
I had the same issue when I used the RStudio preview window and was able to solve this issue by always opening a browser with the command
runApp(launch.browser = TRUE)
Related
I am trying to render a local image file onto the Shiny app interface using a snippet of the example code provided by Shiny website below:
ui <- fluidPage(
imageOutput("plot3")
)
server <- function(input, output, session) {
# Send a pre-rendered image, and don't delete the image after sending it
# NOTE: For this example to work, it would require files in a subdirectory
# named images/
output$plot3 <- renderImage({
filename <- normalizePath(file.path('./images',
paste('image', '2', '.jpeg', sep='')))
# Return a list containing the filename
list(src = filename, alt = "Alternate text")
}, deleteFile = FALSE)
}
shinyApp(ui, server)
It didn't work when I ran the application. However when I added back the interactive() function that was originally in the example code, encase the main code body, I was able to display the local image file without any problems.
if (interactive()) {
ui <- fluidPage(
imageOutput("plot3")
)
server <- function(input, output, session) {...
}
This puzzles me as many of Shiny's tutorials and demonstrations showed rendering can be done without encasing the code body in a scope.
Is there anyone who encounter a similar scenario such as this? Rendering a local image file into a Shiny app?
I just discovered what was wrong with the code through trial and error. The directory which the shiny code app is saved in a different location from the location where the image file is saved. So the solution is either to place a setwd([www image folder location]) or relocate image folder www to where the shiny app resides which it worked - the image is successfully rendered.
The data in my shiny application takes a few seconds to be processed.
I have a download button and I would like it to be either unclickable until the data are prepared or have the download handler wait until prepared.
At the moment clicking the download button before 5 secs returns the default html file and then after 5 secs it behaves as expected.
My current solution is to use `shinyjs::hide/show. I’ve shown this below.
Is this best practice? Also, why the shinyjs::useShiny() at the start? It seems unique to that package.
ui <- fluidPage(
shinyjs::useShiny(),
shinyjs::hidden(downloadButton("downloadData", "Download"))
)
server <- function(input, output) {
# Our dataset
data <- mtcars
if(is.null(mtcars)){shinyjs::hide(“downloadData”)}
else{shinyjs::show(“downloadData”)}
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(data, file)}
)
}
shinyApp(ui, server)
What you describe is perfectly reasonable and has been suggested on stackoverflow in the past. You can also use disable/enable instead of hide/show, whatever you feel is a better user experience.
The useShinyjs() is required to set up all the R <--> JavaScript communication that is happening. Without it, when you try to call a shinyjs function from the server, nothing will happen because the UI didn't get initialized with the javascript. Some other pacakges have also adopted this pattern since I made shinyjs, especially packages that also deal with javascript.
I am setting up a Shiny app that allows the user to download a custom dataset. Following the tutorial, I set up the downloadHandler following the example given in the docs (reproduced here, since the same thing happens if I copy and paste this).
ui <- fluidPage(
downloadLink("downloadData", "Download")
)
server <- function(input, output) {
# Our dataset
data <- mtcars
output$downloadData <- downloadHandler(
filename = function() {
paste("data-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(data, file)
}
)
}
shinyApp(ui, server)
Problem:
This issue only comes up on my Linux* system and seems to work just fine on a Mac. The download and everything works just fine, but the "Save" GUI does not offer me the right file name. There is no error message or warning. Based on my input,
I'd expect it to give me data-TIME.csv, i.e. the input to filename. (It does not work either if I give it simple string in that slot).
but it offers me DownloadData or whatever name I give to the output variable (cf. screenshot).
Question:
Is this a OS issue as I suspect, or am I doing something wrong?
How do i fix this? Can I get this to work on any system?
Thanks!
I'm running elementary OS 0.4 Loki, Built on "Ubuntu 16.04.2 LTS", GTK version: 3.18.9. & RStudio 1.0.143
If you are using the Rstudio Browser to test you App this could be the problem. I have the same issue on Windows.
When I use the Rstudio Browser the filename is not properly hand over, but if I use Firefox everything works fine. Your code works also fine in my Firefox.
I am trying to show some PDFs from around the web in an app on shinyapps.io. Unfortunately, the standard way of using an iframe with the URL is not an option because of the mixed-content safeguards (the pdfs are served via http). I think that a possible option is to download the pdfs from the url then display them in an iframe from the local file, but I cannot get this to work with tempfile().
A sample app:
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
textInput("url", "add a url"),
actionButton("button","hit the button"),
h5("use case - embed a pdf user guide in the app - embed as a local pdf or from web URL")
),
mainPanel(
tabsetPanel(
tabPanel("PDF",
htmlOutput("pdf")
)
)
)
)
)
server <- function(input, output, session) {
observeEvent(input$button, {
temp <- tempfile(fileext = ".pdf")
download.file(input$url, temp)
output$pdf <- renderUI({
tags$iframe(src=temp)
})
})
}
shinyApp(ui, server)
Sample pdf: http://www.pdf995.com/samples/pdf.pdf
When I open this in the browser I get an error in the browser console:
Not allowed to load local resource: file:///C:/Users/.../Local/Temp/Rtmp8subWX/file19403a2a2fc8.pdf and nothing in the panel where the iframe is.
A similar attempt uploaded to shinyapps.io failed as well, showing a 404 Not Found error in the pdf viewer.
I think this may be an issue with how shiny/shinyapps.io deal with temp files, but can't quite figure it out. Thanks.
You need to download the PDF in binary mode in a subfolder of your current directory, then call addResourcePath to allow shiny to serve it:
observeEvent(input$button, {
pdf_folder <- "pdf_folder"
if(!file.exists(pdf_folder))
dir.create("pdf_folder")
temp <- tempfile(fileext = ".pdf", tmpdir = "pdf_folder")
download.file(input$url, temp, mode = "wb")
addResourcePath("pdf_folder",pdf_folder)
output$pdf <- renderUI({
tags$iframe(src=temp)
})
})
I am using combination of Shiny and knitr to create PDF documents.
Currently I want to add feature that will allow user to upload picture that will be placed within the created document. However, I am really stuck because I am unable to get the path of the input picture. Could anyone help me with that?
Simple example:
Application:
library(knitr)
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("picture", label = 'Picture'),
downloadButton('report', label = 'Download PDF')
),
mainPanel()
)
)
server <- function(input,output){
picture <- reactive({
input$picture[,4]
})
output$report = downloadHandler(
filename = "test.pdf",
content = function(file){
picture = picture()
out = knit2pdf(input = 'test.Rnw', compiler = 'xelatex', clean = TRUE)
file.rename(out, file)
},
contentType = 'application/pdf'
)
}
shinyApp(ui = ui, server = server)
and the .Rnw document:
\documentclass{article}
\begin{document}
Put picture here:
<<echo = FALSE , message = F, results='asis'>>=
cat(paste('\\includegraphics[height=3in]{', picture,'}'))
#
\end{document}
Part '\includegraphics[height=3in]{', picture,'} is obviously causing the problem, because I do not know the picture path only temporary one.
You said you were working with Shiny Server, then you should be okay with the full path of the picture, even if it is in a temporary directory (because currently Shiny Server only works on Linux, and LaTeX should be okay with Linux file paths like /tmp/...../yourfile.png). The problem is perhaps the datapath (i.e. input$picture[, 4]) does not have the file extension, so LaTeX could not recognize it. You may try to retrieve the filename extension of the original file, and copy the uploaded picture to a temp file with the same extension, e.g.
picture <- reactive({
path1 <- input$picture$datapath
path2 <- tempfile(fileext = gsub('^(.*)([.].+)$', '\\2', input$picture$name))
file.copy(path1, path2, overwrite = TRUE)
path2
})
i see a solution in two ways:
1) copy the temporary file to a folder of your choice and use that image:
observe({
if (is.null(input$picture)) return()
picture<-"your/final/path/to/disk/uploadImage.jpg" # OR do a PASTE with the PATH and the upload file name
file.copy(input$picture$datapath, picture)
if(file.exists(picture)){
# PROCESS THE IMAGE IF NEEDED
}
picture<<-picture # sometimes needed to R to see the variable outside the observe scope
})
2) if you (in this case the R session) are not allowed to write to disk you can turn the image into a base64 variable and include that into your Knitr document (or save it to a database as a string). This takes the Knitr/HTML route if you are willing to take that detour. (R studio running from a server almost always has a lot of restrictions in reading/writing that you can only handle as an ADMIN. And the server runs the shiny session as RStudio and not you so Rstudio must have the read/write permissions needed if you run the Shiny app as an automatic Rstudio Shiny session and not run it directly form RStudio using RUN)
Make sure the base64 is readable by R ouside the 'observe' or 'if' scope again by using '<<-' together with '<-'. Scoping is quite something special with R so be sure to test it properly.
You should dive into this (base64) with sites like:
https://github.com/yihui/knitr/issues/944
https://github.com/yihui/knitr/blob/master/R/utils-base64.R