Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R Shiny: Uploading a file on button click

I know that there is quite some material already available on the web to answer my question but none of them seem to work for me. I suppose that's because I do not understand Shiny's reactive programming well.

So, I wish to create an interface that lets a user select a file using fileInput and upload it only on clicking the Upload button. I tried a few solutions from various forums but none worked. Following is my latest attempt:

#ui.R

library(shiny)

shinyUI(pageWithSidebar(


    headerPanel(""),

    sidebarPanel(

            fileInput("in_file", "Input file:",
                    accept=c("txt/csv", "text/comma-separated-values,text/plain", ".csv")),
            checkboxInput(inputId="is_header", label="Does the input file have column names?", value=TRUE),
            actionButton("upload_data", "Upload Data"),
    ),
    mainPanel(
        tabsetPanel(
                    tabPanel("Original Data", tableOutput("orig_data"))
        )
    )
))


#server.R

library(shiny)

shinyServer(function(input, output, session) {

    ra_dec_data <- reactive({
            if(input$upload_data==0)
                    return(NULL)

            return(isolate({
                    head(read_data(input$in_file$datapath, input$in_file$is_header), 50)
            }))
    })

    output$orig_data <- renderTable({
        ra_dec_data()
    })
})

The issue I face is that the file gets uploaded as soon as it is selected and the Upload button is unresponsive.

My guess is that what I have done does not make sense, so please accept my apologies for doing this terribly. Any help would be really appreciated. Thanks!

like image 552
tejas_kale Avatar asked Feb 16 '14 16:02

tejas_kale


1 Answers

fileInput upload the file directly so I suggest you to create your own "fileInput".

Here is how I shall proceed :

Server.R

library(shiny)

shinyServer(function(input, output, session) {

  observe({

    if (input$browse == 0) return()

    updateTextInput(session, "path",  value = file.choose())
  })

  contentInput <- reactive({ 

    if(input$upload == 0) return()

    isolate({
      writeLines(paste(readLines(input$path), collapse = "\n"))
    })
  })

  output$content <- renderPrint({
    contentInput()
  })

})

Ui.R

library(shiny)

shinyUI(pageWithSidebar(

  headerPanel("Example"),

  sidebarPanel(
    textInput("path", "File:"),
    actionButton("browse", "Browse"),
    tags$br(),
    actionButton("upload", "Upload Data")
  ),

  mainPanel(
    verbatimTextOutput('content')
  )

))

In "Server.R" firstly we update the value of the text input each time the action button "Browse" is clicked.

"contentInput" is a reactive function, it will be reexecuted when input values (contained in the body of the function) are changed, "input$upload" here, and not when "input$path" changed because we isolate it. If we didn't isolate the part containing "input$path", the "contentInput" will be reexecuted each times we browse a new file and then the upload button will be useless here.

And then we return the result of "contentInput" in "output$content".

Hope this help.

EDIT ## :

I realized that if you cancel the file choosing it produce an error and the shiny app crash, then you should use this function by Henrik Bengtsson (https://stat.ethz.ch/pipermail/r-help/2007-June/133564.html) :

file.choose2 <- function(...) {
  pathname <- NULL;
  tryCatch({
    pathname <- file.choose();
  }, error = function(ex) {
  })
  pathname;
}
like image 135
Julien Navarre Avatar answered Oct 28 '22 01:10

Julien Navarre