Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R Shiny: Reactive Error

I'm building my first Shiny app with the intent of creating a mortgage calculator and adjustable amoritization schedule. I am able to get the following code to render with runApp(), but it is not functional (i.e., doesn't output any values, nor display the graph). Further, it generates the following error in RStudio's console:

"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.)"

For background, I'm running: Win 7, 64-bit OS | R v3.1.1 | RStudio v0.98.944

And have tried implementing the procedures defined here with no luck: Shiny Tutorial Error in R R Shiny - Numeric Input without Selectors

ui.R

library(shiny)
shinyUI(
      pageWithSidebar(
      headerPanel(
            h1('Amoritization Simulator for Home Mortgages'), 
            windowTitle = "Amoritization Simulator"
      ),
      sidebarPanel(
            h3('Mortgage Information'),
            h4('Purchase Price'),
            p('Enter the total sale price of the home'),
            textInput('price', "Sale Price ($USD)", value = ""),
            h4('Percent Down Payment'),
            p('Use the slider to select the percent of the purchase price you 
              intend to pay as a down payment at the time of purchase'),
            sliderInput('per.down', "% Down Payment", value = 20, min = 0, max = 30, step = 1),
            h4('Interest Rate (APR)'),
            p('Use the slider to select the interest rate of the loan expressed
              as an Annual Percentage Rate (APR)'),
            sliderInput('apr', "APR", value = 4, min = 0, max = 8, step = 0.125),
            h4('Term Length (Years)'),
            p('Use the buttons to define the term of the loan'),
            radioButtons('term', "Loan Term (Years)", choices = c(15, 30), selected = 30),
            submitButton('Calculate')
            ),
      mainPanel(
            h3('Payment and Amoritization Simulation'),
            p('Use this tool to determine your monthly mortgage payment, 
              how much interest you will owe over the life of the loan, and how 
              you can reduce that amount with additional payment'),
            h4('Monthly Payment (Principal and Interest)'),
            p('This is the amount (in $USD) you would pay each month for a 
              mortgage under the terms you defined'),
            verbatimTextOutput("base.monthly.payment"),
            h4('Total Interest Over Life of Loan'),
            p('If paying just that amount per month, this is the total amount 
              in $USD you will spend on interest for that loan'),
            verbatimTextOutput("base.total.interest"),
            h4('Additional Principal Simulation'),
            p('One way to reduce the interest expense is to pay more principal 
              each month. Use the slider below to select an additional amount to
              include with your payment and see the reduction in interest expense
              for the life of the loan.'),
            sliderInput('add', "Additional Principal ($USD)", value = 250, min = 0, max = 1000, step = 25),
            p('Interest costs saved with this additional principal (in $USD)'),
            verbatimTextOutput("savings"),
            p('You will also pay the loan off the loan this many months early'),
            verbatimTextOutput("early"),
            plotOutput('plot')
            )
      )
)

server.R

library(shiny)
library(ggplot2)
library(scales)
shinyServer(
function(input, output) {
## determine baseline payment and interest total
price <- reactive({as.numeric(input$price)})
per.down <- reactive({input$per.down / 100})
int <- reactive({input$apr / 1200})
n <- reactive({input$term * 12})
base.monthly.payment <- (int() * price() * (1 - per.down()) * ((1 + int())^n())) / (((1 + int())^n()) - 1)
output$base.monthly.payment <- renderPrint({base.monthly.payment})
base.total.interest <- (base.monthly.payment * n()) - (price() * (1 - per.down()))
output$base.total.interest <- renderPrint({base.total.interest})
## create dataframe to populate with increments of additional payment
schedule <- data.frame(matrix(data = NA, nrow = 41, ncol = 6, 
                         dimnames = list(1:41, c("add", "add.n",
                                                "prin", "add.total.interest", 
                                                "savings", "early"))))
## initialize 'for' loop to populate possible amoritization totals
c <- 1
for (i in seq(0, 1000, 25)) {
      schedule$add[c] <- i
      schedule$add.n[c] <- log(((base.monthly.payment + i) / int()) / (((base.monthly.payment + i) / int()) - (price() * (1 - per.down())))) / log(1 + int())
      schedule$prin[c] <- round(price() * (1 - per.down()), digits = 2)
      schedule$add.total.interest[c] <- round(((base.monthly.payment + i) * schedule$add.n[c]) - schedule$prin[c], digits = 2)
      schedule$savings[c] <- round(base.total.interest - schedule$add.total.interest[c], digits = 2)
      schedule$early[c] <- round(n() - schedule$add.n[c], digits = 0)
      c <- c + 1
}
add <- reactive({input$add})
output$savings <- renderPrint({schedule$savings[which(schedule$add == add())]})
output$early <- renderPrint({schedule$early[which(schedule$add == add())]})
## create data.frame suitable for plotting
graph.data <- data.frame(matrix(data = NA, nrow = 82, ncol = 3, 
                                dimnames = list(1:82, c("add", "amount", "type"))))
c <- 1
for (i in seq(0, 1000, 25)) {
      graph.data$add[c] <- i
      graph.data$add[c + 1] <- i
      graph.data$amount[c] <- schedule$prin[which(schedule$add == i)]
      graph.data$amount[c + 1] <- schedule$add.total.interest[which(schedule$add == i)]
      graph.data$type[c] <- "Principal" 
      graph.data$type[c + 1] <- "Interest"
      c <- c + 2
}
## create plot of amoritization with line for additional principal amount
output$plot <- renderPlot({
ggplot(graph.data, aes(x = add, y = amount), color = type)
+ geom_area(aes(fill = type), position = 'stack', alpha = 0.75)
+ geom_vline(xintercept = add(), color="black", linetype = "longdash", size = 1)
+ labs(x = "Additional Principal/Month", y = "Total Cost")
+ scale_fill_manual(values=c("firebrick3", "dodgerblue3"), name = "Payment Component")
+ theme(axis.title.x = element_text(face = "bold", vjust = -0.7, size = 16), 
        axis.title.y = element_text(face = "bold", vjust = 2, size = 16),
        axis.text.x = element_text(size = 14), 
        axis.text.y = element_text(size = 14), 
        panel.margin = unit(c(5, 5, 5, 5), "mm"),
        plot.margin = unit(c(5, 5, 5, 5), "mm"),
        panel.background = element_blank(),
        panel.grid.major.y = element_line(colour = "gray"),
        panel.grid.minor.y = element_line(colour = "gray86"),
        panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank())
+ scale_x_continuous(labels = dollar)
+ scale_y_continuous(labels = dollar)
})
})

Thanks in advance for any help!

like image 733
Ryan S Avatar asked Oct 19 '14 19:10

Ryan S


People also ask

What is reactive programming in shiny?

In Shiny, there are three kinds of objects in reactive programming: reactive sources, reactive conductors, and reactive endpoints, which are represented with these symbols: The simplest structure of a reactive program involves just a source and an endpoint: In a Shiny application, the source typically is user input through a browser interface.

How do I validate an input in shiny?

You need to validate an input only once (in a reactive or render* expression). Shiny will pass the valuation results to any observer or expression that calls upon the input. You can personalize validation error messages by writing your own need functions or by styling validation output with CSS.

What does REQ mean in shiny?

Introducing req The req (...) function was introduced in Shiny 0.13 to simplify dealing with missing inputs and other preconditions. req is short for “require”, so req (x) can be read as either “require x to be available”.

What are reactive objects in shiny?

In Shiny, there are three kinds of objects in reactive programming: reactive sources, reactive conductors, and reactive endpoints, which are represented with these symbols: Reactive sources and endpoints The simplest structure of a reactive program involves just a source and an endpoint:


1 Answers

Your error is in the lines like this:

base.monthly.payment <- (int() * price() * (1 - per.down()) * 
  ((1 + int())^n())) / (((1 + int())^n()) - 1)

base.monthly.payment makes use of int(), n(), per.down() and price() which are all reactive. Therefore base.monthly.payment will also be reactive. So when you create it /assign a value you will need to wrap it in a reactive like so:

base.monthly.payment <- reactive ({
  (int() * price() * (1 - per.down()) * ((1 + int())^n())) / (((1 + int())^n()) - 1)
})

and refer to it as base.monthly.payment() just like you do for n(), int(), etc.

The same is true for many other objects in your code e.g.: schedule , base.total.interest, graph.data.

like image 103
John Paul Avatar answered Sep 27 '22 23:09

John Paul