Reputation: 359
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
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