I am building a plot of Net Present Value (NPV), using FinCal package, and its odds. For the NPV, the cash-flows are simulated using a triangular distribution for sales, normal distribution for costs and so on. So, here is a snippet of what I am doing:
The And, here is the Shiny code that uses the above snippet.
The problem is as follows. The same code when run in R, I get the plot right in terms of the NPV
curve, horizontal and vertical lines. Whereas, when run as a Shiny
application, the horizontal and vertical lines are hugely displaced.
This is despite, hiving of the NPV and cash-flows code into a separate
.R file and setting the same seed value for both the Shiny and non-shiny versions. For example, Here are the plots - with and without Shiny. Notice how the curve looks same but, the intersection of horizontal and vertical lines are off. imagebin.ca/v/3K47HvFC6Gt8 (with Shiny) and imagebin.ca/v/3K46LXO7ZvKs (without Shiny) |
--
You received this message because you are subscribed to the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this group and stop receiving emails from it, send an email to shiny-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/shiny-discuss/f1c5533f-43f0-4e55-9ce4-5548094e76f3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
# source(npd-c.R)
input <- list( varCostSd = 3, salesMode = 6000, demDeclMean = 0.9, fixedCostRange = c(36000, 44000), salesRange = c(500, 24000), hurdleRate = 0.1, varCostMean = 20, demDeclSd = 0.1, outlay = 0.5)
npvOddsPlot(input)
library(shiny)library(FinCal)library(dplyr)library(triangle)library(ggplot2)
SEED <- 2017ITERATIONS <- 5000MILLION <- 1000000
salesIter <- function(consts, threshold = -1) { y1 <- rtriangle(ITERATIONS, consts$SALES_TRIANG_MIN, consts$SALES_TRIANG_MAX, consts$SALES_TRIANG_MODE) demDecl <- rnorm( ITERATIONS, mean = consts$DEM_DECL_FACTOR_MEAN, sd = consts$DEM_DECL_FACTOR_SD ) yr1Demand <- round(y1, consts$DIGITS) y2 <- round(yr1Demand * demDecl, consts$DIGITS) yr2Demand <- ifelse(y2 <= threshold, 0.0, y2) yr3Demand <- round(yr2Demand * demDecl, consts$DIGITS) yr4Demand <- round(yr3Demand * demDecl, consts$DIGITS) sales <- data.frame(yr1Demand, yr2Demand, yr3Demand, yr4Demand) names(sales) <- c("Y1Sales", "Y2Sales", "Y3Sales", "Y4Sales") return (sales)}
revenueIter <- function(consts, sales) { revenue <- data.frame( round(sales$Y1Sales * consts$PRICE, consts$DIGITS), round(sales$Y2Sales * consts$PRICE, consts$DIGITS), round(sales$Y3Sales * consts$PRICE, consts$DIGITS), round(sales$Y4Sales * consts$PRICE, consts$DIGITS) ) names(revenue) <- c("Y1Revenue", "Y2Revenue", "Y3Revenue", "Y4Revenue") return (revenue)}
varCostIter <- function(consts, sales) { varCostRate <- rnorm(ITERATIONS, mean = consts$VAR_COST_RATE_MEAN, sd = consts$VAR_COST_RATE_SD) varCost <- data.frame( round(sales$Y1Sales * varCostRate, consts$DIGITS), round(sales$Y2Sales * varCostRate, consts$DIGITS), round(sales$Y3Sales * varCostRate, consts$DIGITS), round(sales$Y4Sales * varCostRate, consts$DIGITS) ) names(varCost) <- c("Y1VarCost", "Y2VarCost", "Y3VarCost", "Y4VarCost") return (varCost)}
fixedCostIter <- function(consts) { fixedCost <- runif(ITERATIONS, min = consts$FIX_COST_RATE_MIN, max = consts$FIX_COST_RATE_MAX) return (fixedCost)}
cashFlow <- function(consts, revenue, varCost, fixedCost) { cashFlow <- data.frame( revenue$Y1Revenue - varCost$Y1VarCost - fixedCost, revenue$Y2Revenue - varCost$Y2VarCost - fixedCost, revenue$Y3Revenue - varCost$Y3VarCost - fixedCost, revenue$Y4Revenue - varCost$Y4VarCost - fixedCost ) names(cashFlow) <- c("Y1", "Y2", "Y3", "Y4") return (cashFlow)}
cashFlowNpv <- function(consts, cashFlow) { n <- NULL outlay <- -1 * consts$OUTLAY * MILLION j <- ITERATIONS for (i in c(1:j)) { j <- cashFlow[i:i, ] yearlyCashFlow <- c(outlay, j$Y1, j$Y2, j$Y3, j$Y4) n <- append(n, round(npv( r = consts$HURDLE_RATE, cf = yearlyCashFlow ), consts$DIGITS)) } cashFlowNpv <- mutate(cashFlow, npvY0 = n) return (cashFlowNpv)}
salesCashFlowNpv <- function(consts, sales, cfNpv) { salesCashFlowNpv <- data.frame( Y1Sales = sales$Y1Sales, Y1CashFlow = cfNpv$Y1, Y2Sales = sales$Y2Sales, Y2CashFlow = cfNpv$Y2, Y3Sales = sales$Y3Sales, Y3CashFlow = cfNpv$Y3, Y4Sales = sales$Y4Sales, Y4CashFlow = cfNpv$Y4, NPV = cfNpv$npvY0 ) return(salesCashFlowNpv)
}
npvCdf <- function(n) { N <- sort(n) P <- ecdf(N) return(P)}
getBreakEven <- function(consts, n) { x <- filter(n, NPV >= 0) breakEvenNpv = min(x$NPV) breakEvenSales = round(select(filter(x, round(NPV, consts$DIGITS) == breakEvenNpv), Y1Sales)$Y1Sales, 0) return(breakEvenSales)}
npdDistribution <- function(consts, m) { N <- m$NPV / MILLION
P <- npvCdf(N) # # NPV distribution curve n <- sort(N) p <- P(n) * 100 df <- data.frame(npv = n, odds = p)
return(df)}
pointsOnPlot <- function(consts, m) { # Points of interest s <- getBreakEven(consts, m) o <- consts$NPV_BREAK_EVEN_WORST_ODDS
w <- o * 100
n <- m$NPV / MILLION n <- sort(n) q <- round((quantile(n, o)), consts$DIGITS) e <- consts$NPV_BREAK_EVEN_VALUE b <- npvCdf(m$NPV / MILLION)(0) * 100 p <- data.frame(s, o, w, q, e, b) names(p) <- c("s", "o", "w", "q", "e", "b") return(p)}
makePlot <- function(d, p) { # Labels npvOdds <- paste("Odds of break-even : ", p$b, "%") salesThresh <- paste("Sales threshold : ", p$s) worstCase <- paste("Worst case (@ 5% odds) : ", p$q, "million")
# # Make plot #
g <- ggplot(d, aes(x = d$npv, y = d$odds)) +
geom_line(colour = "blue") +
labs(title = "Net Present Value (NPV) and Odds") +
labs(x = "NPV (million)") + labs(y = "Percent (%)") +
geom_vline(xintercept = p$e,
colour = "red", linetype = "longdash") +
geom_hline(yintercept = p$b,
colour = "green", linetype = "longdash") +
geom_vline(xintercept = p$q,
colour = "green", linetype = "dotdash") +
geom_hline(yintercept = p$w, colour = "red", linetype = "dotdash") + annotate("text", x=4, y=75, label=npvOdds) return (g)}
buildOutputTable <- function(consts, p) { outputTable <- data.frame(consts$OUTLAY, consts$HURDLE_RATE * 100, p$b, p$s, p$q) names(outputTable) <- c("Outlay (mn)", "Hurdle Rate (%)", "BE Odds (%)", "BE Sales", "Wconsts Loss (mn)") return(outputTable)}
npvCalc <- function(consts, threshold = -1) { s <- salesIter(consts, threshold) r <- revenueIter(consts, s) v <- varCostIter(consts, s) f <- fixedCostIter(consts) c <- cashFlow(consts, r, v, f) n <- cashFlowNpv(consts, c) t <- salesCashFlowNpv(consts, s, n) return (t)}
npvPlot <- function(consts, threshold = -1) { set.seed(consts$SEED) n <- npvCalc(consts, threshold) d <- npdDistribution(consts, n) p <- pointsOnPlot(consts, n) g <- makePlot(d, p) return(g)}
npvTable <- function(consts, threshold=-1) { set.seed(consts$SEED) n <- npvCalc(consts, threshold) d <- npdDistribution(consts, n) p <- pointsOnPlot(consts, n) t <- buildOutputTable(consts, p) return(t)}
getConstants <- function(input) { consts <- data.frame( SEED, 3, 100, 0.0, 0.05, input$outlay, input$hurdleRate,
input$salesRange[1], input$salesRange[2], input$salesMode, input$demDeclMean, input$demDeclSd, input$varCostMean, input$varCostSd, input$fixedCostRange[1], input$fixedCostRange[2] )
names(consts) <- c("SEED", "DIGITS", "PRICE", "NPV_BREAK_EVEN_VALUE", "NPV_BREAK_EVEN_WORST_ODDS", "OUTLAY",
"HURDLE_RATE", "SALES_TRIANG_MIN", "SALES_TRIANG_MAX", "SALES_TRIANG_MODE", "DEM_DECL_FACTOR_MEAN", "DEM_DECL_FACTOR_SD", "VAR_COST_RATE_MEAN", "VAR_COST_RATE_SD", "FIX_COST_RATE_MIN", "FIX_COST_RATE_MAX" )
return(consts)}
npvOddsPlot <- function(input) { consts <- getConstants(input) threshold <- -1 g <- npvPlot(consts,threshold) return (g)}
npvOddsTable <- function(input) { consts <- getConstants(input) df <- npvTable(consts) return(df)}
ui <- fluidPage( titlePanel("New Product Introdction Demo"), sidebarLayout( sidebarPanel( sliderInput("outlay", label = "Initial Outlay (million)", min = 0.1, max = 10, value = 0.5), sliderInput("hurdleRate", label = "Hurdle Rate", min = 0.01, max = 1, value = 0.1), sliderInput("salesRange", label = "Range of sales", min = 100, max = 50000, value = c(500, 24000)), sliderInput("salesMode", label = "Mode of sales", min = 1000, max = 40000, value = 6000), sliderInput("demDeclMean", label = "Demand declining factor - Mean", min = 0.0, max = 1.0, value = 0.9), sliderInput("demDeclSd", label = "Demand declining factor - SD", min = 0.0, max = 1.0, value = 0.1), sliderInput("fixedCostRange", label = "Fixed Costs - Min and Max", min = 30000, max = 50000, value = c(36000, 44000)), sliderInput("varCostMean", label = "Variable Costs - Mean", min = 10, max = 50, value = 20), sliderInput("varCostSd", label = "Variable Costs - SD", min = 1, max = 10, value = 3) ), mainPanel( plotOutput("npdPlot"), tableOutput("npdTable") ) ))
server <- function(input, output, session) { output$npdPlot <- renderPlot({ print(reactiveValuesToList(input)) npvOddsPlot(reactiveValuesToList(input)) }) output$npdTable <- renderTable({ npvOddsTable(input) })}
shinyApp(ui, server)
input <- list( varCostSd = 3, salesMode = 6000, demDeclMean = 0.9, fixedCostRange = c(36000, 44000), salesRange = c(500, 24000), hurdleRate = 0.1, varCostMean = 20, demDeclSd = 0.1, outlay = 0.5)
npvOddsPlot(input)