Home > Enterprise >  Shiny: reactiveValues() which depends on a reactive()
Shiny: reactiveValues() which depends on a reactive()

Time:08-27

I'm trying to set up a reactiveValues() object whose elements depends on a reactive() but I keep getting an error which says what I'm trying to do can only be done inside a reactive consumer. Here's a minimal code example:

library(shiny)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      actionButton(inputId = "button1", "Generate"),
      actionButton(inputId = "button2", "Toggle")
    ),
    
    mainPanel(
      verbatimTextOutput("toggle"),
      verbatimTextOutput("dat_avail"),
      verbatimTextOutput("test")
    )
  )
)

server <- function(input, output) {
  
  toggle <- reactiveVal(FALSE)
  dat_avail <- reactiveVal(FALSE)
  observeEvent(input$button2, {
    toggle(!toggle())
  })
  
  dat <- eventReactive(input$button1, {
    x <- rnorm(10,0,1)
    y <- rnorm(10,0,2)
    data.frame(x,y)
  })
  
  observeEvent(input$button1, {
    dat_avail(TRUE)
  })
  
  test <- reactiveValues({
    if (toggle() & dat_avail()) {
      m = mean(dat()$x)
    }
    else {
      m = NULL
    }
  })

  output$toggle <- renderPrint({toggle()})
  output$dat_avail <- renderPrint({dat_avail()})
  output$test <- renderPrint({test()})
}

shinyApp(ui = ui, server = server)

If I replace my test bit with the following, then it works:

  test <- reactive({
    if (toggle() & dat_avail()) {
      mean(dat()$x)
    }
    else {
      NULL
    }
  })

but I'd rather be able to do this with test as a reactiveValues() object instead. Is that doable?

EDIT:

Here's a more complicated setup where the answer below doesn't do what I intend it to do.

library(shiny)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      actionButton(inputId = "button1", "Generate"),
      actionButton(inputId = "button2", "Toggle"),
      sliderInput(inputId = "yrange",
                  label = "Range (y)",
                  min = -10,
                  max = 10,
                  value = c(-2,2))
    ),
    
    mainPanel(
      verbatimTextOutput("toggle"),
      verbatimTextOutput("dat_avail"),
      verbatimTextOutput("test"),
      verbatimTextOutput("test2")
    )
  )
)

server <- function(input, output) {
  
  toggle <- reactiveVal(FALSE)
  dat_avail <- reactiveVal(FALSE)
  observeEvent(input$button2, {
    toggle(!toggle())
  })
  
  dat <- eventReactive(input$button1, {
    x <- rnorm(100,0,1)
    y <- rnorm(100,0,2)
    data.frame(x,y)
  })
  
  new_dat <- reactive({
    if (dat_avail()) {
      subset(dat(), y<=input$yrange[2], y>=input$yrange[1])
    }
    else {
      data.frame()
    }
  })
  
  observeEvent(input$button1, {
    dat_avail(TRUE)
  })
  
  test <- reactiveValues(m=NULL)
  
  observeEvent(toggle(),{
    test$m=
      if (toggle() & dat_avail()) {
        mean(dat()$x)
      }
    else {
      NULL
    }
  })
  
  test2 <- reactive({
    if (toggle() & dat_avail()) {
      mean(new_dat()$x)
    }
    else {
      NULL
    }
  })
  
  
  output$toggle <- renderPrint({toggle()})
  output$dat_avail <- renderPrint({dat_avail()})
  output$test <- renderPrint({test$m})
  output$test2 <- renderPrint({test2()})
}

shinyApp(ui = ui, server = server)

test2 is what I'm after but I'd like to do it with reactiveValues() instead of reactive().

CodePudding user response:

post the last edit :


  observe({
    test$m=
      if (toggle() & dat_avail()) {
        mean(new_dat()$x)
      }
    else {
      NULL
    }
  })
  
  • Related