Jak nasłuchiwać więcej niż jednego wyrażenia zdarzenia w module obsługi Shiny eventReactive

85

Chcę, aby dwa różne zdarzenia wyzwalały aktualizację danych używanych przez różne wykresy / wyjścia w mojej aplikacji. Jeden to klikany przycisk ( input$spec_button), a drugi to punkt klikniętej kropki ( mainplot.click$click).

Zasadniczo chcę wymienić oba te elementy jednocześnie, ale nie jestem pewien, jak napisać kod. Oto, co mam teraz:

na serwerze.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
    }
  })

Ale klauzula if-else nie działa

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

-> Czy jest jakaś funkcja łącząca akcje, której mogę użyć dla mainplot.click$click | input$spec_buttonklauzuli?

Hillary Sanders
źródło
Czy możesz sprawdzić wyjście! Is.null (wejście $ spec_button)?
Gopala

Odpowiedzi:

94

Wiem, że to jest stare, ale miałem to samo pytanie. W końcu to rozgryzłem. Umieszczasz wyrażenie w nawiasach klamrowych i po prostu podajesz zdarzenia / reaktywne obiekty. Moje (bezpodstawne) przypuszczenie jest takie, że błyszcząca po prostu wykonuje taką samą reaktywną analizę wskaźnika do tego bloku wyrażenia, jak do reactivebloku standardowego .

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

EDYTOWAĆ

Zaktualizowano, aby obsłużyć przypadek, w którym ostatnia linia w wyrażeniu zwraca NULL. Po prostu zwróć stałą wartość.

Duncan Brown
źródło
1
Zmiana akceptowanej odpowiedzi na tę, ponieważ wydaje się być lepszym rozwiązaniem niż moje oryginalne rozwiązanie.
Hillary Sanders
3
Czy możesz zidentyfikować, które zdarzenie zostało wywołane?
PeterVermont
Nie, że jestem świadomy. Zrobiłem to w kilku przypadkach, śledząc je w oddzielnych zmiennych i wykonując porównanie samodzielnie, aby zobaczyć, co się zmieniło. Ale to brzydkie. Prawdopodobnie lepiej jest umieścić główny kod w funkcji, a następnie mieć dwa observEvents, które wywołują fn, a następnie wykonują określone czynności dla każdego zdarzenia.
Duncan Brown
8
Tylko ostrzeżenie: observeEventużywa ignoreNULL = TRUEdomyślnie, co oznacza, że ​​jeśli mainplot.click$click(wartość zwracana) jest NULL, procedura obsługi nigdy nie zostanie wywołana, nawet jeśli zostanie input$spec_buttonzmieniona. Poleciłbym odpowiedź w stylu @ JustAnother, aby zapobiec wpadnięciu w tę pułapkę.
greg L
1
Kolejne ostrzeżenie: w moich testach odkryłem, że składnia tego nawiasu ( {}) WYMAGA, aby każde zdarzenie znajdowało się we własnym znaku nowej linii, w przeciwnym razie zakończy się niepowodzeniem z komunikatem „Błąd w analizie ...”, gdy tylko parser napotka drugie zdarzenie. np. wszystko w jednej linii: observeEvent({input$spec_button mainplot.click$click}, {...})niepowodzenie. Odpowiedź @ JustAnother za pomocą S3 Generic Combination syntax ( c()) działa niezależnie od nowych linii.
Brian D
54

Również:

observeEvent(c( 
  input$spec_button,
  mainplot.click$click
), { ... } )
Kolejny
źródło
6
Chociaż wygląda to bardzo podobnie do odpowiedzi @DuncanBrown, znalazłem sytuację, w której 2 przyciski akcji wyzwalają modal, to zadziałało, a {wersja nie. Nie potrafię wyjaśnić, dlaczego tak jest.
John Paul,
2
Dodano komentarz do odpowiedzi @Duncan Brown na temat tego, czym różni się ta odpowiedź (i lepsza IMO)
greg L
Ten nie działa dla mnie
wyskakuje
czy istnieje sposób, aby dowiedzieć się, które zdarzenie zostało wywołane? powiedzmy, że mam dwa przyciski, input$button1i input$button2że zrobić bardzo podobne rzeczy, tylko z innym indeksem. Chciałbym uniknąć wielokrotnego kopiowania kodu tylko dlatego, że nie znam indeksu. Dzięki!
Nikos Bosse
10

Rozwiązałem ten problem, tworząc obiekt reaktywny i używając go w wyrażeniu zmiany zdarzenia. Jak poniżej:

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

output$mypotput <- eventReactive( xxchange(), {
...
...
...
} )
Selcuk Akbas
źródło
4
To bardzo dobra odpowiedź, która mogłaby zyskać na dokładniejszym wyjaśnieniu. Chociaż przyjęta odpowiedź jest prostsza, dzięki czemu jest lepsza dla podstawowych programów, ta odpowiedź jest lepiej dostosowana do dużych i złożonych kodów. Wydaje się, że w odpowiedzi brakuje dwóch punktów (1) Wklej (lub lista) umieszcza dwa zdarzenia w tej samej linii, dzięki czemu kod jest bardziej zwarty. (2) Obiekt reaktywny oszczędza wysiłek związany z powtarzaniem tych samych dwóch zdarzeń w kółko, jeśli więcej niż jeden słuchacz nasłuchuje tego samego zestawu zdarzeń.
Agriculturist
5

Oto rozwiązanie, które wymyśliłem: w zasadzie utwórz pusty reactiveValuesuchwyt danych, a następnie zmodyfikuj jego wartości w oparciu o dwa oddzielne observeEventinstancje.

  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
źródło
3
będzie list(mainplot.click$click, input$spec_button)również działać na sposób OP.
Jan
1

Nadal można to zrobić za pomocą eventReactive, po prostu umieszczając swoje akcje w wektorze.

eventReactive(
  c(input$spec_button, mainplot.click$click), 
{ ... } )
JD Caddell
źródło
0

Pomysł polega na utworzeniu funkcji reaktywnej, która wykona warunek, który chcesz przekazać w observEvent, a następnie możesz przekazać tę funkcję reaktywną, aby sprawdzić poprawność instrukcji. Na przykład:

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

Koduj dalej!

Vishal Sharma
źródło