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.
Related
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've got a package that has a shiny app included. I would like to include a link in the app to open the vignette. I'd prefer to have the link directly open the user's version of the vignette (ie...I'd rather not have to maintain a copy of the vignettes online somewhere). I'm not sure the package will ever go to CRAN, so I don't want to depend on a CRAN link either (and the shiny app will only ever be run locally). I've tried this is the ui code:
vig_path <- system.file("doc", package="myPackage")
HTML(paste0("Introduction"))
When copy the link location and paste it in the browser (ie, from "Inspect" via Chrome dev tools), it opens (so, the path is correct). There is an error "Not allowed to load local resource:". So, am I just out of luck, or is there a trick to open local files that I'm missing?
Well, most of the magic for showing vignettes in R happens in the utils:::print.vignette function. This function can get the URL for the help page using R's built-in help system. Unfortunately it doesn't seem to make it easy to extract this URL from the function itself. But we can cut out the guts and wrap it ourselves. For example
get_vignette_link <- function(...) {
x <- vignette(...)
if (nzchar(out <- x$PDF)) {
ext <- tools::file_ext(out)
port <- if (tolower(ext) == "html")
tools::startDynamicHelp(NA)
else 0L
if (port > 0L) {
out <- sprintf("http://127.0.0.1:%d/library/%s/doc/%s",
port, basename(x$Dir), out)
return(out)
}
}
stop("no html help found")
}
And we can use it like
get_vignette_link("programming", package="dplyr")
and that should return the URL for that vignette. It takes the same parameters as the ?vignette function does. You can then use that to create a link in your Shiny app. For example
library(shiny)
ui <- fluidPage(
htmlOutput("text")
)
server <- function(input, output) {
output$text <- renderUI({
a("dplyr programming vignette",
href=get_vignette_link("programming", package="dplyr"))
})
}
shinyApp(ui = ui, server = server)
Because you are going through R's HTML help server, you don't have to access the local file path so you shouldn't get permission errors.
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)
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
Running the following minimal case:
library(shiny)
runApp(list(
ui = bootstrapPage(downloadButton("myDownload")),
server = function(input, output) {
output$myDownload <- downloadHandler(
filename = function() "mtcars.txt",
content = function(file) write.table(mtcars, file),
contentType = ".txt"
)
}
))
which looks like:
yields the below error in Internet Explorer 8.0.7601 when I click the download button:
Anyone know why this is happening?
Cannot recreate the problem, since I do not have IE 8. But I have remembered this thread, which talks about incompatibilty of shiny with Internet explorer lower than 10:
shiny-discuss/websockets
So I would suggest you upgrade your browser (your code works on my Internet Explorer 10, for example.)
does your code works with other browser like firefox or chrome? Past i have faced similar problem in download data thing. in downloadHandaler where data is getting generated i have assigned it as a global variable. after that is started working, i guess.