renderUI and downstream calculation

I am new to shiny and need to use renderUI to create a matrixInput with the dimension depending on the selectInput . The matrixInput will later be used in a downstream calculation, which requires the correct dimension of matrixInput. However, whenever I change the dimension in selectInput, the downstream calculation first uses the old selectInput before trying the new selectInput, producing temporary errors when the old selectInput is used. In other words, the actual workflow seems to be

selectInput -> downstream calculation -> matrixInput created from renderUI -> downstream calculation

I would like the workflow to be

selectInput -> matrixInput created from renderUI -> downstream calculation

How can I enforce this sequence of updates? Please see below for a reproducible example. Thank you for your help!

library(shiny)

ui <- fluidPage(
  selectInput(
    "kMax", "Number of stages",
    choices = seq_len(6), selected = 2),
  
  uiOutput("timing"),
  
  verbatimTextOutput("text"),
)

server <- function(input, output, session) {
  output$timing <- renderUI({

    shinyMatrix::matrixInput(
      "timing",
      label = "Analysis timing",
      value = matrix(seq_len(input$kMax)/as.numeric(input$kMax),
                     ncol=1,
                     dimnames = list(paste0("Look ", seq_len(input$kMax)),
                                     "Information time")),
      inputClass = "numeric",
      rows = list(names=TRUE, extend=FALSE),
      cols = list(names=TRUE, extend=FALSE))
  })
  
  
  output$text <- renderPrint({
    if (length(input$timing[,1]) != input$kMax) {
      stop("Incorrect length for analysis timing")
    }
    
    as.vector(input$timing[,1], "numeric") 
  })
  
}

shinyApp(ui, server)

I'd try to avoid re-rendering the matrixInput via renderUI and use updateMatrixInput instead. Using update* functions usually is faster than re-rendering.

To avoid passing invalid values while updating the input you can use freezeReactiveValue.

Please also check the "Dynamic UI" section from "Mastering Shiny" in this context.

library(shiny)
library(shinyMatrix)

ui <- fluidPage(
  selectInput(
    "kMax",
    "Number of stages",
    choices = seq_len(6),
    selected = 2
  ),
  shinyMatrix::matrixInput(
    "timing",
    label = "Analysis timing",
    value = matrix(),
    inputClass = "numeric",
    rows = list(names = TRUE, extend = FALSE),
    cols = list(names = TRUE, extend = FALSE)
  ),
  verbatimTextOutput("text"),
)

server <- function(input, output, session) {
  observe({
    freezeReactiveValue(input, "timing")
    updateMatrixInput(
      session,
      inputId = "timing",
      value = matrix(
        seq_len(input$kMax) / as.numeric(input$kMax),
        ncol =
          1,
        dimnames = list(paste0("Look ", seq_len(input$kMax)),
                        "Information time")
      )
    )
  })
  
  output$text <- renderPrint({
    if (length(input$timing[, 1]) != input$kMax) {
      stop("Incorrect length for analysis timing")
    }
    as.vector(input$timing[, 1], "numeric")
  })
  
}

shinyApp(ui, server)

Thank you very much for the clarification. It works beautifully!

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.