1. ホーム
  2. r

[解決済み] reactiveとobserveのメリットとobserveEventのメリット

2023-08-19 06:34:36

疑問点

shiny reactive programmingについてできる限りのことを読みました。 私は少し混乱しています。 以下はすべて動作しますが、望ましい方法は何ですか、そしてなぜですか? 明らかに、以下の例は単純ですが、いずれかの方法でより大きなアプリケーションを作成するときに問題が発生するでしょうか?

私は、サーバーコード#1 のスタイルに引き寄せられる傾向があります。 理由は、if 文を分割することができるからです。 私にとっては、この方がずっと読みやすく思えます。 以下の簡単な例はそれほど複雑ではありませんが、サーバー コード 2 とサーバー コード 3 が、入れ子になった if / if else 文で非常に混乱することは容易に想像できます。

UI コード

library(shiny)

ui <- fluidPage(
  selectInput(inputId = 'choice',
              label = 'Choice',
              choice = c('Hello','Goodbye'),
              selected = c('Hello')
  ),

  textOutput('result')

)

サーバーコード1

server <- function(input,output,session)({

  text <- reactiveValues()

  observe({
    if (input$choice == 'Hello') {
      text$result <- 'Hi there'
      }
    })

  observe({
    if (input$choice == 'Goodbye') {
      text$result <- 'See you later'
      }
    })

  output$result <- renderText({
    text$result
  })

})

shinyApp(ui = ui, server = server)

サーバーコード2

server <- function(input,output,session)({

  getStatus <- reactive({

    if (input$choice == 'Hello') {
      'Hi there'
    } else if (input$choice == 'Goodbye'){
      'See you later'
    }
  })

  output$result <- renderText({
    getStatus()
  })

})

shinyApp(ui = ui, server = server)

サーバーコード3

server <- function(input,output,session)({

  text <- reactiveValues()

  observeEvent(input$choice,{
    if (input$choice == 'Hello') {
      text$result <- 'Hi there'
    } else if (input$choice == 'Goodbye') {
      text$result <- 'See you later'
    }
  })

  output$result <- renderText({
    text$result
  })

})

shinyApp(ui = ui, server = server)

どのように解決するのですか?

まず第一に、これは曖昧なもので、あまり直感的でないところがあります。

以下は、このトピックに関する私の最良の理解です。

まず reactive

リアクティブ関数は、入力または他の変化する変数の状態を監視し、コードの他の場所で使用するためにその値を返すことができます。リアクティブ変数の監視は怠慢とみなされます。 "リアクティブ式は遅延評価を使用します。つまり、依存関係が変化してもすぐに再実行せず、他の誰かから呼び出されるまで待ちます( ソース) "です。 の中で変数を呼び出すことができるので、例2ではこれをうまく示していますね。 renderText 環境内で変数を呼び出すことができ、一度呼び出されると、反応呼び出しの中のコードが実行され、変数が再評価されます。

科学オタクにとっては、リアクティブ変数を呼び出す(それを観察する)ことによって、再評価によってそれが変化するという点で、これは量子力学によく似ていますが、大げさすぎますか?

では、次に observe

Observeはreactiveに似ていますが、主な違いは自分以外の環境に値を返さないことと、遅延がないことです。オブザーブ関数は は、その環境内のすべてのリアクティブな値の変化を継続的に監視します。 そして、これらの値が変更されたときに、その環境内のコードを実行します。したがって、observeは再評価の前に呼ばれるのを待たないので、 "lazy"評価ではありません。繰り返しますが、observeから変数を代入することはできないことに注意してください。

実験のためです。

server <- function(input,output,session)({

   observe({
   if (input$choice == 'Hello') {
      getStatus <- 'Hi there'
    }
  })

  observe({
    if (input$choice == 'Goodbye') {
      getStatus <- 'See you later'
    }
  })

  output$result <- renderText({
    getStatus
  })

})

shinyApp(ui = ui, server = server)

ここで重要なことは observe で実行されるコードの中で、外部の環境反応変数を操作することができることです。この例では text <- reactiveValues() を代入し、それを操作するために text$result <- 'Hi there' . を更新するようなこともできます。 selectInput のような選択肢や、その他の輝くウィジェットもできますが、この環境では、上記の例の getStatus のような非反応変数を割り当てることができません。そして、この考え方は observe のドキュメントで言及されています。

オブザーバーはリアクティブな値を読み、リアクティブな式を呼び出すことができるという点で、リアクティブな式に似ています。そして、それらの依存関係が変化したときに自動的に再実行されます。しかし、リアクティブ式とは異なり、結果を出すことはなく、他のリアクティブ式の入力として使用することはできません。したがって、オブザーバはその副次的効果(例えばI/Oの実行など)においてのみ有用である( ソース )"です。

最後に observeEvent

最適な使用方法は observeEvent を使用する最良の方法は、あるイベントまたは変数の変化を監視し、イベントが発生したときに起動するような、定義されたトリガーと考えることです。私は、ボタンへの入力を監視するために、最も一般的にこれを使用します。これは、ボタンが押された後に何かが起こるように定義されたイベントだからです。これは isolate 環境を使用します。これは、この関数がどのように動作するかにぴったりの名前だと思います。

この環境の中では、たくさんの反応変数を呼び出すことができますが、トリガーとして定義するのは1つだけです。との主な違いは observeEventobserve がトリガーとなり observe は何か変更があったときにいつでも実行され observeEvent はトリガーを待ちます。この環境は、反応しない変数を返さないという点で、observeと似ていることに注意してください。

概要

これらのアイデアをまとめた例を紹介します。

library(shiny)

ui<-
 fluidPage(
   fluidRow(
     column(4,
      h2("Reactive Test"),
      textInput("Test_R","Test_R"),
      textInput("Test_R2","Test_R2"),
      textInput("Test_R3","Test_R3"),
      tableOutput("React_Out")
    ),
     column(4,
      h2("Observe Test"),
      textInput("Test","Test"),
      textInput("Test2","Test2"),
      textInput("Test3","Test3"),
      tableOutput("Observe_Out")
    ),
    column(4,
      h2("Observe Event Test"),
      textInput("Test_OE","Test_OE"),
      textInput("Test_OE2","Test_OE2"),
      textInput("Test_OE3","Test_OE3"),
      tableOutput("Observe_Out_E"),
      actionButton("Go","Test")
    )

    ),
  fluidRow(
    column(8,
    h4("Note that observe and reactive work very much the same on the surface,
       it is when we get into the server where we see the differences, and how those
       can be exploited for diffrent uses.")
  ))

  )

server<-function(input,output,session){

# Create a reactive Evironment. Note that we can call the varaible outside same place
# where it was created by calling Reactive_Var(). When the varaible is called by
# renderTable is when it is evaluated. No real diffrence on the surface, all in the server.

Reactive_Var<-reactive({c(input$Test_R, input$Test_R2, input$Test_R3)})

output$React_Out<-renderTable({
  Reactive_Var()
  })

# Create an observe Evironment. Note that we cannot access the created "df" outside 
# of the env. A, B,and C will update with any input into any of the three Text Feilds.
observe({
  A<-input$Test
  B<-input$Test2
  C<-input$Test3
  df<-c(A,B,C)
  output$Observe_Out<-renderTable({df})
  })

#We can change any input as much as we want, but the code wont run until the trigger
# input$Go is pressed.
observeEvent(input$Go, {
  A<-input$Test_OE
  B<-input$Test_OE2
  C<-input$Test_OE3
  df<-c(A,B,C)
  output$Observe_Out_E<-renderTable({df})
})

}
shinyApp(ui, server)

reactive 変数を作成する この変数はユーザーの入力によって時間と共に変化し、呼ばれたときだけという意味で "lazy"を評価します。

observe 反応イベントと変数を継続的に監視し、いつでも いつでも リアクティブ変数が環境(観測環境)で変更されるたびに、コードが評価されます。以前に定義されたリアクティブ変数の値を変更することができ、変数を作成/返却することはできません。

observeEvent (ドミノ効果) 継続的に監視する ワン 定義されたリアクティブ変数/イベント(トリガー)を継続的に監視し、そのトリガーの変更/入力によってトリガーがアクティブになったときにコードを実行します。事前に定義されたリアクティブ変数の値を変更することができ、変数の作成/返却はできません。

eventReactive 変数の作成 と同様に定義されたトリガーで observeEvent . これは、呼び出されたときではなく、トリガーによって評価される反応型変数が欲しいときに使います。

もし私の理解に間違いがあったり、より明確な説明が必要であれば、遠慮なくこの回答を編集していただければと思います。