es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo modificar la cadena de reactividad para que el último objeto modificado controle otros objetos encadenados?

[Nueva nota 1: código resuelto final publicado en la parte inferior que refleja la solución de ismirsehregal del 03-Dic-2021 y algunos ajustes menores marcados como “ADDED” y “MODIFIED”. ADD se refiere a la solución del problema que encontré cuando se eliminan filas de la matriz 1 después de que se hayan agregado valores a la matriz 2 (como se comenta a continuación), y “MODIFIED” es para hacer que las cabeceras de columna para las matrices 1 y 2 sean iguales (no tenía sentido que tuvieran cabeceras de columnas diferentes).]

Al ejecutar el código a continuación, me gustaría que el último objeto modificado en la cadena de reactividad “controle” o “domine” otros objetos en esa cadena de reactividad. En este código, los objetos reactivos en cadena son “matrix1” y “matrix2”. Las entradas de matrix1 fluyen hacia matrix2, y las entradas a las primeras 2 columnas de matrix2 fluyen hacia matrix1. Como está redactado, las entradas en matrix2 tienen prioridad sobre las entradas en matrix1. Quisiera que cualquiera de las matrices que haya recibido la entrada más reciente tenga prioridad sobre la otra matriz. ¿Puede alguien ayudarme con esto?

Las imágenes al final ayudan a ilustrar.

He intentado usar “isolate()” y otras cosas para tratar de hacer que esto funcione como quiero, pero también he tenido el problema de que las matrices quedan atrapadas en un ciclo en el que los valores rebotan entre las 2 matrices. Todavía no tengo una comprensión completa de “isolate()”.

Código:

library(dplyr)
library(ggplot2)
library(shiny)
library(shinyMatrix)

sumMat <- function(x){return(rep(sum(x,na.rm = TRUE), 10))}

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      matrixInput("matrix1",
                  label = "Matrix 1 (scenario 1):",
                  value = matrix(c(60,5),ncol=2,dimnames=list(NULL,c("X","Y"))),
                  rows = list(extend = TRUE, delete = TRUE),
                  class = "numeric"),
      actionButton(inputId = "showMat2", "Add scenarios"),br(),br(),
    ),
    mainPanel(plotOutput("plot"))
  )
)

server <- function(input, output, session){

  observeEvent(input$matrix1, {
    tmpMat1 <- input$matrix1
    if(any(rownames(input$matrix1) == "")){rownames(tmpMat1) <- paste("Row", seq_len(nrow(input$matrix1)))    }
    isolate(updateMatrixInput(session, inputId = "matrix1", value = tmpMat1))
  })

  observeEvent(input$showMat2,{
    showModal(
      modalDialog(
        matrixInput("matrix2",
                    label = "Matrix 2:",
                    value = input$matrix1,
                    rows = list(extend = TRUE, delete = TRUE),
                    cols = list(extend = TRUE, delta = 2, delete = TRUE, multiheader = TRUE),
                    class = "numeric"),
        footer = tagList(modalButton("Close"))
      ))
    observeEvent(input$matrix2, {
      tmpMat2 <- input$matrix2
      rownames(tmpMat2) <- paste("Row", seq_len(nrow(input$matrix2)))
      colnames(tmpMat2) <- paste("Scenario",rep(1:ncol(tmpMat2),each=2,length.out=ncol(tmpMat2)))
      isolate(updateMatrixInput(session, inputId = "matrix2", value = tmpMat2))
      isolate(updateMatrixInput(session, inputId = "matrix1", value = tmpMat2[,1:2]))
    })
  })

  plotData <- reactive({
    tryCatch(
      lapply(seq_len(ncol(input$matrix1)/2), 
             function(i){
               tibble(
                 Scenario= colnames(input$matrix1)[i*2-1],X=seq_len(10),
                 Y=sumMat(input$matrix1[,(i*2-1):(i*2), drop = FALSE])
               )
             }) %>% bind_rows(),
      error = function(e) NULL
    )
  })

  output$plot <- renderPlot({
    plotData() %>% ggplot() + 
      geom_line(aes(x = X, y = Y, colour = as.factor(Scenario))) +
      theme(legend.title=element_blank())
  })
}

shinyApp(ui, server)

enter image description here

enter image description here

enter image description here

[Nueva nota 1: código resuelto final a continuación]

“`R
sumMat <- function(x) {return(rep(sum(x, na.rm = TRUE), 10))}

ui <- fluidPage(sidebarLayout(
sidebarPanel(
matrixInput(
“matrix1”,
label = “Matrix 1:”, # MODIFIED HEADER
value = matrix(c(60,5),ncol=2,dimnames=list(NULL,rep(“Scenario 1”,2))), # MODIFIED HEADER
rows = list(extend = TRUE, delete = TRUE),
cols = list(multiheader = TRUE), # ADD
class = “numeric”
),
actionButton(inputId = “showMat2”, “Add scenarios”),br(),br(),
),
mainPanel(plotOutput(“plot”))
))

server <- function(input, output, session) {

currentMat <- reactiveVal(isolate(input$matrix1))

observeEvent(input$matrix1, {
tmpMat1 <- input$matrix1
if(any(rownames(input$matrix1)==””)){rownames(tmpMat1)<-paste(“Row”,seq_len(nrow(input$matrix1)))}
updateMatrixInput(session, inputId = “matrix1”, value = tmpMat1)

tmpMat2 <- currentMat()

if(nrow(tmpMat1) > nrow(tmpMat2)){tmpMat2 <- rbind(tmpMat2, rep(NA, ncol(tmpMat2)))}

# ADDED
if(nrow(tmpMat2) > nrow(tmpMat1)){tmpMat1 <- rbind(tmpMat1, rep(NA, ncol(tmpMat1)))}

currentMat(cbind(tmpMat1[drop=FALSE], tmpMat2[,-1:-2,drop=FALSE]))

})

observeEvent(input$showMat2, {
showModal(modalDialog(
matrixInput(
“matrix2”,
label = “Matrix 2:”,
value = currentMat(),
rows = list(extend = TRUE, delete = TRUE),
cols = list(extend = TRUE,delta = 2,delete = TRUE,multiheader = TRUE),
class = “numeric”
),
footer = tagList(modalButton(“Close”))
))
})

observeEvent(input$matrix2, {
tmpMat2 <- input$matrix2
rownames(tmpMat2) <- paste(“Row”, seq_len(nrow(input$matrix2)))
colnames(tmpMat2) <-
paste(“Scenario”, rep(1:ncol(tmpMat2),each = 2,length.out = ncol(tmpMat2)))
currentMat(tmpMat2)
updateMatrixInput(session, inputId = “matrix2”, value = tmpMat2)
updateMatrixInput(session, inputId = “matrix1”, value = tmpMat2[, 1:2, drop = FALSE])
})

plotData <- reactive({ tryCatch( lapply(seq_len(ncol(input$matrix1) / 2), function(i) { tibble( Scenario = colnames(input$matrix1)[i * 2 - 1], X = seq_len(10), Y = sumMat(input$matrix1[, (i * 2 - 1):(i * 2), drop = FALSE]) ) }) %>% bind_rows(),
error = function(e)
NULL
)

Tags:  , ,

Answer

  1. Avatar for davy.ai

    El objetivo de esta tarea es modificar el código dado de tal manera que sea la última matriz introducida la que tenga prioridad sobre la otra matriz. En el código original, las entradas en matrix2 tenían prioridad sobre las entradas en matrix1.

    La solución a esto requiere la creación de un objeto reactiveVal que contenga el estado actual de ambas matrices. Este reactiveVal actúa como un contenedor de estado actual para ambas matrices. Cada vez que ocurre un evento de entrada en matrix1 o matrix2, ambas matrices se actualizan en base a este reactiveVal de estado actual. Específicamente, cuando ocurre un evento de entrada en matrix1, se fusiona el estado actual de matrix2 con matrix1 y se establece como el nuevo estado en el objeto reactiveVal de estado actual. De manera similar, cuando ocurre un evento de entrada en matrix2, se actualiza el objeto reactiveVal de estado actual con el nuevo estado de matrix2.

    A continuación se muestra el código final resuelto que resuelve el problema:

    sumMat <- function(x) {return(rep(sum(x, na.rm = TRUE), 10))}
    
    ui <- fluidPage(sidebarLayout(
      sidebarPanel(
        matrixInput(
          "matrix1",
          label = "Matriz 1:", 
          value = matrix(c(60,5),ncol=2,dimnames=list(NULL,rep("Escenario 1",2))), # ENCABEZADO MODIFICADO
          rows = list(extend = TRUE, delete = TRUE),
          cols = list(multiheader = TRUE), # AGREGADO
          class = "numeric"
        ),
        actionButton(inputId = "showMat2", "Añadir escenarios"),br(),br(),
      ),
      mainPanel(plotOutput("plot"))
    ))
    
    server <- function(input, output, session) {
    
      currentMat <- reactiveVal(isolate(input$matrix1))
    
      observeEvent(input$matrix1, {
        tmpMat1 <- input$matrix1
        if(any(rownames(input$matrix1)== "")){rownames(tmpMat1)<-paste("Fila",seq_len(nrow(input$matrix1)))}
        updateMatrixInput(session, inputId = "matrix1", value = tmpMat1)
    
        tmpMat2 <- currentMat()
    
        if(nrow(tmpMat1) > nrow(tmpMat2)){tmpMat2 <- rbind(tmpMat2, rep(NA, ncol(tmpMat2)))}
    
        # AGREGADO
        if(nrow(tmpMat2) > nrow(tmpMat1)){tmpMat1 <- rbind(tmpMat1, rep(NA, ncol(tmpMat1)))}
    
        currentMat(cbind(tmpMat1[drop=FALSE], tmpMat2[,-1:-2,drop=FALSE]))
      })
    
      observeEvent(input$showMat2, {
        showModal(modalDialog(
          matrixInput(
            "matrix2",
            label = "Matriz 2:",
            value = currentMat(),
            rows = list(extend = TRUE, delete = TRUE),
            cols = list(extend = TRUE,delta = 2,delete = TRUE,multiheader = TRUE),
            class = "numeric"
          ),
          footer = tagList(modalButton("Cerrar"))
        ))
      })
    
      observeEvent(input$matrix2, {
        tmpMat2 <- input$matrix2
        rownames(tmpMat2) <- paste("Fila", seq_len(nrow(input$matrix2)))
        colnames(tmpMat2) <- paste("Escenario", rep(1:ncol(tmpMat2),each = 2,length.out = ncol(tmpMat2)))
        currentMat(tmpMat2)
        updateMatrixInput(session, inputId = "matrix2", value = tmpMat2)
        updateMatrixInput(session, inputId = "matrix1", value = tmpMat2[, 1:2, drop = FALSE])
      })
    
      plotData <- reactive({
        tryCatch(
          lapply(seq_len(ncol(input$matrix1) / 2),
                 function(i) {
                   tibble(
                     Escenario = colnames(input$matrix1)[i * 2 - 1],
                     X = seq_len(10),
                     Y = sumMat(input$matrix1[, (i * 2 - 1):(i * 2), drop = FALSE])
                   )
                 }) %>% bind_rows(),
          error = function(e)
            NULL
        )
      })
    
      output$plot <- renderPlot({
        plotData() %>% ggplot() +
          geom_line(aes(
            x = X,
            y = Y,
            colour = as.factor(Escenario)
          )) +
          theme(legend.title = element_blank())
      })
    }
    
    shinyApp(ui, server)
    

    Nótese que este código todavía está estructurado con el código original de tener matrix2 como un diálogo modal, donde matrix2 es una copia exacta de matrix1. Esto puede ser mejorado aún más, pero la solución actual se centra en abordar el problema principal, que es dejar que la última entrada de matriz modificada domine la otra matriz de entrada.

Comments are closed.