Cómo escuchar más de una expresión de evento dentro de un controlador de evento Shiny

85

Quiero que dos eventos diferentes activen una actualización de los datos que utilizan varios gráficos / salidas en mi aplicación. Uno es un botón en el que se hace clic ( input$spec_button) y el otro es un punto en un punto en el que se hace clic ( mainplot.click$click).

Básicamente, quiero enumerar ambos al mismo tiempo, pero no estoy seguro de cómo escribir el código. Esto es lo que tengo ahora:

en servidor.R:

data <- eventReactive({mainplot.click$click | input$spec_button}, {
    if(input$spec_button){
      # get data relevant to the button
    } else {
      # get data relevant to the point clicked
    }
  })

Pero la cláusula if-else no funciona

Error in mainplot.click$click | input$spec_button : operations are possible only for numeric, logical or complex types

-> ¿Hay algún tipo de función de combinación de acciones que pueda usar para la mainplot.click$click | input$spec_buttoncláusula?

Hillary Sanders
fuente
¿Puede verificar la salida de! Is.null (input $ spec_button)?
Gopala

Respuestas:

94

Sé que esto es antiguo, pero tenía la misma pregunta. Finalmente lo resolví. Incluye una expresión entre llaves y simplemente enumera los eventos / objetos reactivos. Mi suposición (sin fundamento) es que shiny simplemente realiza el mismo análisis de puntero reactivo para este bloque de expresión que para un reactivebloque estándar .

observeEvent({ 
  input$spec_button
  mainplot.click$click
  1
}, { ... } )

EDITAR

Actualizado para manejar el caso donde la última línea de la expresión devuelve NULL. Simplemente devuelva un valor constante.

Duncan Brown
fuente
1
Cambiando la respuesta aceptada a esta, ya que parece ser una mejor solución que mi solución original.
Hillary Sanders
3
¿Puede identificar qué evento se desencadenó?
PeterVermont
No que yo supiese. He hecho esto en algunos casos al realizar un seguimiento de ellos en variables separadas y hacer la comparación yo mismo para ver cuál ha cambiado. Pero es feo. Probablemente sea mejor poner el código principal en una función, luego tener dos observeEvents que llamen al fn y luego hagan cosas específicas para cada evento.
Duncan Brown
8
Solo una advertencia: se observeEventusa ignoreNULL = TRUEde forma predeterminada, lo que significa que si mainplot.click$click(el valor de retorno) es NULL, nunca se llamará al controlador, incluso si se input$spec_buttoncambia. Recomendaría algo como la respuesta de @ JustAnother para evitar caer en esta trampa.
greg L
1
Otra advertencia: en mis pruebas encontré que esta sintaxis de corchetes ( {}) REQUIERE que cada evento esté en su propia línea nueva, de lo contrario, falla con "Error en el análisis ..." tan pronto como el analizador encuentra el segundo evento. por ejemplo, todo en una línea: observeEvent({input$spec_button mainplot.click$click}, {...})falla. La respuesta de @ JustAnother usando S3 Generic combine syntax ( c()) funciona independientemente de las nuevas líneas.
Brian D
54

También:

observeEvent(c( 
  input$spec_button,
  mainplot.click$click
), { ... } )
Solo otro
fuente
6
Si bien esto se ve muy similar a la respuesta de @DuncanBrown, encontré una situación en la que 2 botones de acción activan un modal, esto funcionó y la {versión no. No puedo explicar por qué es así.
John Paul
2
Se agregó un comentario a la respuesta de @Duncan Brown sobre cómo esta respuesta es diferente (y mejor en mi opinión)
greg L
Este no funciona para mí - me sale un error (brillante 1.0.5)
potockan
¿Hay alguna forma de averiguar qué evento se desencadenó? digamos que tengo dos botones, input$button1y input$button2que hacen cosas muy similares, solo que con un índice diferente. Me gustaría evitar copiar el código varias veces solo porque no conozco el índice. ¡Gracias!
Nikos Bosse
10

Resolví este problema al crear un objeto reactivo y usarlo en la expresión de cambio de evento. Como a continuación:

xxchange <- reactive({
paste(input$filter , input$term)
})

output$mypotput <- eventReactive( xxchange(), {
...
...
...
} )
Selcuk Akbas
fuente
4
Esta es una muy buena respuesta que podría beneficiarse de una mayor explicación. Si bien la respuesta aceptada es más sencilla, lo que la hace mejor para programas rudimentarios, esta respuesta se adapta mejor a códigos grandes y complejos. Parece que faltan dos puntos en la respuesta (1) Pegar (o listar) coloca los dos eventos en la misma línea haciendo que el código sea más compacto. (2) El objeto reactivo ahorra el esfuerzo de repetir los mismos dos eventos una y otra vez si más de un oyente está escuchando el mismo conjunto de eventos.
Agricultor
5

Esta es la solución que se me ocurrió: básicamente, cree un contenedor de reactiveValuesdatos vacío y luego modifique sus valores en función de dos observeEventinstancias separadas .

  data <- reactiveValues()
  observeEvent(input$spec_button, {
    data$data <- get.focus.spec(input=input, premise=premise, 
                                itemname=input$dropdown.itemname, spec.info=spec.info)
  })
  observeEvent(mainplot.click$click, {
    data$data <- get.focus.spec(input=input, premise=premise, mainplot=mainplot(),
                                mainplot.click_focus=mainplot.click_focus(),
                                spec.info=spec.info)  
  })
Hillary Sanders
fuente
3
será list(mainplot.click$click, input$spec_button)también trabajar por el camino de la OP.
Juan
1

Esto todavía se puede hacer con eventReactive simplemente poniendo sus acciones en un vector.

eventReactive(
  c(input$spec_button, mainplot.click$click), 
{ ... } )
JD Caddell
fuente
0

La idea aquí es crear una función reactiva que ejecutará la condición que desea pasar en observeEvent y luego puede pasar esta función reactiva para verificar la validez de la declaración. Por ejemplo:

validate_event <- reactive({
    # I have used OR condition here, you can use AND also
    req(input$spec_button) || req(mainplot.click$click)
})

observeEvent(validate_event(), 
    { ... } 
)

¡Sigue codificando!

Vishal Sharma
fuente