Search code examples
rshinyshiny-servershinydashboardreactive

R/RShiny Scoping - Global environment, avoid re-calculations reaction output?


I have a general question about when users make a change to an input value in Shiny and how to respond to that change efficiently.

First, I will paint the picture with words, then I will try and create a minimal version of what I am talking about with code.

Action: User changes drop down menu to select a specific item.

Reaction: A filter function, based on that user input is applied to an output variable and displayed on the screen.

Issue: I want to apply that filter for all of my output values on display (without having to call that filter function again).

Currently, I am calling the same function with my filters as arguments to that function for each of my outputvariables. This seems like a waste of computation because I really only need to call the function one time, use ALL of that data to populate all of my output values.

I feel like I am missing something fundamental here.

Ideally, I would like to be able to call something like this (returns a list containing a tibble and some other calculated values):

test <- reactive({se_report_filtered(my_filter = input$PM_ID, 
                                          start_year = input$obs[1], 
                                          end_year = input$obs[2])})

se_report_filtered is a function that actually calculates new values for me and returns a list.

Then use test to populate all of the other output values. I can't seem to get that to work. Instead, I cam calling se_report_filtered for each of my outputs. This seems like the wrong approach.

This is not a fully reproducible snippet but I am hoping the idea comes across still.

library(shiny)
library(shinydashboard)

header <- dashboardHeader(title = "Home")

frow1 <- fluidRow(
  valueBoxOutput("value2"), 
)


body <- dashboardBody(frow1)

#completing the ui part with dashboardPage
ui <- dashboardPage(title = 'Review', header, sidebar, body, skin='red')


server <- function(input, output) {

output$value2 <- renderValueBox({ 
    valueBox(
      formatC(se_report_filtered(my_filter = input$PM_ID, 
                                 start_year = input$obs[1], 
                                 end_year = input$obs[2])[[2]], 
              format="d", big.mark=',')
      ,'Total Met'
      ,icon = icon("stats",lib='glyphicon')
      ,color = "green")  
  })
}

shinyApp(ui, server)

So, essentially, I want to replace:

output$value2 <- renderValueBox({ 
        valueBox(
          formatC(se_report_filtered(my_filter = input$PM_ID, 
                                     start_year = input$obs[1], 
                                     end_year = input$obs[2])[[2]], 
                  format="d", big.mark=',')
          ,'Total Met'
          ,icon = icon("stats",lib='glyphicon')
          ,color = "green")  
      })

with

output$value2 <- renderValueBox({ 
        valueBox(
          formatC(test[[2]], 
                  format="d", big.mark=',')
          ,'Total Met'
          ,icon = icon("stats",lib='glyphicon')
          ,color = "green")  
      })

I believe I am missing something fundamental when it comes to dealing with reactive variables.


Solution

  • Again I am not sure what your function does so I am creating a reactive list with the fourth element being an input from a slider. When I call the reactive variable I assign it to a regular variable before sub-setting the fourth out. This is all done within the render function.

    library(shiny)
    library(shinydashboard)
    
    ui  <- fluidPage(
      fluidRow(
        valueBoxOutput("value2"),
        sliderInput("slider","Fourth Element", 1, 10, 5)
      ))
    
    server <- function(input, output, session) { 
    
      test<-reactive(list(1,2,3,input$slider))
    
      output$value2 <- renderValueBox({ 
        Test<-test()
        Test<-Test[4]
        valueBox(
          formatC(Test, 
                  format="d", big.mark=',')
          ,'Total Met'
          ,icon = icon("stats",lib='glyphicon')
          ,color = "green")  
      })
    
    
    
    }
    
    
    shinyApp(ui = ui, server = server)
    

    Since the render function is a reactive environment, it responds to changes in changes to reactive variables, in this case test().

    In your case test() returns whatever is created inside of se_report_filtered, it can be subset the same way.