Home > database >  Repeatedly running a function over a reactive dataframe in RShiny
Repeatedly running a function over a reactive dataframe in RShiny

Time:01-13

I am building an RShiny app that I want to display some outputs based on the a dataframe.

The dataframe is generated within the app based on some UI inputs.

I have a function that I want to run over the dataframe.

I can achieve this once (or multiple times if I repeat the block of code)

But what I'd like to be able it so the function is run x times based on another UI input.

In my example the app should display two graphs. The first where the sample has 1 added to their age, and the second where this is done as many times as the user input.

# Define UI for application that draws a histogram
ui <- fluidPage(
  
  # Application title
  titlePanel("Ipsum Lorem"),
  
  # Sidebar with sliders for input numbers 
  sidebarLayout(
    sidebarPanel(
      
      sliderInput("n_Age",
                  "Base Number:",
                  min = 100, max = 500,
                  value = 100),
      
      sliderInput("projection",
                  "Number of repeated runs:",
                  min = 1,max = 5,
                  value = 2),
      
      actionButton("refresh", "New Random Sample")
    ),
    
    # Show a plot of the generated distribution
    mainPanel(
      
      tabsetPanel(type = "tabs",
                  
                  tabPanel("Plot", 
                           h4("Graphs of rando numbers"),
                           plotOutput("distPlot1"),

                           br(),hr(),br(),
                           plotOutput("distPlot2")),
                  
                  tabPanel("Table", 
                           h4("Table of invisible numbers"))
      )
    )
  )
)

# Define server logic required to draw a histogram
server <- function(input, output, session) {
  
  dataInput1 <- reactive({
    
    input$refresh
    
    # creates base data.frame of IDs and ages from Base number
    df01 = data.table(1:input$n_Age, round((rnbinom(input$n_Age, 10, 0.28) 24),0))
    colnames(df01) = c("ID","Age")
    return (df01)
  })
  
  # creates the Ageing function
  fxx1 = function(a) {
    a$Age = a$Age   1
    a$ID = c(1:length(a$Age))
    a
  }
  
  # runs the Ageing function once 
  dataInput2 <- reactive({
    df01 = fxx1(dataInput1())
    return(df01)
  })
  
  # plots the results
  output$distPlot1 <- renderPlot({
    ggplot(dataInput2(), aes(Age)) 
      geom_bar(width = 0.75) 
      theme_minimal()
      })
  
  ##### THIS IS THE PROBLEM I THINK #####
  # runs the Ageing function x times based on projection slider 
  dataInput3 <- reactive({
    for (i in 1:(input$projection))
    {
      df01 = fxx1(dataInput2())
    }
    return(df01)
  })
  
  # plots the results
  output$distPlot2 <- renderPlot({
    ggplot(dataInput3(), aes(Age)) 
      geom_bar(width = 0.75) 
      theme_minimal()
      })

}

# Run the application 
shinyApp(ui = ui, server = server)

The above just produces two identical graphs.

I trailed the for loop outside of shiny and it works as I want it to, I think the problem is probably that the loop effectively resets each run, always using the same dataframe instead of the product of the previous run, but I can't think of any solutions. Also FYI the real function is a good bit more complicate than my example.

CodePudding user response:

Actually your plots are not identical. They are shifted by one year. But you are right, your for loop is doing nothing, as in each iteration df01 is computed as df01 = fxx1(dataInput2()). Instead I would suggest to init df01 as dataInput2() outside of the loop. Then, inside the loop do df01 <- fxx1(df01):

library(shiny)
library(ggplot2)
library(data.table)

# Define UI for application that draws a histogram
ui <- fluidPage(

  # Application title
  titlePanel("Ipsum Lorem"),

  # Sidebar with sliders for input numbers
  sidebarLayout(
    sidebarPanel(
      sliderInput("n_Age",
        "Base Number:",
        min = 100, max = 500,
        value = 100
      ),
      sliderInput("projection",
        "Number of repeated runs:",
        min = 1, max = 5,
        value = 2
      ),
      actionButton("refresh", "New Random Sample")
    ),

    # Show a plot of the generated distribution
    mainPanel(
      tabsetPanel(
        type = "tabs",
        tabPanel(
          "Plot",
          h4("Graphs of rando numbers"),
          plotOutput("distPlot1"),
          br(), hr(), br(),
          plotOutput("distPlot2")
        ),
        tabPanel(
          "Table",
          h4("Table of invisible numbers")
        )
      )
    )
  )
)

# creates the Ageing function
fxx1 <- function(a) {
  a$Age <- a$Age   1
  a$ID <- seq_along(a$Age)
  a
}

# Define server logic required to draw a histogram
server <- function(input, output, session) {
  dataInput1 <- reactive({
    input$refresh

    # creates base data.frame of IDs and ages from Base number
    df01 <- data.table(1:input$n_Age, round((rnbinom(input$n_Age, 10, 0.28)   24), 0))
    colnames(df01) <- c("ID", "Age")
    return(df01)
  })

  # runs the Ageing function once
  dataInput2 <- reactive({
    df01 <- fxx1(dataInput1())
    return(df01)
  })

  # plots the results
  output$distPlot1 <- renderPlot({
    ggplot(dataInput2(), aes(Age))  
      geom_bar(width = 0.75)  
      theme_minimal()
  })

  # runs the Ageing function x times based on projection slider
  dataInput3 <- reactive({
    df01 <- dataInput2()
    for (i in seq_len(input$projection)) {
      df01 <- fxx1(df01)
    }
    return(df01)
  })

  # plots the results
  output$distPlot2 <- renderPlot({
    ggplot(dataInput3(), aes(Age))  
      geom_bar(width = 0.75)  
      theme_minimal()
  })
}

# Run the application
shinyApp(ui = ui, server = server)
#> 
#> Listening on http://127.0.0.1:8721

  • Related