0

I have a shiny app that uses fileInput and magick to read a user chosen image, and display it as a ggplot.

library(shiny)
library(magick)
library(ggplot2)

ui <- fluidPage(


   titlePanel(""),


   sidebarLayout(
      sidebarPanel(
        fileInput("current_image", "Choose image file")),


      mainPanel(
        plotOutput("current_image_plot")
      )
   )
)


server <- function(input, output) {

  output$current_image_plot <- renderPlot({
    req(input$current_image)
    myplot <- magick::image_read(input$current_image$datapath)
    myplot <- image_ggplot(myplot)
    return(myplot)
})
}

shinyApp(ui = ui, server = server)

However, I'd like to separate the logic of reading the image, from the logic of plotting the image. I tried putting the image_read inside its own observeEvent, but this threw the error The 'image' argument is not a magick image object.

I know that when I print class(myplot) within the observeEvent, it returns a magick-image object, so what has changed by the time I'm trying to access active_image?

library(shiny)
library(magick)
library(ggplot2)

ui <- fluidPage(


   titlePanel(""),

   sidebarLayout(
      sidebarPanel(
        fileInput("current_image", "Choose image file")),


      mainPanel(
        plotOutput("current_image_plot")
      )
   )
)


server <- function(input, output) {

  active_image <- observeEvent(input$current_image, {
    req(input$current_image)
    myplot <- magick::image_read(input$current_image$datapath)
    return(myplot)
  })

  output$current_image_plot <- renderPlot({
    req(input$current_image)
    myplot <- image_ggplot(active_image)
    return(myplot)
})
}

shinyApp(ui = ui, server = server)
Conor Neilson
  • 1,026
  • 1
  • 11
  • 27

1 Answers1

0

An observeEvent does not return an object. Use eventReactive instaed, that is, replace

  active_image <- observeEvent(input$current_image, {
    req(input$current_image)
    myplot <- magick::image_read(input$current_image$datapath)
    return(myplot)
  })

with

  active_image <- eventReactive(input$current_image, {
    req(input$current_image)
    myplot <- magick::image_read(input$current_image$datapath)
    return(myplot)
  })

or more concisely:

  active_image <- eventReactive(input$current_image, {
    req(input$current_image)
    magick::image_read(input$current_image$datapath)
  })

Now, active_image is a reactive conductor, it is not the value returned. You have to do active_image() to get the returned value:

  output$current_image_plot <- renderPlot({
    req(input$current_image)
    image_ggplot(active_image())
  })
Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225