web-dev-qa-db-fra.com

Est-il possible d'afficher les messages de la console (écrits avec `message`) dans une interface utilisateur brillante?

Je ne comprends pas trop le message de R vs chat vs print vs etc., mais je me demande s'il est possible de capturer des messages et de les afficher dans une application brillante?

Exemple: l'application suivante peut capturer des instructions cat (et imprimer également des instructions) mais pas des instructions de message

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

Message croisé du groupe Google brillant-discuter depuis que j'ai obtenu 0 réponses.

34
DeanAttali

Yihui m'a suggéré d'utiliser withCallingHandlers, et cela m'a permis de trouver une solution. Je ne savais pas trop comment utiliser cette fonction d'une manière qui ferait exactement ce dont j'avais besoin car mon problème était que j'avais une fonction qui imprimait plusieurs messages un à la fois et en utilisant une approche naïve, j'imprimais uniquement le dernier message. Voici ma première tentative (qui fonctionne si vous n'avez qu'un seul message à afficher):

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

Remarquez comment seulement two\n est sorti. Donc ma dernière solution a été d'utiliser la fonction html du package shinyjs (clause de non-responsabilité: j'ai écrit ce package), ce qui me permet de modifier ou d'ajouter le code HTML à l'intérieur d'un élément. Cela a fonctionné parfaitement - maintenant les deux messages ont été imprimés en temps réel.

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

Je sais que ce n'est pas aussi élégant, mais j'ai contourné un problème un peu similaire en utilisant capture.output; malheureusement sink ne permet pas la capture simultanée de message s et output cependant. Vous ne les obtenez pas dans l'ordre d'origine, mais vous pouvez au moins extraire les deux flux (ici en 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>")
  )})
 })
)

Production:

test message
test message2
test cat
test cat2

Peut-être que si l'utilisateur souhaite capturer les deux mais également les séparer, cela fournira une solution pratique. (Votre package shinyjs semble soigné, il faut y jeter un œil!)

1