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.