Come ascoltare più di un'espressione di evento all'interno di un gestore di Shiny eventReactive


88

Desidero che due eventi diversi attivino un aggiornamento dei dati utilizzati da vari grafici / output nella mia app. Uno è un pulsante su cui si fa clic ( input$spec_button) e l'altro è un punto su un punto su cui si fa clic ( mainplot.click$click).

Fondamentalmente, voglio elencare entrambi allo stesso tempo, ma non sono sicuro di come scrivere il codice. Ecco cosa ho adesso:

nel server.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
    }
  })

Ma la clausola if-else non funziona

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

-> C'è una sorta di funzione combinatore di azioni che posso usare per la mainplot.click$click | input$spec_buttonclausola?


Puoi controllare l'output di! Is.null (input $ spec_button)?
Gopala,

Risposte:


97

So che questo è vecchio, ma avevo la stessa domanda. Finalmente l'ho capito. Includete un'espressione tra parentesi graffe e semplicemente elencate gli eventi / oggetti reattivi. La mia ipotesi (infondata) è che shiny esegua semplicemente la stessa analisi del puntatore reattivo a questo blocco di espressioni come a un reactiveblocco standard .

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

MODIFICARE

Aggiornato per gestire il caso in cui l'ultima riga dell'espressione restituisce NULL. Restituisci semplicemente un valore costante.


1
Modifica la risposta accettata a questa poiché sembra essere una soluzione migliore della mia soluzione originale.
Hillary Sanders

3
Riuscite a identificare quale evento è stato attivato?
Peter Vermont

Non che io sappia. L'ho fatto in alcuni casi tenendone traccia in variabili separate e facendo il confronto io stesso per vedere quale è cambiato. Ma è brutto. Probabilmente è meglio mettere il codice principale in una funzione, quindi avere due ObservEvents che chiamano fn e quindi fare cose specifiche per ogni evento.
Duncan Brown

8
Solo un avvertimento: observeEventusa ignoreNULL = TRUEdi default, il che significa che se mainplot.click$click(il valore restituito) è NULL, il gestore non verrà mai chiamato anche se input$spec_buttonmodificato. Consiglierei qualcosa come la risposta di @ JustAnother per evitare di cadere in questa trappola.
greg L

1
Un altro avvertimento: durante i miei test ho scoperto che questa sintassi della parentesi ( {}) RICHIEDE che ogni evento sia sulla sua nuova riga, altrimenti fallisce con "Errore in analisi ..." non appena il parser incontra il secondo evento. ad esempio, tutto su una riga: observeEvent({input$spec_button mainplot.click$click}, {...})fallisce. La risposta di @ JustAnother utilizzando la sintassi di combinazione generica S3 ( c()) funziona indipendentemente dalle nuove righe.
Brian D

57

Anche:

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

6
Sebbene questo sia molto simile alla risposta di @DuncanBrown, ho trovato una situazione in cui 2 pulsanti di azione attivano entrambi un modale, questo ha funzionato e la {versione no. Non riesco a spiegare perché sia ​​così.
Giovanni Paolo il

2
Aggiunto un commento alla risposta di @Duncan Brown su come questa risposta sia diversa (e migliore IMO)
greg L

Questo non funziona per me - Ottengo un errore (brillante 1.0.5)
potockan

c'è un modo per scoprire quale evento è stato attivato? diciamo che ho due pulsanti input$button1e input$button2che fanno cose molto simili, solo con un indice diverso. Vorrei evitare di copiare il codice più volte solo perché non conosco l'indice. Grazie!
Nikos Bosse

11

Ho risolto questo problema creando un oggetto reattivo e usandolo nell'espressione di modifica degli eventi. Come sotto:

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

output$mypotput <- eventReactive( xxchange(), {
...
...
...
} )

5
Questa è un'ottima risposta che potrebbe trarre vantaggio da ulteriori spiegazioni. Mentre la risposta accettata è più semplice e migliore per i programmi rudimentali, questa risposta è più adatta a codici grandi e complessi. Due punti sembrano mancare dalla risposta (1) Paste (o list) mette i due eventi sulla stessa riga rendendo il codice più compatto. (2) L'oggetto reattivo risparmia lo sforzo di ripetere gli stessi due eventi più e più volte se più di un ascoltatore sta ascoltando lo stesso insieme di eventi.
Agricoltore

5

Ecco la soluzione che ho trovato: fondamentalmente, crea un reactiveValuescontenitore di dati vuoto e quindi modifica i suoi valori in base a due observeEventistanze separate .

  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)  
  })

3
funzionerà list(mainplot.click$click, input$spec_button)anche per la strada di OP.
Giovanni

1

Questo può ancora essere fatto con eventReactive semplicemente inserendo le tue azioni in un vettore.

eventReactive(
  c(input$spec_button, mainplot.click$click), 
{ ... } )

0

L'idea qui è di creare una funzione reattiva che eseguirà la condizione che si desidera passare in ObservEvent e quindi è possibile passare questa funzione reattiva per verificare la validità dell'istruzione. Per esempio:

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(), 
    { ... } 
)

Continua a codificare!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.