Aaron England
Aaron England

Reputation: 1273

Return reactive output from user-defined function in shiny

I am relatively new to shiny. I created an NBA win-probability model a few weeks ago and have been trying to create a shiny app that will generate the output from my model for which I have created a user-defined function.

In my user interface I want a place to enter numeric input value for "Home Points", "Away Points", and "Time Remaining". Once, values have been entered for these values I want the user to click an action button. After the action button is clicked I simply want the app to display the output from my function in the main panel. However, I am unable to figure out how to get this to work.

Here is my code:

library(shiny)

# Define UI for application that calculates win probability
ui <- fluidPage(

# Application title
titlePanel("Win Probability"),

# Sidebar layout with inputs and output definitions
sidebarLayout(

 #sidebar panel for inputs
  sidebarPanel(

    #Add numeric input for home team points
    numericInput(inputId = "home.pts", label = h3("Home Points"), value = 0),

    #Add numeric input for away team points
    numericInput(inputId = "away.pts", label = h3("Away Points"), value = 0),

    #Add numeric input for time remaining in fourth quarter
    numericInput(inputId = "time", label = h3("Time Remaining"), value = 0),

    #Add action buttion
    actionButton("goButton","Apply")),

  # Show output
  mainPanel(
     verbatimTextOutput("win_prob")
  )))

win_prob <- function(time, home.pts, away.pts) {
  #calculate point difference
  diff <- home.pts - away.pts
  #Store intercept and betas
  intercept <- 0.09564935
  b_time <- 0.01087832
  b_diff <- 0.5243092
  b_interact <- -0.03066952
  #calculate and store logit
  logit <- intercept + (time*b_time) + (diff*b_diff) + 
  ((time*diff)*b_interact)
  #function to change logit to probability
  logit2prob <- function(logit) {
    odds <- exp(logit)
    prob <- odds/(1+odds)
  }
  #Store probability
  prob <- logit2prob(logit)
  prob
}


# Define server to return win probability
server <- function(input, output) {

  #Store reactive values
  home.pts <- reactive({input$home.pts})
  away.pts <- reactive({input$away.pts})
  time <- reactive({input$time})

  output$win_prob <- renderPrint({win_prob(reactive({input$home.pts}), 
reactive({input$away.pts}), reactive({input$time}))})

}


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

If someone can please help me I would greatly appreciate it!

Thank you!

Upvotes: 2

Views: 2126

Answers (2)

A. Suliman
A. Suliman

Reputation: 13125

Using reactivity

server <- function(input, output) {

  #Store reactive values
   home.pts <- reactive({input$home.pts})
   away.pts <- reactive({input$away.pts})
   time <- reactive({input$time})
   output$win_prob <- renderPrint({win_prob(home.pts(), away.pts(), time())})

  }

Using ObserveEvent

server <- function(input, output) {
           data <- reactiveValues()

           observeEvent(input$goButton,{
                              data$home.pts <- input$home.pts
                              data$away.pts <- input$away.pts
                              data$time <- input$time

                            })
output$win_prob <- renderPrint({
req(data$home.pts)  #to delay displaying result until user press Apply 
win_prob(data$home.pts,data$away.pts, data$time)})
  }

Now you can see the deference between the two approaches

Upvotes: 1

kluu
kluu

Reputation: 2995

Well you don't need to store all your inputs in reactive values. They already update themselves. When you have an actionButton, the best way to trigger an event from the click on the button is to use observeEvent. If I understood well, I would rewrite your server function like this:

# Define server to return win probability
server <- function(input, output) {
  observeEvent(input$goButton, {
    output$win_prob <- renderPrint({
      win_prob(input$home.pts, 
               input$away.pts, 
               input$time)
    })
  })
}

Upvotes: 1

Related Questions