Search code examples
rshinyshinyjs

Possible to show console messages (written with `message`) in a shiny ui?


I don't understand R's message vs cat vs print vs etc. too deeply, but I'm wondering if it's possible to capture messages and show them in a shiny app?

Example: the following app can capture cat statements (and print statements as well) but not message statements

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

Cross post from the shiny-discuss Google group since I got 0 answers.


Solution

  • Yihui suggested I use withCallingHandlers, and that indeed let me to a solution. I wasn't quite sure how to use that function in a way that would do exactly what I needed because my problem was that I had a function that printed out several messages one at a time and using a naive approach only printed the last message. Here is the my first attempt (which works if you only have one message to show):

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

    Notice how only two\n gets outputted. So my final solution was to use the html function from shinyjs package (disclaimer: I wrote that package), which lets me change or append to the HTML inside an element. It worked perfectly - now both messages got printed out in real-time.

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