rshiny

Create a chain of reactive values in R Shiny


I’m planning to transform a large Excel model into R Shiny. Before starting to code, I’d like to clarify a few aspects. One of these involves translating the dependency logic from Excel, and I’ll explain it using a minimal example below.

Let’s assume we have one input, Input 1, and a simple 1 × 5 data frame. The value for Year 1 is based on real data.

enter image description here

  1. The values for the subsequent years depend on previous years. This relationship is demonstrated in the formula view in Excel below:

enter image description here

  1. Additionally, Input 1 also influences these years: enter image description here

Given that this method will apply to more than 200 variables, I’m wondering about the best practices for creating reactive values that:

  1. Depend on prior data (e.g., Year 2) or reactive data (e.g., from Year 3 onwards).
  2. Are also affected by Input 1.

I hope I’m not overthinking it—any feedback or suggestions would be much appreciated.


Solution

  • A direct translation would be to convert each formula cell into a reactive:

    library(shiny)
    
    ui <- fluidPage(
      sliderInput("input_1", "Input 1", min = 0.1, max = 2, value = 1.1),
      numericInput("year_1", "Year 1", value = 1),
      verbatimTextOutput("result"),
    )
    
    server <- function(input, output, session) {
      year_1 <- reactive(input$year_1)
      year_2 <- reactive(year_1() * input$input_1)
      year_3 <- reactive(year_2() * input$input_1)
      year_4 <- reactive(year_3() * input$input_1)
      output$result <- renderPrint({
        c(year_1(), year_2(), year_3(), year_4())
      })
    }
    
    shinyApp(ui, server)
    

    This is the most general approach but may not be particularly efficient.

    If you have a recursive formula it may be better to use a single reactive vector:

    library(shiny)
    
    ui <- fluidPage(
      sliderInput("input_1", "Input 1", min = 0.1, max = 2, value = 1.1),
      numericInput("year_1", "Year 1", value = 1),
      verbatimTextOutput("result"),
    )
    
    server <- function(input, output, session) {
      years <- reactive({
        values <- numeric(4)
        values[1] <- input$year_1
        for (i in seq_along(values)[-1]) {
          values[i] <- values[i - 1] * input$input_1
        }
        values
      })
      output$result <- renderPrint(years())
    }
    
    shinyApp(ui, server)
    

    But a more idiomatic approach in R would be to find an explicit formula, if available:

    library(shiny)
    
    ui <- fluidPage(
      sliderInput("input_1", "Input 1", min = 0.1, max = 2, value = 1.1),
      numericInput("year_1", "Year 1", value = 1),
      verbatimTextOutput("result"),
    )
    
    server <- function(input, output, session) {
      years <- reactive({
        input$year_1 * input$input_1^(seq_len(4) - 1)
      })
      output$result <- renderPrint(years())
    }
    
    shinyApp(ui, server)
    

    There's tradeoffs to each approach, depending on the details of your application.