Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to prevent the download page from opening in R Shiny?

Once the download button has been clicked in a shiny app, a new page opens initialising the download. However, my download handler takes some time to produce the downloadable file which is shown in a progress bar on the main shiny page. Is there a way to keep the user on the main page or to prevent the download page from opening or postponing the download page till the file has been produced?

Many Thanks

Marcus

like image 381
steinbock Avatar asked Jan 29 '14 08:01

steinbock


2 Answers

Vincent's solution using two buttons, an action button for the calculation and a download button for the download is the one I went with. An additional bonus to this solution is the progress bar that also comes in the shinyIncubator package.

An explanation of my code incase someone else wants to do the same thing:

The ui.R has an action button and a dynamic download button:

actionButton("makePlots", "Calculate Results"),
uiOutput("download_button")

and a progress initialisation for the progress bar:

  mainPanel(
    progressInit(),
      uiOutput("mytabs")) # dynamic rendering of the tabs

The server.R is a little more complex. So that the download button is only shown when there is something to download I used the dynamic uiOutput with the following code:

    output$download_button <- renderUI({
          if(download){
              downloadButton("downloadPlots", "Download Results")
          }
     })

The download button is only shown when download==TRUE. At the start of server.R the variable is initialised: download<-FALSE

As the action button increases by 1 everytime it is clicked I included a counter (initial value 0) that increases after each "use" of the action button. Reason for this is the first if statement.

makePlots<-reactive({

    if(input$makePlots>counter){ # tests whether action button has been clicked

       dir.create("new_directory_for_output")

       withProgress(session, min=1, max=15, expr={ # setup progress bar

       for(i in 1:15){

         png(paste0("new_directory_for_output/plot",i,".png"))
         plot(i)
         dev.off()

         setProgress(message = 'Calculation in progress',
              detail = 'This may take a while...',
              value=i)

       } # end for

       }) # end progress bar

       counter<<-counter+1 # needs the <<- otherwise the value of counter
                           # is only changed within the function

       download<<-TRUE     # something to download     

     } # end if

}) # end function

At this stage the function makePlots() doesn't have an output and isn't called anywhere so it does nothing. I therefore placed makePlots() at the beginning of each tab so that no matter which tab the user is on, once the action button has been clicked the plots are made and saved.

The final piece of teh puzzle is the download handler:

output$downloadPlots <- downloadHandler(

    filename = function() { my_filename.zip },
    content = function(file){

      fname <- paste(file,"zip",sep=".") 
      zip(fname,new_directory_for_output) # zip all files in the directory
      file.rename(fname,file)

      unlink(new_directory_for_output,recursive = TRUE) # delete temp directory
      download<<-FALSE # hide download button 
    }

    ) # end download handler
like image 79
steinbock Avatar answered Nov 09 '22 04:11

steinbock


Here is an example of the html code generated for a downloadHandler output :

<a id="downloadData" class="btn shiny-download-link shiny-bound-output" target="_blank" href="session/d832cc1f9218bd9e356572b089628030/download/downloadData?w=">Download</a>

The target attribute specifies where to open the href, target="_blank" opens it in a new tab or new window.

By default (on many browser) when you open a new tab it will focus it, this is what you want to avoid, the problem is that you can't change the client default behaviour with some HTML/JS.

Moreover, change to target="self" will open the href url in the same frame as it was clicked but the problem is that it will close the current session and you need this session openned (a tab with a localhost:port url) to download the datas.

Though, you can add a non-disturbing note that the user could use Ctrl+Click to open the download without focusing the new empty tab.

For example :

helpText("Note : Use Ctrl+Click to open the download in background")
like image 4
Julien Navarre Avatar answered Nov 09 '22 06:11

Julien Navarre