5

I am currently working on a shiny app that runs a series of calculations on a dataset on the fly when someone presses "Calculate". The dataset is very large and a lot of calculations are made via a lapply, which allows the user to track the progress with a progress bar.

This means the generation of the output data frame can be quite slow even when there are potentially results already sitting there just waiting to be displayed. The problem I'm having is that the data is potentially quite time sensitive when something is found and therefore if the calculations take, say, 15 minutes to run, there may have been something to display on the first calculation that is 15 minutes out of date.

Is there a way that after each iteration of the lapply (or feel free to suggest another method) the app can look to see whether there is data there and immediately show it, essentially refreshing the output table after each iteration? Essentially updating the reactive value during the observe rather than after.

I've put below a short example app that may help visualise the problem I'm having:

library(shiny)

testDF <- data.frame(number = c(1:10),
                     letter = letters[1:10])

ui <- fluidPage(
    # UI Input
    numericInput(inputId = "attemptDivide", label = "Number to divide by",
                 value = 1, min = 1, max = 10),

    actionButton(inputId = "calculate", label = "Calculate"),

    # UI Output
    dataTableOutput("dividedTable")

)

# Define server logic
server <- function(input, output) {

    # Create a bucket for results
    results <- reactiveVal()

    # Observe when "Calculate" is pushed and we should work out whether the
    # number is perfectly divisible by the input given
    observeEvent(input$calculate, {

        divisibleDF <- lapply(testDF$number, function(x) {

            # Set to sleep for 1 second to simulate for the the lapply being
            # bigger and taking more time than this example
            Sys.sleep(1)

            # Find the row we're interested in
            interest <- subset(testDF, number == x)

            # Find whether the number is perfectly divisible by the one given
            divisible <- (x / input$attemptDivide) %% 1 == 0

            # If divisible is TRUE we keep, else we return an empty data frame
            if (divisible) {
                return(interest)
            } else {
                return(data.frame(number = integer(), letter = character()))
            }

        }) %>%
            do.call(rbind, .)

        # Save the results to bucket
        results(divisibleDF)

    })

    # Create the table
    output$dividedTable <- renderDataTable({
        results()
    })

}

# Run the app
shinyApp(ui = ui, server = server)

Thanks in advance for any help.

JohnnyB
  • 61
  • 4
  • Here is a solution to similar problem: https://stackoverflow.com/questions/55484581/how-to-update-textoutput-in-r-shiny-within-the-execution-of-an-actionbutton – Ronin scholar Aug 08 '22 at 19:47

0 Answers0