Skip to content

Instantly share code, notes, and snippets.

@jcheng5
Created June 29, 2016 05:05
  • Star 15 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jcheng5/3830244757f8ca25d4b00ce389ea41b3 to your computer and use it in GitHub Desktop.
Someone at #useR2016 asked me if you can have Shiny execute code in observers/reactives but send the console output to the browser.
library(shiny)
withConsoleRedirect <- function(containerId, expr) {
# Change type="output" to type="message" to catch stderr
# (messages, warnings, and errors) instead of stdout.
txt <- capture.output(results <- expr, type = "output")
if (length(txt) > 0) {
insertUI(paste0("#", containerId), where = "beforeEnd",
ui = paste0(txt, "\n", collapse = "")
)
}
results
}
# Example usage
ui <- fluidPage(
pre(id = "console")
)
server <- function(input, output, session) {
observe({
invalidateLater(1000)
withConsoleRedirect("console", {
str(cars)
})
})
}
shinyApp(ui, server)
@wilsoncai1992
Copy link

Thanks Joe!

@daattali
Copy link

daattali commented Aug 4, 2016

@jcheng5 do you have a similar piece of code that could work when expr is a call to someone else's function that created output that you don't have control over, but you want to display that output in shiny in real-time? I've always used a different implementation because I wanted the output to be shown in shiny in real time.

library(shiny)

longfunc <- function() {
  message("Thinking...")
  Sys.sleep(1)
  message("Still thinking...")
  Sys.sleep(1)
  message("Done")
}

withConsoleRedirect <- function(containerId, expr) {
  # Change type="output" to type="message" to catch stderr
  # (messages, warnings, and errors) instead of stdout.
  txt <- capture.output(results <- expr, type = "message")
  if (length(txt) > 0) {
    insertUI(paste0("#", containerId), where = "beforeEnd",
             ui = paste0(txt, "\n", collapse = "")
    )
  }
  results
}

ui <- fluidPage(
  shinyjs::useShinyjs(),
  actionButton("joe", "Joe"),
  actionButton("dean", "Dean"),
  pre(id = "console")
)

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

  observeEvent(input$joe, {
     withConsoleRedirect("console", {
      longfunc()
    })
  })

  observeEvent(input$dean, {
    withCallingHandlers(
      longfunc(),
      # can use "warning" instead/on top of "message" to catch warnings too 
      message = function(m) {
        shinyjs::html("console", m$message, TRUE)
      }
    )
  })
}

shinyApp(ui, server)

Note that I don't know how to make withCallingHandlers() work with cat or print

@zx8754
Copy link

zx8754 commented Mar 28, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment