R блестящий: изолировать переменные сеанса

Я пытаюсь изолировать раздел, содержащий значение сеанса session$sendCustomMessage, чтобы я мог отправлять сообщение при нажатии ActionButton. Пользователь загружает файл, после чего становится видимым ActionButton. Только при нажатии кнопки мы должны войти в изолированный раздел server.R. После этого выполняются некоторые вычисления, и файл возвращается пользователю. Однако мне не удается правильно изолировать, и файл возвращается даже без нажатия кнопки ActionButton. Вот мое приложение:

сервер.R:

library(shiny)


shinyServer(function(input, output, session) {


  observe({

    inFile <- input$upload

    if (is.null(inFile))
      return(NULL)

    # Send message indicating that the file is now uploaded
    session$sendCustomMessage("upload_ready", list(fileSize=0))

    # Read the .csv file 
    df = readLines(inFile$datapath)

    # Isolate this section from the reactive context.
    # But this is executing even if the Action Button is not
    # clicked
    isolate({

      # Make this isolated section dependent on the start_proc ActionButton
      input$start_proc

      output$data_file <- downloadHandler(
        filename = function() {
          paste('probabilities-', Sys.Date(), '.txt', sep='')
        }
        ,
        content = function(file1) {
          writeLines(df, con = file1)
        }
      )

      # I think this is the problem, the session changes even if the
      # action button is not clicked, and this is why the code is going
      # into this section.
      session$sendCustomMessage("download_ready", list(fileSize=0))

    })

  })

})

ui.R

library(shiny)
library(shinyBS)

shinyUI(fixedPage(
  singleton(tags$head(HTML(
    '
    <script type="text/javascript">
    $(document).ready(function() {

    // disable download at startup. data_file is the id of the downloadButton

    $("#data_file").attr("disabled", "true").attr("onclick", "return false;");

    // Disable start_prob at the beginning
    $("#start_proc").hide();


    // When uploaded file is ready, give the option to start process
    Shiny.addCustomMessageHandler("upload_ready", function(message) {
    $("#start_proc").show();
    });  

    // When the start_proc button is clicked, hide the button and disable
    // 

    $("#start_proc").click(function(){
    $("#start_proc").hide();
    $("#upload").prop("disabled", true);
    });

    // Show the option to download the file when the download is ready.
    // Also hide the button stat_proc and reactivate the option to upload
    // a file.
    Shiny.addCustomMessageHandler("download_ready", function(message) {
    $("#upload").prop("disabled", false);
    $("#data_file").removeAttr("disabled").removeAttr("onclick").html(
    "<i class=\\"fa fa-download\\"></i>Download Ready");
    });
    })
    </script>
    '
  ))),
   fileInput("upload", ""),
   bsButton("start_proc", h5("Compute Probability\n"), size = "extra-small", style = "primary"),
   downloadButton("data_file"),
   helpText("Download will be available once the processing is completed.")
))

person Cauchy    schedule 19.09.2015    source источник


Ответы (1)


Ваши проблемы совершенно не связаны с переменными сеанса. Единственным событием, которое фактически запускает вычисления, является input$upload. Если загрузка пуста, ваш код попадает в следующие строки

if (is.null(inFile))
  return(NULL)

и все работает как положено. Если файл был загружен, ваша программа достигает изолированного блока. Любая переменная, заключенная с помощью isolate, не считается зависимостью, поэтому следующая часть вашего кода не имеет никакого эффекта, и предположение, которое вы делаете в комментарии, просто неверно:

isolate({
   # Make this isolated section dependent on the start_proc ActionButton
   input$start_proc
   ...
})

Даже если вы поместите input$start_proc за пределы блока isolate, ваш код не будет работать должным образом, поскольку вы не проверяете, была ли вообще нажата кнопка действия.

Один из способов заставить ваш код работать — разделить логику загрузки и загрузки следующим образом:

shinyServer(function(input, output, session) {
    raw <- reactive({
        inFile <- input$upload
        if (is.null(inFile)) return()
        # Read the .csv file 
        readLines(inFile$datapath)
    })

    observe({
        if (is.null(raw())) return() # If input empty return
        # Send message indicating that the file is now uploaded
        session$sendCustomMessage("upload_ready", list(fileSize=0))
    })

    df <- eventReactive(
        input$start_proc, # Button clicked 
        {raw()} # Send data to download handler
    )

    observe({
        if (is.null(df())) return() # In "preprocessed" data empty return

        output$data_file <- downloadHandler(
            filename = function() {
                paste('probabilities-', Sys.Date(), '.txt', sep='')
            },
            content = function(file1) {
                writeLines(df(), con = file1)
            }
        )
        # And send meassage
        session$sendCustomMessage("download_ready", list(fileSize=0))
    })
})
person zero323    schedule 20.09.2015
comment
хорошая идея с разделением вещей. Тем не менее, кнопка щелчка будет постоянно увеличиваться, поэтому простой проверки, равна ли она 0, недостаточно. - person Cauchy; 22.09.2015
comment
Если вы хотите поддерживать более одной загрузки, имеет смысл извлечь логику обработки и обработчик кнопок. - person zero323; 22.09.2015