Home > Software design >  Trying to pass a "fixed" input to a reactive shiny function - using purrr's pmap
Trying to pass a "fixed" input to a reactive shiny function - using purrr's pmap

Time:09-28

I am trying to build a basic Shiny App. I have the following fixed variables and a function.

################################
# Fixed variables
mtsSqrd = 10000
rent = 20 # per square foot
# Variables & Assumptions
# in mts squared
operatingExpensesPerc = 10
# general vacancy
vacancy = 0.10
purchasePrice = 1000000
capRate = 0.08
growthRateInc = 0.03
growthRateExp = 0.02

leveragedCapRateTableFunction = function(purchasePrice, capRate, equity){
  ####################################################
  # First year
  generalPotentialRev = mtsSqrd * rent
  generalVacancy = generalPotentialRev * vacancy
  effGrossRev = generalPotentialRev - generalVacancy
  operatingExpenses = mtsSqrd * operatingExpensesPerc
  netOpInc = effGrossRev - operatingExpenses
  # Subsequent years
  T = 5
  generalPotentialRev_T = generalPotentialRev*(1   growthRateInc)^(1:T)
  generalVacancy_T = generalPotentialRev_T * vacancy # we assume the vacancy rate is fixed over the years
  effGrossRev_T = generalPotentialRev_T - generalVacancy_T
  operatingExpenses_T = operatingExpenses*(1 growthRateExp)^(1:T)
  netOpInc_T = effGrossRev_T - operatingExpenses_T
  # Valuation at Sale
  # NOI at year 6
  salePrice = netOpInc_T[T] / capRate
  ####################################################
  #loanToValuePerc = loanToValue
  #loanToValue = purchasePrice * loanToValuePerc
  #equity = purchasePrice - loanToValue
  loanToValue = purchasePrice - equity
  
  interestRate = 0.06
  amortisationPeriod = 25 # years 
  interestRate_monthly = interestRate/12
  amortisationPeriod_monthly = amortisationPeriod*12
  years = 30
  months = years*12
  payment = FinCal::pmt(r = interestRate_monthly, n = amortisationPeriod_monthly, pv = loanToValue, fv = 0)
  amortTable = FinancialMath::amort.table(Loan = loanToValue, pmt = payment*-1, i = 0.06, ic = 12, pf = 12, plot = FALSE)
  amortSchedule = amortTable$Schedule %>%
    data.frame() %>%
    mutate(
      year = rep(1:amortisationPeriod, each = 12)
    )
  amortScheduleCalcs = amortSchedule %>% 
    group_by(year) %>% 
    summarise(
      sumInterestPaid = sum(Interest.Paid),
      sumPrincipal = sum(Principal.Paid)
    ) %>% 
    mutate(
      monthlyPayments = sumInterestPaid/12,
      #monthlyPrincipal = sumPrincipal/12
      InterestPrincipal = sumInterestPaid   sumPrincipal,
      monthlyInterestPrincipal = InterestPrincipal /12
    )
  cashFlows = bind_cols(
    amortScheduleCalcs[1:6, ],
    netOpInc = c(netOpInc, netOpInc_T)
  ) %>% 
    mutate(
      cashFlowAfterDebtService = netOpInc - InterestPrincipal
    )
  NOI_Year_6 = cashFlows$netOpInc[6]
  mortgageBalanceEOY_5 = amortSchedule$Balance[60]
  netSaleProceeds = salePrice - mortgageBalanceEOY_5
  # Leveraged returns
  cashFlowStreamsLeveraged = c(equity*-1, cashFlows$cashFlowAfterDebtService[1:T-1], cashFlows$cashFlowAfterDebtService[T]   netSaleProceeds)
  internalRateOfRetrunLeveraged = jrvFinance::irr(cashFlowStreamsLeveraged)
  return(internalRateOfRetrunLeveraged)
}

Running the function I can compute the following:

leveragedCapRateTableFunction(purchasePrice = 1000000, equity = 200000, capRate = 0.08)
[1] 0.2908751

However, I want to expand the function over to different combinations/scenarios of the capRate and purchasePrice. (Keeping the equity variable fixed.

In R I can define a new perc increase / decrease function and use expand grid to create the different combinations

percDecreaseIncreaseFunction = function(x, perc = perc, decrease = TRUE){
  if(decrease == TRUE){
    out = x   (x * - perc)
  } else {
    out = x   (x * perc)
  }
  return(out)
}

unleveragedCapRates = expand_grid(
  propertyPrices = c(percDecreaseIncreaseFunction(purchasePrice, 0.10, FALSE),
                     percDecreaseIncreaseFunction(purchasePrice, 0.05, FALSE),
                     purchasePrice,
                     percDecreaseIncreaseFunction(purchasePrice, 0.05, TRUE),
                     percDecreaseIncreaseFunction(purchasePrice, 0.10, TRUE)), 
  capRates = c(
    percDecreaseIncreaseFunction(capRate, 0.10, FALSE),
    percDecreaseIncreaseFunction(capRate, 0.05, FALSE),
    capRate, 
    percDecreaseIncreaseFunction(capRate, 0.05, TRUE),
    percDecreaseIncreaseFunction(capRate, 0.10, TRUE)
  ))

However, when I try to use pmap I

  1. can't get it to work in R.
pmap(list(
  ...1 = leveragedCapRates$propertyPrices,
  ...2 = leveragedCapRates$capRates,
  ...3 = equity,
),
~leveragedCapRateTableFunction(..1, ..2, ..3)
) 
   unlist() %>% 
   matrix(ncol = 5, byrow = FALSE) %>% 
   data.frame() %>% 
   set_names(unique(leveragedCapRates$propertyPrices)) %>% 
   add_column(capRates = unique(leveragedCapRates$capRates)) %>% 
   relocate(capRates, everything()) %>% 
   round(4)
  1. How can I pass an input$equity when I pass it through an eventReactive()?

In the following App.R - I am having difficulty at the following point in the eventReactive() part of the server function.

pmap(list(
  ...1 = unleveredInputs()$propertyPrices,
  ...2 = unleveredInputs()$capRates,
  ...3 = input$equity,
),
~leveragedCapRateTableFunction(..1, ..2, ..3)

The output should be a 5 x 5 matrix looking something like (but not the same numbers)

enter image description here

Code / App.R

library(tidyverse)
library(shiny)
library(shinyWidgets)

################################
# Fixed variables
mtsSqrd = 10000
rent = 20 # per square foot
# Variables & Assumptions
# in mts squared
operatingExpensesPerc = 10
# general vacancy
vacancy = 0.10
purchasePrice = 1000000
capRate = 0.08
growthRateInc = 0.03
growthRateExp = 0.02


#leveragedCapRateTableFunction(purchasePrice = 1000000, equity = 200000, capRate = 0.08)
leveragedCapRateTableFunction = function(purchasePrice, capRate, equity){
  ####################################################
  # First year
  generalPotentialRev = mtsSqrd * rent
  generalVacancy = generalPotentialRev * vacancy
  effGrossRev = generalPotentialRev - generalVacancy
  operatingExpenses = mtsSqrd * operatingExpensesPerc
  netOpInc = effGrossRev - operatingExpenses
  # Subsequent years
  T = 5
  generalPotentialRev_T = generalPotentialRev*(1   growthRateInc)^(1:T)
  generalVacancy_T = generalPotentialRev_T * vacancy # we assume the vacancy rate is fixed over the years
  effGrossRev_T = generalPotentialRev_T - generalVacancy_T
  operatingExpenses_T = operatingExpenses*(1 growthRateExp)^(1:T)
  netOpInc_T = effGrossRev_T - operatingExpenses_T
  # Valuation at Sale
  # NOI at year 6
  salePrice = netOpInc_T[T] / capRate
  ####################################################
  #loanToValuePerc = loanToValue
  #loanToValue = purchasePrice * loanToValuePerc
  #equity = purchasePrice - loanToValue
  loanToValue = purchasePrice - equity
  
  interestRate = 0.06
  amortisationPeriod = 25 # years 
  interestRate_monthly = interestRate/12
  amortisationPeriod_monthly = amortisationPeriod*12
  years = 30
  months = years*12
  payment = FinCal::pmt(r = interestRate_monthly, n = amortisationPeriod_monthly, pv = loanToValue, fv = 0)
  amortTable = FinancialMath::amort.table(Loan = loanToValue, pmt = payment*-1, i = 0.06, ic = 12, pf = 12, plot = FALSE)
  amortSchedule = amortTable$Schedule %>%
    data.frame() %>%
    mutate(
      year = rep(1:amortisationPeriod, each = 12)
    )
  amortScheduleCalcs = amortSchedule %>% 
    group_by(year) %>% 
    summarise(
      sumInterestPaid = sum(Interest.Paid),
      sumPrincipal = sum(Principal.Paid)
    ) %>% 
    mutate(
      monthlyPayments = sumInterestPaid/12,
      #monthlyPrincipal = sumPrincipal/12
      InterestPrincipal = sumInterestPaid   sumPrincipal,
      monthlyInterestPrincipal = InterestPrincipal /12
    )
  cashFlows = bind_cols(
    amortScheduleCalcs[1:6, ],
    netOpInc = c(netOpInc, netOpInc_T)
  ) %>% 
    mutate(
      cashFlowAfterDebtService = netOpInc - InterestPrincipal
    )
  NOI_Year_6 = cashFlows$netOpInc[6]
  mortgageBalanceEOY_5 = amortSchedule$Balance[60]
  netSaleProceeds = salePrice - mortgageBalanceEOY_5
  # Leveraged returns
  cashFlowStreamsLeveraged = c(equity*-1, cashFlows$cashFlowAfterDebtService[1:T-1], cashFlows$cashFlowAfterDebtService[T]   netSaleProceeds)
  internalRateOfRetrunLeveraged = jrvFinance::irr(cashFlowStreamsLeveraged)
  return(internalRateOfRetrunLeveraged)
}

percDecreaseIncreaseFunction = function(x, perc = perc, decrease = TRUE){
  if(decrease == TRUE){
    out = x   (x * - perc)
  } else {
    out = x   (x * perc)
  }
  return(out)
}






ui <- fluidPage(
  tags$h2("Change shiny app background"),
  setBackgroundColor("white"),
  
  # Application title
  titlePanel("Internal Rate of Return Computations"),
  
  fluidRow(
    column(3,
           numericInput("purchasePrice", label = "Price?", value = 1000000, min = 1),
           numericInput("equity", label = "Equity?", value = 200000, min = 1), # the max should be dependent on the max of the purchasePrice input
           numericInput("capRate", label = "Capital Expenditure?", value = 0.08, min = 0, max = 1, step = 0.01),
           actionButton("computeIRR", "Compute IRR!")
    ),
    column(9,
           dataTableOutput(("leveredirrTable"))
    )
  )
)


################################################################################

server <- function(input, output) {
  
  ############ Unlevereaged inputs #########################################
  unleveredInputs <- eventReactive(input$computeIRR, {
    expand_grid(
      propertyPrices = c(
        percDecreaseIncreaseFunction(x = input$purchasePrice, 0.10, FALSE),
        percDecreaseIncreaseFunction(input$purchasePrice, 0.05, FALSE),
        input$purchasePrice,
        percDecreaseIncreaseFunction(input$purchasePrice, 0.05, TRUE),
        percDecreaseIncreaseFunction(input$purchasePrice, 0.10, TRUE)
      ), 
      capRates = c(
        percDecreaseIncreaseFunction(input$capRate, 0.10, FALSE),
        percDecreaseIncreaseFunction(input$capRate, 0.05, FALSE),
        input$capRate, 
        percDecreaseIncreaseFunction(input$capRate, 0.05, TRUE),
        percDecreaseIncreaseFunction(input$capRate, 0.10, TRUE)
      )
      # equity = c(
      #   input$equity
      # )
    ) %>% 
      data.frame()
  })
  
  leveredIRR <- eventReactive(unleveredInputs(), {
    req(unleveredInputs())
    pmap(list(
      ...1 = unleveredInputs()$propertyPrices,
      ...2 = unleveredInputs()$capRates,
      ...3 = input$equity,
    ),
    ~leveragedCapRateTableFunction(..1, ..2, ..3)
    ) %>%
      unlist() %>%
      matrix(ncol = 5, byrow = FALSE) %>%
      data.frame() %>% 
      set_names(unique(unleveredInputs()$equity)) %>%
      add_column(capRates = unique(unleveredInputs()$capRates)) %>%
      relocate(capRates, everything()) %>%
      round(4)
  })
  output$leveredirrTable <- renderDataTable(leveredIRR(), options = list(pageLength = 5))
  observeEvent(unleveredInputs(), {
    print(leveredIRR())
  })
}

shinyApp(ui = ui, server = server)

CodePudding user response:

Try this

server <- function(input, output, session) {
  
  ############ Unlevereaged inputs #########################################
  unleveredInputs <- eventReactive(input$computeIRR, {
    expand_grid(
      propertyPrices = c(
        percDecreaseIncreaseFunction(x = input$purchasePrice, 0.10, FALSE),
        percDecreaseIncreaseFunction(input$purchasePrice, 0.05, FALSE),
        input$purchasePrice,
        percDecreaseIncreaseFunction(input$purchasePrice, 0.05, TRUE),
        percDecreaseIncreaseFunction(input$purchasePrice, 0.10, TRUE)
      ), 
      capRates = c(
        percDecreaseIncreaseFunction(input$capRate, 0.10, FALSE),
        percDecreaseIncreaseFunction(input$capRate, 0.05, FALSE),
        input$capRate, 
        percDecreaseIncreaseFunction(input$capRate, 0.05, TRUE),
        percDecreaseIncreaseFunction(input$capRate, 0.10, TRUE)
      )
      , equity = c(
        input$equity
      )
    ) %>% 
      data.frame()
  })
  
  leveredIRR <- eventReactive(unleveredInputs(), {
    req(unleveredInputs())
    A = unleveredInputs()$propertyPrices
    B = unleveredInputs()$capRates
    C = input$equity
    vars <- list(A, B, C)
    
    pmap(vars,  ~leveragedCapRateTableFunction(..1, ..2, ..3)
    ) %>%
      unlist() %>%
      matrix(ncol = 5, byrow = FALSE) %>%
      data.frame() %>%
      set_names(unique(unleveredInputs()$equity)) %>%
      add_column(capRates = unique(unleveredInputs()$capRates)) %>%
      relocate(capRates, everything()) %>%
      round(4)
  })
  output$leveredirrTable <- renderDataTable(leveredIRR(), options = list(pageLength = 5))
  observeEvent(unleveredInputs(), {
    print(leveredIRR())
  })
}

output

  • Related