web-dev-qa-db-ja.com

( `message`で書かれた)コンソールメッセージを光沢のあるUIで表示することは可能ですか?

Rのメッセージvs猫vs印刷vsなどについてはあまり理解していませんが、メッセージをキャプチャして、光沢のあるアプリで表示することは可能でしょうか。

例:次のアプリはcatステートメント(およびprintステートメントも)をキャプチャできますが、メッセージステートメントはキャプチャできません

runApp(shinyApp(
  ui = fluidPage(
    textOutput("test")
  ),
  server = function(input,output, session) {
    output$test <- renderPrint({
      cat("test cat")
      message("test message")
    })
  }
))

の回答を得たので、光沢のあるディスカッションのGoogleグループからのクロス投稿。

34
DeanAttali

Yihuiは私がwithCallingHandlersを使用することを提案しました。私の問題は、一度に複数のメッセージを出力する機能があり、単純なアプローチを使用すると最後のメッセージしか出力されないということだったので、必要な機能を正確に実行する方法がわかりませんでした。これが私の最初の試みです(表示するメッセージが1つしかない場合に機能します)。

foo <- function() {
  message("one")
  message("two")
}

runApp(shinyApp(
  ui = fluidPage(
    actionButton("btn","Click me"),
    textOutput("text")
  ),
  server = function(input,output, session) {
    observeEvent(input$btn, {
      withCallingHandlers(
        foo(),
        message = function(m) output$text <- renderPrint(m$message)
      )
    })
  }
))

two\nが出力されます。したがって、私の最終的な解決策は、htmlパッケージのshinyjs関数を使用することでした(免責事項:私はそのパッケージを作成しました)。これにより、要素内のHTMLを変更または追加できます。完全に機能しました。両方のメッセージがリアルタイムで出力されました。

foo <- function() {
  message("one")
  Sys.sleep(0.5)
  message("two")
}

runApp(shinyApp(
  ui = fluidPage(
    shinyjs::useShinyjs(),
    actionButton("btn","Click me"),
    textOutput("text")
  ),
  server = function(input,output, session) {
    observeEvent(input$btn, {
      withCallingHandlers({
        shinyjs::html("text", "")
        foo()
      },
        message = function(m) {
          shinyjs::html(id = "text", html = m$message, add = TRUE)
      })
    })
  }
))
36
DeanAttali

これはそれほどエレガントではないことはわかっていますが、capture.outputを使用して少し似た問題を回避しました。残念ながら、sinkmessage sとoutputの同時キャプチャを許可しません。それらを元の順序で取得することはできませんが、少なくとも両方のストリームを抽出できます(ここではHTMLになります)。

runApp(shinyApp(
  ui = fluidPage(
    uiOutput("test")
  ),
  server = function(input,output, session) {
    output$test <- renderUI({
      HTML(
      paste(capture.output(type = "message", expr = { 
        message(capture.output(type = "output", expr = {
          cat("test cat<br>")
          message("test message")
          cat("test cat2<br>")
          message("test message2")
        }))
      }), collapse="<br>")
  )})
 })
)

出力:

test message
test message2
test cat
test cat2

おそらく、ユーザーが両方をキャプチャするだけでなく、それらも分離したい場合、これは便利な回避策を提供します。 (あなたのshinyjsパッケージはきれいに見えます、それを見てみる必要があります!)