В R shiny, как встроить функцию observeEvent в раздел renderUI?

#r #shiny

Вопрос:

У меня возникли проблемы при работе с renderUI в Shiny.

В приведенном ниже коде MWE у пользователя есть возможность изменить входные данные для слайдера ( periods ) и первой сетки матрицы ( base_input ) из их значений по умолчанию (для этого MWE активирована только 1-я строка этой матрицы x1, строка «A»).

Пользователь также может создать многопеременный вектор для этой переменной «A», нажав кнопку «Показать» и вставив значения во 2-ю матрицу ( vector_input ), которая появляется на той же боковой панели. Это прекрасно работает. По мере изменения входных данных в ползунке и первой строке/столбце матрицы x1 (если матрица x2 появилась, нажав «Показать»), 1-я строка матрицы x2 отражает эти изменения реактивно, что и должно работать. (Обратите внимание, что для ввода в эту 2 — ю матрицу вы должны 1-й раз щелкнуть и ввести в правый столбец перед вводом в левый столбец-это связано с незначительной ошибкой в shinyMatrix, для которой у меня есть исправление, но еще не реализовано).

Мой вопрос: как я могу адаптировать это так, чтобы изменения в слайдере и матрице x1 отражались в матрице x2 ПЕРЕД нажатием кнопки ПОКАЗАТЬ, которая запускает renderUI?

Поэтому, если пользователь внес какие-либо изменения во входные данные слайдера/матрицы x1 перед нажатием кнопки ПОКАЗАТЬ, а затем нажал кнопку ПОКАЗАТЬ, то эти изменения в слайдере/матрице x1 уже отражены в матрице x2.

Кажется, что приведенное ниже событие, связывающее слайдер/матрицу x1 с матрицей x2, должно быть встроено в раздел renderUI, чтобы выполнить вышеуказанную работу, но когда я пытаюсь это сделать, это не работает. Есть какие-нибудь решения?

Кроме того, я не хочу нажимать на кнопку «Скрыть», чтобы сбросить значения по умолчанию в этой матрице 2.

Я публикую несколько изображений ниже, чтобы сделать это более понятным.

Ниже приведен код MWE:

 library(shiny)
library(shinyMatrix)
library(shinyjs)

ui <- 
  pageWithSidebar(
    headerPanel("Model..."),
    sidebarPanel(
      conditionalPanel(condition="input.tabselected==2",
          sliderInput('periods','',min=1,max=120,value=60),
          matrixInput(
            "base_input",
            value = matrix(c(0.2), 4, 1, dimnames = list(c("A","B","C","D"),NULL)),
            rows = list(extend = FALSE,  names = TRUE),
            cols = list(extend = FALSE, names = FALSE, editableNames = FALSE),
            class = "numeric"),
                       
          h5(strong("Vectorize variables:")), # Adds a line of text
          # Action buttons to conditionally show/hide performance vectors:
          useShinyjs(),
          actionButton('showPerfVectorBtn','Show',style="width:9vw"), 
          actionButton('hidePerfVectorBtn','Hide',style="width:9vw"),
          uiOutput("Vectors")
      )), # close conditional and sidebar panels
    
  mainPanel(
    tabsetPanel(
      tabPanel("Dynamic", value=2,
               helpText("Dynamic B")),
        id = "tabselected"))
  ) # close page with sidebar

server <- function(input,output,session)({
  # --- Set reactive input variables
  periods       <- reactive(input$periods)
  base_input    <- reactive(input$base_input)
  vector_input  <- reactive(input$vector_input)
  
  # --- Link first row of vector input grids to base_input matrix
  observeEvent(input$periods|input$base_input,{
    updateMatrixInput(session,"vector_input", 
                      value=matrix(c(input$periods,input$base_input[1,1]),1,2, 
                                   dimnames=list(NULL, c("Y","Z")))
    ) # close update matrix
  }) # close observe event
  
  # --- Action buttons to conditionally show/hide performance vectors
  output$Vectors <- renderUI({
    req(input$showPerfVectorBtn)
    tagList(
        matrixInput(
          "vector_input",
          value = matrix(c(1,0.2),1,2,dimnames=list(NULL,c("Y","Z"))),
          rows = list(extend = TRUE,  names = FALSE),
          cols = list(extend = FALSE, names = TRUE, editableNames = FALSE),
          class = "numeric")
    ) # close tag list    
  }) # close render UI
  
  observeEvent(input$showPerfVectorBtn,{shinyjs::show("Vectors")})
  observeEvent(input$hidePerfVectorBtn,{shinyjs::hide("Vectors")})
  # --- Captures inputs as global variables
  observeEvent(periods(), {periods.R <<- periods()})
  observeEvent(base_input(), {base_input.R <<- base_input()})  
  observeEvent(vector_input(), {vector_input.R <<- vector_input()})
}) # close server section

shinyApp(ui, server)
 

введите описание изображения здесь
введите описание изображения здесь

Ответ №1:

Решение намного проще, чем я думал. Я повозился с ним еще немного, внимательно посмотрел на код, чтобы убедиться, что понимаю.

В matrixInput функции, в renderUI функции Server раздела в коде MWE, опубликованном выше, см. строку, которая гласит value = matrix(c(1,0.2),1,2,dimnames=list(NULL,c("Y","Z"))) .

Чтобы это сработало, как описано выше, просто измените определение матрицы в этой строке С c(1,0.2) НА c(input$periods,input$base_input[1,1]) . Это была оплошность с моей стороны. Теперь, с этим изменением определения матрицы, первая строка значений matrix2 полностью реагирует и связана со значениями слайдера (точка) и строки матрицы A (base_input) во всех сценариях использования.