5

I found this code from J. Cheng as an example of freezeReactiveValue. However, before the plot is displayed, occasionally the error is momentarily displayed in place of the plot. (it takes a few changes of the inputs to get this.) As i understand, the problem is that for a short period of time - the X and Y (columns) are staying for the previous dataset, and don't match up to the new dataset. For example, I get error message "Error in FUN: object 'speed' not found" for a second after I select "pressure" dataset. (but only if beforehand "cars" dataset was selected with x=Speed and y=pressure.) Clearly, the plot is attempting to grab x variable before it had chance to be updated, but I don't know how to prevent this from happening. Would appreciate any tips you have!!! Thank you!

library(shiny)
library(ggplot2)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      selectInput("dataset", "Dataset", c("cars", "pressure", "mtcars")),
      selectInput("x", "x variable", character(0)),
      selectInput("y", "y variable", character(0))
    ),
    mainPanel(
      plotOutput("plot")
    )
  )
)

server <- function(input, output, session) {
  dataset <- reactive({
    get(input$dataset, "package:datasets")
  })

  observe({
    freezeReactiveValue(input, "x")
    freezeReactiveValue(input, "y")
    columns <- names(dataset())
    updateSelectInput(session, "x", choices = columns, selected =    columns[[1]])
    updateSelectInput(session, "y", choices = columns, selected = columns[[2]])
  })

  output$plot <- renderPlot({
    Sys.sleep(2)
    req(input$dataset,input$x,input$y)
    ggplot(dataset(), aes_string(input$x, input$y)) + geom_point()
  })
}

shinyApp(ui, server)
JustLearning
  • 180
  • 2
  • 12
  • 4
    you could add another check to `req` to see if the x and y are in the data set: `data <- dataset(); req(input$dataset, input$x, input$y, all(c(input$x, input$y) %in% colnames(data))); ggplot(data, aes_string(input$x, input$y)) + geom_point()` I don't use shiny so idk the proper way.. in this case you can remove the `Sys.sleep` as well – rawr May 14 '18 at 23:36
  • Thank you @rawr, this worked for me but I was hoping for a more generic solution, - a way to check if the X and Y inputs are """fresh""" and have been updated after dataset input has been changed. - the reason is - i have a real problem i'm trying to solve based on this example, (with data that is hard to reproduce in example here.) - In my case, the distinction between old x,y and new/fresh x, y inputs is not so clear as in this case, hence i'm cofused how to know i'm using x/y values after the update. Thank you! – JustLearning May 15 '18 at 00:06

1 Answers1

3

This is a little about reactivity priority and related to "invalidation of the selections". I think the only way to be assured of an atomic update (to both the data and the inputs), you need to combine the data update and input changes into the same block or risk dependent-chunks being executed out of desired-order (i.e., there are multiple paths in the reactivity chain).

One way is to use side-effect for everything, not just assigning $x and $y. (I am still looking for a solution here that does not require this side-effect ...) (I borrow from @rawr's comment.)

Using your ui, try this:

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

  observeEvent(input$dataset, {
    req(input$dataset)
    x <- get(input$dataset, "package:datasets")
    columns <- names(x)
    updateSelectInput(session, "x", choices = columns, selected = columns[[1L]])
    updateSelectInput(session, "y", choices = columns, selected = columns[[2L]])
    dataset(x)
  })

  output$plot <- renderPlot({
    req(dataset())
    columns <- names(dataset())
    req(all(c(input$x, input$y) %in% columns))
    ggplot(dataset(), aes_string(input$x, input$y)) + geom_point()
  })
}

where I've put the assignment to 'x' and 'y' into the same observe chunk that reassigns the data. With this, you are relatively guaranteed that the selectInputs will be updated immediately after input$dataset is changed.

r2evans
  • 141,215
  • 6
  • 77
  • 149