Namra
Namra

Reputation: 359

How can I use a for loop in an R shiny app

Aim

I want to use a for loop in a shiny app. The code below will work without the for loop, but then fails to work with it.

Attempt

library(shiny)
library(dplyr)
library(lubridate)

#create table
dates <- seq(as.Date("2020-01-01"), as.Date("2022-04-01"), by="months")
supply <- floor(runif(28, min = 80000, max = 100000))
demand <- rep(0, length(dates))
shortfall <- ifelse(demand - supply > 0, demand -supply, 0)
df <- bind_cols(dates, supply, demand, shortfall)
names(df) <- c("dates", "supply", "demand", "shortfall")

# Define UI ----
ui <- navbarPage(
  
  titlePanel("Supply & Demand"),
  
  tabPanel(title = "Demand", 
           mainPanel(h3("Demand", align = "center"), 
                     plotOutput(outputId = "demand")), 
           sidebarPanel(sliderInput(inputId = "A", label = "A", min = 0, max = 50000, value = 5000), 
                        sliderInput(inputId = "B", label = "B", min = 0, max = 50000, value = 5000), 
                        sliderInput(inputId = "C", label = "C", min = 0, max = 50000, value = 5000))), 
  

  tabPanel(title = "Table", 
           mainPanel(h3("Table", align = "center"), 
                     tableOutput(outputId = "table")))
  
)

# Define server logic ----
server <- function(input, output) {

  df_ <- reactive({
    df %>% mutate(demand = input$A + input$B + input$C, 
                  shortfall = rep(0, 28),
                  returning_shortfall = c(10000, rep(0, 27)),
                  stored_shortfall = rep(0, 28),
                  total_demand = rep(0, 28))
  })
  
  df2_ <- reactive({
    
  for (i in 2:length(df_()$dates)) {
    df_()$total_demand[i] = df_()$demand[i] + df_()$returning_shortfall[i-1]
    df_()$shortfall[i] = ifelse(df_()$total_demand[i] - df_()$supply[i] > 0, df_()$total_demand[i] - df_()$supply[i], 0)
    df_()$returning_shortfall[i] = df_()$shortfall[i-1] * 0.15
    df_()$stored_shortfall[i] = df_()$stored_shortfall[i-1] + df_()$shortfall[i] * 0.15
  }
    
  })
  
  #Table
  output$table <- renderTable(df2_())

}
  
# Run the app ----
shinyApp(ui = ui, server = server)

Error message

Warning: Error in =: invalid (NULL) left side of assignment
  113: <reactive:df2_> [C:/Users/user/filename]
   97: df2_
   96: renderTable
   95: func
   82: renderFunc
   81: output$table
    1: runApp

Outcome Sought

Tha main challenge is creating a column that where each value relies on a previous row's value. "For loops" seems to solve that problem, but it does not work in shiny.

Upvotes: 1

Views: 1807

Answers (1)

YBS
YBS

Reputation: 21349

You just need one reactive object. Try this

library(shiny)
library(dplyr)
library(lubridate)

#create table
dates <- seq(as.Date("2020-01-01"), as.Date("2022-04-01"), by="months")
supply <- floor(runif(28, min = 8000, max = 20000))
demand <- rep(0, length(dates))
shortfall <- ifelse(demand - supply > 0, demand -supply, 0)
df1 <- bind_cols(dates, supply, demand, shortfall)
names(df1) <- c("dates", "supply", "demand", "shortfall")

# Define UI ----
ui <- navbarPage(
  
  titlePanel("Supply & Demand"),
  
  tabPanel(title = "Demand", 
           mainPanel(h3("Demand", align = "center"), 
                     plotOutput(outputId = "demand")), 
           sidebarPanel(sliderInput(inputId = "A", label = "A", min = 0, max = 50000, value = 5000), 
                        sliderInput(inputId = "B", label = "B", min = 0, max = 50000, value = 5000), 
                        sliderInput(inputId = "C", label = "C", min = 0, max = 50000, value = 5000))), 
  
  
  tabPanel(title = "Table", 
           mainPanel(h3("Table", align = "center"), 
                     tableOutput(outputId = "table")))
  
)

# Define server logic ----
server <- function(input, output) {
  
  
  df2 <- reactive({
    
    df <- df1 %>% mutate(demand = input$A + input$B + input$C, 
                  shortfall = rep(0, 28),
                  returning_shortfall = c(10000, rep(0, 27)),
                  stored_shortfall = rep(0, 28),
                  total_demand = rep(0, 28))
    
    for (i in 2:length(df$dates)) {
      df$total_demand[i] <- df$demand[i] + df$returning_shortfall[i-1]
      df$shortfall[i] <- ifelse(df$total_demand[i] - df$supply[i] > 0, df$total_demand[i] - df$supply[i], 0)
      df$returning_shortfall[i] <- df$shortfall[i-1] * 0.15
      df$stored_shortfall[i] <- df$stored_shortfall[i-1] + df$shortfall[i] * 0.15
    }
    df
  })
  
  #Table
  output$table <- renderTable(df2())
  
}

# Run the app ----
shinyApp(ui = ui, server = server)

Upvotes: 2

Related Questions