16

I have a simple app, below, that displays a ggplot. ggplot generates a warning in the console (see picture at bottom). I'd like to capture the warning, and display it in the app, under the plot.

Here's my code:

library(shiny)
library(ggplot2)

ui <- fluidPage(

   titlePanel("How do i output ggplot warnings? :("),
   mainPanel(
       plotOutput("my_plot_that_generates_warnings"),
       tags$br(),
       verbatimTextOutput(outputId='ggplot_warnings')
   )
)

server <- function(input, output) {

    messages <- reactiveValues(ggplot_warning = 'How to capture warning and display it?')
    output$my_plot_that_generates_warnings <- renderPlot({
        tryCatch({

            ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width)) +
                geom_point() +
                geom_smooth()

        }, message = function(e) {
            messages$ggplot_warning <- e$message
        }, warning = function(e) {
            messages$ggplot_warning <- e$message
        }, error = function(e) {
            messages$ggplot_warning <- e$message
        })
    })

    output$ggplot_warnings <- renderPrint({
        cat(messages$ggplot_warning)
    })
}

shinyApp(ui = ui, server = server)

I assume the underlying problem has to do with lazy evaluation and the fact that the graph doesn't actually get rendered (and the warning generated) until after the trycatch. I can actually get the warning to appear in the verbatimTextOutput by wrapping ggplot call in a print(), but then of course the plot doesn't show up.

In my ignorance of the problem I've tried force() rather than print() but it didn't work.

enter image description here

markus
  • 25,843
  • 5
  • 39
  • 58
shaneker
  • 375
  • 2
  • 8
  • Have you tried the evaluate package (see: https://cran.r-project.org/web/packages/evaluate/index.html)? Based on https://stackoverflow.com/a/4963132/8757228 you might save your warning into a variable first and then display it whereever you want independent of your plot output. – alex_555 Nov 29 '18 at 10:36

1 Answers1

9

When you call ggplot it creates an object of type ggplot, as far as my understanding goes, internally, the messages aren't generated till you call print() on the object. There's an explanation on similar issue wrt messages so have a read Why does ggplot not allow suppressing of messages generated by its geoms?.

What we can do is explicitly print the ggplot and capture the messages

library(shiny)
library(ggplot2)

ui <- fluidPage(

  titlePanel("This is now fixed :)"),
  mainPanel(
    plotOutput("my_plot_that_generates_warnings"),
    tags$br(),
    verbatimTextOutput(outputId='ggplot_warnings')
  )
)

server <- function(input, output) {

  data <- reactive({
    ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width)) +
      geom_point() +
      geom_smooth()
  })

  dataerrors <- reactive({
    tryCatch({
      print(data())
    }, message = function(e) {
      return(e$message)
    }, warning = function(e) {
      return(e$message)
    }, error = function(e) {
      return(e$message)
    })
  })

  output$my_plot_that_generates_warnings <- renderPlot({
    data()
  })

  output$ggplot_warnings <- renderPrint({
    dataerrors()
  })
}

shinyApp(ui = ui, server = server)

enter image description here

Pork Chop
  • 28,528
  • 5
  • 63
  • 77
  • 2
    One issue seems to be capturing multiple messages and warnings. If, for example, there are NAs in my data, there are multiple warnings generated (for each column with NAs)... Only 1 warning is captured with the current solution. Additionally, the geom_smooth warning actually comes as a message. So if there are warnings *and* messages I will only get one of those. Any ideas? :) – shaneker Nov 29 '18 at 21:28
  • well, i "solved" it by using some stuff out out https://adv-r.hadley.nz/conditions.html basically, i used `withCallingHandlers` and built up a list of all messages/warnings, but it is sloooowwwww. – shaneker Nov 29 '18 at 22:09
  • If this is an issue, you can either switch to other charting library, such as `highcharter`, `dygraphs`, `rCharts`, `billboarder`, `plotly` or write your own error handling with `req` and `need` – Pork Chop Nov 30 '18 at 07:51