library(ggplot2)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggrepel)
## Warning: package 'ggrepel' was built under R version 4.3.3
#COSTS
current_rent <- 675.0
july1_rent <- 520.0
avg_food <- 300.0
target_food <- 200.0
insure_cost_semester <- 700.0
tuition_fee_semester <- 1600
#defining a function
cumulative_cost <- function(months) {
# Fixed values
current_rent <- 675.0
july1_rent <- 520.0
avg_food <- 300.0
target_food <- 200.0
insure_cost_semester <- 700.0
tuition_fee_semester <- 1600.0
# Choose appropriate rent based on month count
if (months < 2) {
rent_per_month <- current_rent
} else {
rent_per_month <- july1_rent
}
# Total rent and food
total_rent <- rent_per_month * months
total_food <- target_food * months
# Semester-based costs (assume 1 semester = 5 months)
semester_counter = -5 + months
semesters <- ceiling(semester_counter / 5)
total_insurance <- semesters * insure_cost_semester
total_tuition <- semesters * tuition_fee_semester
# Total cost
total_cost <- total_rent + total_food + total_insurance + total_tuition
return(total_cost)
}
#better functions which allows flexible cost changes and projections
initial_money <- 10000 # Example starting money
# Function to generate monthly cumulative cost
generate_projection <- function(name, months, rent, food, insure_cost, tuition_cost, transit, gym, income, initial_money) {
cumulative_costs <- numeric(months)
remaining_money <- numeric(months) # Initialize remaining_money vector
total_insurance <- 0
total_tuition <- 0
for (m in 1:months) {
total_rent <- rent * m
total_food <- food * m
total_gym <- gym * m
total_transit <- transit * m
total_income <- -income * m
#canadian government money
total_income = total_income - (200 * m)
if (m %% 5 == 0) {
total_insurance <- total_insurance + insure_cost
total_tuition <- total_tuition + tuition_cost
}
cumulative_costs[m] <- total_rent + total_food + total_insurance + total_tuition + total_gym + total_transit + total_income
remaining_money[m] <- initial_money - cumulative_costs[m]
}
# Return data frame with all projections
data.frame(
Month = 1:months,
CumulativeCost = cumulative_costs,
RemainingMoney = remaining_money,
Projection = name
)
}
# Define different projections (scenarios)
months <- 12
# Scenario 1: Baseline
proj1 <- generate_projection(
name = "Current Living Expenses",
months = months,
rent = 675, # Post-July rent
food = 300,
insure_cost = 700,
tuition_cost = 1600,
transit =40,
gym = 50,
income = 0,
initial_money = initial_money
)
# Scenario 2: Reduced Food Budget
proj2 <- generate_projection(
name = "Current Living Expenses + Income (400euros/month)",
months = months,
rent = 675,
food = 300, # Lower food cost
insure_cost = 700,
tuition_cost = 1600,
transit =40,
gym = 50,
income = 400,
initial_money = initial_money
)
#Gym, tight food budgeting, income
proj3 <- generate_projection(
name = "Reduced Rent and Income (400euros/month)",
months = months,
rent = 520, # Hypothetical rent hike
food = 300,
insure_cost = 700,
tuition_cost = 1600,
transit = 40,
gym = 50,
income = 400,
initial_money = initial_money
)
#Scenario 4: Bare minimum
proj4 <- generate_projection(
name = "Reduced Rent, Reduced Food (120euros/month)\nIncome (400euros/month), No Gym, No Transit ",
months = months,
rent = 520,
food = 120,
insure_cost = 700,
tuition_cost = 1600,
transit =0,
gym = 0,
income = 400,
initial_money = initial_money
)
proj5 <- generate_projection(
name = "Bare Minimum; Increased Income (850euros/month)",
months = months,
rent = 520,
food = 120,
insure_cost = 700,
tuition_cost = 1600,
transit =0,
gym = 0,
income = 850,
initial_money = initial_money
)
proj6 <- generate_projection(
name = "Realistic Projection: Low Food (200euros/month)\nNo Transit, Cheap Gym, Income (650euros/month)",
months = months,
rent = 520,
food = 200,
insure_cost = 700,
tuition_cost = 1600,
transit =0,
gym = 20,
income = 650,
initial_money = initial_money
)
proj7 <- generate_projection(
name = "Realistic Projection: Low Food (200euros/month)\nNo Transit, Cheap Gym, High Income (850euros/month)",
months = months,
rent = 520,
food = 200,
insure_cost = 700,
tuition_cost = 1600,
transit =0,
gym = 20,
income = 850,
initial_money = initial_money
)
# Combine all scenarios
all_proj <- bind_rows(proj1, proj2, proj3, proj4, proj5, proj6, proj7)
# Plot
label_data <- all_proj %>%
group_by(Projection) %>%
filter(Month == max(Month))
plot_colors <- RColorBrewer::brewer.pal(15, "Set2")
## Warning in RColorBrewer::brewer.pal(15, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
# Plot with direct labels
ggplot(all_proj, aes(x = Month)) +
# Remaining money line
geom_line(aes(y = RemainingMoney, color = Projection), linetype = "dashed", size = 0.5) +
# Cumulative cost line
geom_line(aes(y = CumulativeCost, color = Projection), size = 1.2) +
# Labels for each projection at the end
geom_text_repel(
data = label_data,
aes(label = Projection, y = CumulativeCost, color = Projection),
hjust = 0,
nudge_x = 0.5,
direction = "y",
show.legend = FALSE,
segment.color = "grey50"
) +
# Horizontal dotted line at y = 0 (baseline for remaining money)
geom_hline(yintercept = 0, linetype = "dotted", color = "black") +
scale_color_manual(values = plot_colors) + # Color the lines using fcolors vector
labs(
title = "Cumulative Cost and Remaining Money Projections (Semester Costs Start at Month 5)",
x = "Month",
y = "Amount (Euros)",
color = "Scenario"
) +
theme_classic() +
theme(legend.position = "none") + # Remove legend
xlim(1, max(all_proj$Month) + 10) # Add space for labels to the right
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

#calculating the regression
#first create a lookup table
income_lookup <- tibble::tibble(
Projection = c(unique(all_proj$Projection)),
MonthlyIncome = c(0, 400, 400, 400, 850, 650, 850) # Add corresponding income for each projection
)
all_proj_avgs <- all_proj %>%
left_join(income_lookup, by = "Projection") %>%
mutate(
TotalIncome = Month * (MonthlyIncome + 200), # Include Canadian gov. support
NetCost = CumulativeCost - TotalIncome # Net cost after income
)
library(broom)
average_net_costs <- all_proj_avgs %>%
group_by(Projection) %>%
do(tidy(lm(NetCost ~ Month, data = .))) %>%
filter(term == "Month") %>%
rename(AverageMonthlyNetCost = estimate) %>%
select(Projection, AverageMonthlyNetCost)
#Integration with shiny app.
library(shiny)
library(shinyjs)
##
## Attaching package: 'shinyjs'
## The following object is masked from 'package:shiny':
##
## runExample
## The following objects are masked from 'package:methods':
##
## removeClass, show
library(ggplot2)
library(dplyr)
# UI part of the Shiny app
ui <- fluidPage(
useShinyjs(), # Enable shinyjs functionality
titlePanel("Resizable Sidebar Panel"),
# Layout
sidebarLayout(
sidebarPanel(
# Button to toggle visibility of numeric inputs
actionButton("toggle_btn", "Toggle Inputs"),
# Create a container div to wrap the numeric inputs (only these will be toggled)
div(id = "numeric-inputs-container",
fluidRow(
column(4, # First column (left side)
numericInput("months", "Number of Months", 12, min = 1),
numericInput("initial_money", "Starting Money (€)", 10000),
numericInput("rent", "Monthly Rent (€)", 520),
numericInput("food", "Monthly Food (€)", 200)
),
column(4, # Second column (middle)
numericInput("gym", "Monthly Gym (€)", 20),
numericInput("transit", "Monthly Transit (€)", 0)
),
column(4, # Third column (right side)
numericInput("income", "Monthly Income (€)", 850),
numericInput("insure", "Insurance per Semester (€)", 700),
numericInput("tuition", "Tuition per Semester (€)", 1600)
)
)
),
# Keep sliders outside the toggle container so they are always visible
sliderInput("rent_slider", "Rent Slider", min = 0, max = 2000, value = 520, step = 10),
sliderInput("food_slider", "Food Slider", min = 0, max = 2000, value = 200, step = 10),
sliderInput("income_slider", "Income Slider", min = 0, max = 2000, value = 850, step = 10)
),
# Main panel for displaying the plot
mainPanel(
plotOutput("costPlot", height = "90vh") # Full height of the viewport
)
)
)
# Server part of the Shiny app
server <- function(input, output, session) {
# Toggle the visibility of numeric inputs
observeEvent(input$toggle_btn, {
# Hide or show the numeric inputs container using shinyjs::toggle
toggle("numeric-inputs-container") # Toggle visibility of the numeric inputs container
})
# Create a reactive expression for projection data that automatically updates when inputs change
projection_data <- reactive({
# Use the slider values directly for calculation
months <- input$months
cumulative_costs <- numeric(months)
remaining_money <- numeric(months)
total_insurance <- 0
total_tuition <- 0
for (m in 1:months) {
# Use slider values in the calculations
total_rent <- input$rent_slider * m
total_food <- input$food_slider * m
total_gym <- input$gym * m
total_transit <- input$transit * m
if (m %% 5 == 0) {
total_insurance <- total_insurance + input$insure
total_tuition <- total_tuition + input$tuition
}
# Expense only (without income)
cumulative_costs[m] <- total_rent + total_food + total_gym + total_transit + total_insurance + total_tuition
# Now subtract income directly from cumulative cost
income <- input$income_slider * m + 200 * m # Use the income slider
cumulative_costs[m] <- cumulative_costs[m] - income
# Calculate remaining money (starting with initial money)
remaining_money[m] <- input$initial_money - cumulative_costs[m]
}
tibble(
Month = 1:months,
CumulativeCost = cumulative_costs,
RemainingMoney = remaining_money
)
})
# Render the plot based on the reactive data
output$costPlot <- renderPlot({
df <- projection_data()
ggplot(df, aes(x = Month)) +
geom_line(aes(y = CumulativeCost, color = "Cumulative Cost"), size = 1.2) +
geom_line(aes(y = RemainingMoney, color = "Remaining Money"), linetype = "dashed", size = 1.2) +
geom_hline(yintercept = 0, linetype = "dotted") +
labs(
title = "Cumulative Cost and Remaining Money Over Time",
y = "€ Amount",
x = "Month"
) +
scale_color_manual(values = c("Cumulative Cost" = "red", "Remaining Money" = "blue")) +
theme_minimal() # Static plot
})
}
# Run the app
shinyApp(ui, server)
Shiny applications not supported in static R Markdown documents