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
}
})