Como ouvir mais de uma expressão de evento em um manipulador Shiny eventReactive


88

Quero dois eventos diferentes para acionar uma atualização dos dados que estão sendo usados ​​por vários gráficos / saídas em meu aplicativo. Um é um botão sendo clicado ( input$spec_button) e o outro é um ponto em um ponto sendo clicado ( mainplot.click$click).

Basicamente, quero listar os dois ao mesmo tempo, mas não tenho certeza de como escrever o código. Aqui está o que tenho agora:

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

Mas a cláusula if-else não funciona

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

-> Existe algum tipo de função combinadora de ação que eu possa usar para a mainplot.click$click | input$spec_buttoncláusula?


Você pode verificar a saída de! Is.null (input $ spec_button)?
Gopala

Respostas:


97

Eu sei que isso é antigo, mas eu tinha a mesma pergunta. Eu finalmente descobri. Você inclui uma expressão entre colchetes e simplesmente lista os eventos / objetos reativos. Minha suposição (não comprovada) é que brilhante simplesmente executa a mesma análise de ponteiro reativo para este bloco de expressão como para um reactivebloco padrão .

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

EDITAR

Atualizado para lidar com o caso em que a última linha da expressão retorna NULL. Simplesmente retorne um valor constante.


1
Mudar a resposta aceita para esta, pois parece ser uma solução melhor do que minha solução original.
Hillary Sanders

3
Você consegue identificar qual evento foi disparado?
PeterVermont

Não que eu saiba. Fiz isso em alguns casos, acompanhando-as em variáveis ​​separadas e fazendo a comparação eu mesmo para ver o que mudou. Mas é feio. Provavelmente melhor colocar o código principal em uma função, então ter dois observeEvents que chamam o fn e então fazem coisas específicas para cada evento.
Duncan Brown

8
Apenas um aviso: observeEventusa ignoreNULL = TRUEpor padrão, o que significa que se mainplot.click$click(o valor de retorno) for NULL, o manipulador nunca será chamado, mesmo se input$spec_buttonalterado. Eu recomendaria algo como a resposta de @JustAnother para evitar cair nessa armadilha.
Greg L

1
Outro aviso: em meus testes, descobri que esta sintaxe de colchetes ( {}) REQUER que cada evento esteja em sua própria nova linha, caso contrário, ele falha com "Erro na análise ..." assim que o analisador encontra o segundo evento. por exemplo, tudo em uma linha: observeEvent({input$spec_button mainplot.click$click}, {...})falha. A resposta de @JustAnother usando a sintaxe de combinação S3 Generic ( c()) funciona independentemente das novas linhas.
Brian D de

57

Além disso:

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

6
Embora pareça muito semelhante à resposta de @DuncanBrown, encontrei uma situação em que dois botões de ação acionam um modal, isso funcionou e a {versão não. Não consigo explicar por que isso acontece.
João Paulo

2
Adicionou um comentário à resposta de @Duncan Brown sobre como essa resposta é diferente (e melhor, IMO)
greg L

Este não funciona para mim - recebo um erro (brilhante 1.0.5)
potockan

existe uma maneira de descobrir qual evento foi disparado? digamos que eu tenha dois botões input$button1e input$button2que façam coisas muito semelhantes, apenas com um índice diferente. Gostaria de evitar copiar o código várias vezes só porque não conheço o índice. Obrigado!
Nikos Bosse,

11

Resolvi esse problema com a criação de um objeto reativo e uso-o na expressão de mudança de evento. Como abaixo:

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

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

5
Esta é uma resposta muito boa que poderia se beneficiar de mais explicações. Embora a resposta aceita seja mais direta, tornando-a melhor para programas rudimentares, essa resposta é mais adequada para códigos grandes e complexos. Dois pontos parecem faltar na resposta (1) Colar (ou lista) coloca os dois eventos na mesma linha, tornando o código mais compacto. (2) O objeto reativo poupa o esforço de repetir os mesmos dois eventos indefinidamente se mais de um ouvinte estiver ouvindo o mesmo conjunto de eventos.
Agricultor

5

Aqui está a solução que encontrei: basicamente, crie um reactiveValuessuporte de dados vazio e, em seguida, modifique seus valores com base em duas observeEventinstâncias 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)  
  })

3
vai list(mainplot.click$click, input$spec_button)também trabalhar para o caminho de OP.
João,

1

Isso ainda pode ser feito com eventReactive simplesmente colocando suas ações em um vetor.

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

0

A ideia aqui é criar uma função reativa que irá executar a condição que você deseja passar em observeEvent e então você pode passar essa função reativa para verificar a validade da instrução. Por exemplo:

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

Continue codificando!

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.