Как прослушивать более одного выражения события в обработчике Shiny eventReactive

88

Я хочу, чтобы два разных события запускали обновление данных, используемых различными графиками / выходами в моем приложении. Один - это нажатая кнопка ( input$spec_button), а другой - точка на нажатой точке ( mainplot.click$click).

По сути, я хочу перечислить оба варианта одновременно, но я не уверен, как писать код. Вот что у меня есть сейчас:

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

Но предложение if-else не работает

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

-> Есть ли какая-то функция объединения действий, которую я могу использовать для этого mainplot.click$click | input$spec_buttonпредложения?

Хиллари Сандерс
источник
Можете ли вы проверить вывод! Is.null (вход $ spec_button)?
Гопала

Ответы:

97

Я знаю, что это старый, но у меня был тот же вопрос. Я наконец-то понял. Вы включаете выражение в фигурные скобки и просто перечисляете события / реактивные объекты. Мое (необоснованное) предположение состоит в том, что shiny просто выполняет тот же анализ реактивного указателя на этот блок выражения, что и на стандартный reactiveблок.

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

РЕДАКТИРОВАТЬ

Обновлено для обработки случая, когда последняя строка в выражении возвращает NULL. Просто верните постоянное значение.

Дункан Браун
источник
1
Изменение принятого ответа на этот, поскольку это кажется лучшим решением, чем мое исходное решение.
Хиллари Сандерс,
3
Можете ли вы определить, какое событие было инициировано?
PeterVermont
Не то, чтобы я в курсе. Я делал это в нескольких случаях, отслеживая их в отдельных переменных и выполняя сравнение самостоятельно, чтобы увидеть, что изменилось. Но это некрасиво. Вероятно, лучше поместить основной код в функцию, а затем иметь два ObservationEvents, которые вызывают fn, а затем выполняют определенные действия для каждого события.
Дункан Браун
8
Просто предупреждение: observeEventиспользуется ignoreNULL = TRUEпо умолчанию, что означает, что если mainplot.click$click(возвращаемое значение) равно NULL, обработчик никогда не будет вызван, даже если он будет input$spec_buttonизменен. Я бы порекомендовал что-то вроде ответа @ JustAnother, чтобы не попасть в эту ловушку.
greg L
1
Еще одно предупреждение: в ходе тестирования я обнаружил, что этот синтаксис скобок ( {}) ТРЕБУЕТ, чтобы каждое событие располагалось на отдельной строке новой строки, в противном случае он выдает ошибку «Ошибка при синтаксическом анализе ...», как только синтаксический анализатор обнаруживает второе событие. например, все в одной строке: observeEvent({input$spec_button mainplot.click$click}, {...})не удается. Ответ @ JustAnother с использованием синтаксиса комбинирования S3 Generic ( c()) работает независимо от новых строк.
Brian D
57

Также:

observeEvent(c( 
  input$spec_button,
  mainplot.click$click
), { ... } )
Просто еще один
источник
6
Хотя это очень похоже на ответ @DuncanBrown, я обнаружил ситуацию, когда две кнопки действий запускают модальное окно, это сработало, а {версия - нет. Я не могу объяснить, почему это так.
Джон Пол
2
Добавил комментарий к ответу @Duncan Brown о том, чем этот ответ отличается (и лучше IMO)
greg L
Этот у меня не работает - я получаю сообщение об ошибке (блестящий 1.0.5)
potockan
есть ли способ узнать, какое событие было инициировано? скажем, у меня есть две кнопки, input$button1и они input$button2делают очень похожие вещи, только с другим индексом. Я бы не хотел копировать код несколько раз только потому, что не знаю индекса. Благодаря!
Никос Боссе
11

Я решил эту проблему с помощью создания реактивного объекта и использования его в выражении изменения события. Как показано ниже:

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

output$mypotput <- eventReactive( xxchange(), {
...
...
...
} )
Сельчук Акбас
источник
5
Это очень хороший ответ, который требует дополнительных пояснений. Хотя принятый ответ более прост, что делает его лучше для элементарных программ, этот ответ лучше подходит для больших и сложных кодов. Кажется, что в ответе отсутствуют два пункта (1) Вставка (или список) помещает два события в одну строку, делая код более компактным. (2) Реактивный объект избавляет от необходимости повторять одни и те же два события снова и снова, если более одного слушателя прослушивают один и тот же набор событий.
Агроном
5

Вот решение, которое я придумал: в основном, создать пустой reactiveValuesдержатель данных, а затем изменить его значения на основе двух отдельных observeEventэкземпляров.

  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
list(mainplot.click$click, input$spec_button)также будет работать для OP.
Джон
1

Это все еще можно сделать с помощью eventReactive, просто поместив свои действия в вектор.

eventReactive(
  c(input$spec_button, mainplot.click$click), 
{ ... } )
Джей Ди Кэдделл
источник
0

Идея здесь состоит в том, чтобы создать реактивную функцию, которая будет выполнять условие, которое вы хотите передать в ObservationEvent, а затем вы можете передать эту реактивную функцию, чтобы проверить действительность оператора. Например:

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

Продолжайте кодировать!

Вишал Шарма
источник