Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a reactive expression in an if statement in shiny

Tags:

r

shiny

I am writing a shiny app where the output should depend on the value of a variable which is calculated in a reactive expression in shiny. Instead of reproducing the actual app I believe I have recreated my problem with the following simple app:

ui.R file:

   library(shiny)

   shinyUI(pageWithSidebar(

   headerPanel("Illustrating problem"),

   sidebarPanel(

   numericInput('id1', 'Numeric input, labeled id1', 0, min = 0, max = 100, step        =5)

  ),

  mainPanel(

    h4('You entered'),

    verbatimTextOutput("oid1"),

    verbatimTextOutput("odic")

  )
))

server.R file


library(shiny)

shinyServer(

  function(input, output) {

    output$oid1 <- renderPrint({input$id1})

    x<-reactive({5*input$id1})

    if (x()>50) output$oid2<-renderPrint({"You entered a number greater than 10"})

    else output$oid2<-renderPrint({"You entered a number less than or equal to 
10"})

  }
)

If I run it like this then I get the error: Error in .getReactiveEnvironment()$currentContext() :`

Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)

If I change the if statement to: if (x>50) ... then I get the error:

Error in x > 50 : comparison (6) is possible only for atomic and list types

When I change the if statement to: if (reactive({(x>50)})) ... then I get the error message:

Error in if (reactive({ : argument is not interpretable as logical

I'd greatly appreciate any help

like image 970
MSR Avatar asked Jan 15 '16 22:01

MSR


2 Answers

A couple problems. The first and biggest problem is that you don't seem to understand how reactivity works. The error says "operation not allowed without an active reactive context" and that's the problem - you're accessing x() inside the server function's main body but not within a reactive context. Any render* function is a reactive context for example. So to solve this you simple have to move the if statement inside the renderPrint.

The other small problem is that your output ids don't match (verbatimTextOutput("odic") vs output$oid2).

If you don't understand reactivity, I highly suggest you take half an hour to understand it better. This tutorial has a section on reactivity that can be helpful, or you can re-read the official shiny tutorial by RStudio.

Here's the code for your fixed app (I removed a bunch of useless UI elements)

library(shiny)
ui <- fluidPage(
  numericInput('id1', 'Numeric input, labeled id1', 0, min = 0, max = 100, step=5),
  verbatimTextOutput("oid1"),
  verbatimTextOutput("oid2")

)
server <- function(input, output, session) {
  output$oid1 <- renderPrint({input$id1})

  x<-reactive({5*input$id1})

  output$oid2<-renderPrint({
    if (x()>50) {
      "You entered a number greater than 10"
    } else {
      "You entered a number less than or equal to 10"
    }
  })
}
shinyApp(ui = ui, server = server)
like image 102
DeanAttali Avatar answered Sep 18 '22 00:09

DeanAttali


Note that Shiny works based according to an event driven model - as do pretty much all graphically oriented UIs (and today that is the vast majority). It is not a new concept, has been around since the 80s at least, but it is more complicated than a programming something that follows a single flowchart - it does take some getting used to.

Anyway, in Shiny reactive and output andobserve statements have to be at the top level, I don't think there are exceptions to this.

You probably want something like this:

library(shiny)

u <- shinyUI(pageWithSidebar(

  headerPanel("Illustrating problem"),

  sidebarPanel(
    numericInput('id1', 'Numeric input, labeled id1', 0, min = 0, max = 100, step =5)
  ),

  mainPanel(

    h4('You entered'),
    verbatimTextOutput("oid1"),
    verbatimTextOutput("oid2")

  )
))

s <- shinyServer(function(input, output) {

    output$oid1 <- renderPrint({input$id1})

    x<-reactive({5*input$id1})

    output$oid2<-renderPrint({
      if (x()>50){
         "You entered a number greater than 10"
      } else {
         "You entered a number less than or equal to 10"
      }
    }
  )
}
)
shinyApp(ui = u, server = s)

Yielding:

enter image description here

like image 35
Mike Wise Avatar answered Sep 22 '22 00:09

Mike Wise