Reactive values for a shiny plot and table

Hi,

I wish to have a shiny app created where I will plot two dataframes in ggplot, then do some simple stats calcs on a variable and plot a summary table underneath it. If I leave the table calculations out then I can plot the line plots just fine and have them change based on the $input function. The problem comes when I try to have the table update based on the $input value from the ui.

Looking through past examples on Stack Overflow and YouTube, it looks like I have to define the variable in the server section before calling the output$plot and rendertable functions.

Also from those examples my understanding is that a reactive input is what I'm after, but I still get the Operation not allowed without an active reactive context error and am going in circles trying to get it to work.

library(shiny)
library(ggplot2)

# Define UI for application
ui <- fluidPage(
  titlePanel("Random Dataset"),
  sidebarLayout(
    sidebarPanel(
      h4("Input Data"),
      sliderInput("pbins", "Multiplier:", min = 1,max = 5, value = 2)
    ),
    # Show a plot of the generated distribution
    mainPanel(
      h4("Distribution"),
      plotOutput("distPlot")
      h4("Table"),
      tableOutput("table")
    )
  )
  
)

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

  i <- 100
  x <- runif(i)
  y <- runif(i)
  # z is a function of y and the slider input (1 to 5)
  z <- reactive ({(y*input$pbins)})

  
    output$distPlot <- renderPlot({

    df <- data.frame("x" = x, "y" = y, "condition" = "nominal")
    df2 <- data.frame("x" = x, "z" = z(), "condition" = "varied")
    
    ggplot()+
      geom_line(data = df, aes(x = x, y = y), colour = "blue") +
      geom_line(data = df2, aes(x = x, y = z), colour = "red")
    
  })
  m_z <- mean(z())
  sd_z <- sd(z())

  results <- data.frame("0", "0")
  results[1,1] = format(m_z, digits = 3)
  results[1,2] = format(sd_z, digits = 4)
  colnames(results) <- c("Mean z", "SD z")
  rownames(results) <- c("Stats")
  
  output$table <- renderTable(results)
}

shinyApp(ui = ui, server = server)

Things in the server section don't generally execute from top to bottom. Shiny builds a linked network of reactive objects which trigger each other in a fairly complex way. Check out the tutorials on RStudio:
https://shiny.rstudio.com/articles/understanding-reactivity.html

So a lot of your server code will only run once and won't react to changes in z(). You need something like

library(shiny)
library(ggplot2)

# global code runs once
i <- 100
x <- runif(i)
y <- runif(i)

# Define UI for application
ui <- fluidPage(
  titlePanel("Random Dataset"),
  sidebarLayout(
    sidebarPanel(
      h4("Input Data"),
      sliderInput("pbins", "Multiplier:", min = 1,max = 5, value = 2)
    ),
    # Show a plot of the generated distribution
    mainPanel(
      h4("Distribution"),
      plotOutput("distPlot"),
      h4("Table"),
      tableOutput("table")
    )
  )
)

# Define server logic required
server <- function(input, output) {
  
  # z is a function of y and the slider input (1 to 5)
  z <- reactive ({(y*input$pbins)})
  
  output$distPlot <- renderPlot({
    
    df <- data.frame(x = x, y = y, condition = "nominal")
    df2 <- data.frame(x = x, z = z(), condition = "varied")
    
    ggplot()+
      geom_line(data = df, aes(x = x, y = y), colour = "blue") +
      geom_line(data = df2, aes(x = x, y = z), colour = "red")
    
  })
  
  output$table <- renderTable({
    m_z <- mean(z())
    sd_z <- sd(z())
    
    results <- data.frame(0, 0)
    results[1,1] = format(m_z, digits = 3)
    results[1,2] = format(sd_z, digits = 4)
    colnames(results) <- c("Mean z", "SD z")
    rownames(results) <- c("Stats")
    results
  })
}

shinyApp(ui = ui, server = server)

Thank you, that works for the simple code that I used for the example thank you for the link. I tried some simple reactive equations my dataset but still getting the reactive error, even though from my understanding I'm just replicating the syntax you posted.

server <- function(input, output) {
  # user inputs an elevation
  elev <- reactive({(input$elevation)})
  
  # angles and weight are input
  HO_angle <- 7
  WperL <- 75
  HOangleRAD <- (90 - HO_angle) / (180) * pi
  
  #tension is calculated
  tension <- ((elev()) * WperL) / (1- (cos(HOangleRAD)))

I get the Operation not allowed without an active reactive contexterror again and looking at the detailed erro message, I assume it's tripping up on line #44 (which is the equation for tension <-

49: server [/Users/1329S/Riser Tool/Riser/risertoolapp.R#44]

tension should be a reactive ()

Ok. So does every expression depending on elevation need to be reactive? and if those expressions are reactive, then any subsequent expression based on them need to be reactive? I have another 11-12 expressions and then table plotting, stats calcs etc.

If they all have to be reactive that seems like a lot of work to get ractive values in a rendertable that follows my plot. it might be easier to just copy and paste the code from renderplot to rendertable, essentially running it twice

yes, you need chains of reactivity so your app runs reactively... thats largely the concept of shiny.
why would copy and pasting be easier, if they have the same content then make a single reactive that is their shared content, and call it twice in the two places its needed.

Thanks. Essentially I have calculations that generates a plot, then a summary table underneath it, which has some stats on the final calcs that the plot is based on.

So my understanding it that if I want both the plot and table to react to the input, all expressions that generate the ggplot line graph and the summary statistics will have to be reactive. In theory this isn't too bad but I have some while loops and some dataframe creations that would have to be reactive, not just simple assignments, which is beyond my knowledge of shiny at the moment.

You can often just put the other reactive bits inside the render block of the plot and table. If you want the plot and table to share some pre-calculations (e.g. somestuff()), make a separate somestuff <- reactive({}) for those bits.

By the way, somestuff refers to the reactive block itself (it's a bit like a function) and somestuff() refers to its value.

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.