College Debt Shiny App

R
Shiny
Data Visualization
Dashboard
Collaborating with Corey Cassell, we’ve developed an interactive tool aiding students in career and financial planning, empowering informed decisions.
Authors

Brian Cervantes Alvarez

Corey Cassell

Published

December 2, 2022

Modified

April 8, 2025

Yapper Labs | AI Summary Model: ChatGPT o3-mini-high

I collaborated with Corey Cassell to build an interactive Shiny dashboard that empowers high school students to make informed decisions by estimating salaries, tuition costs, and student debt. I performed extensive data wrangling on multiple datasets, implemented responsive UI elements, and developed custom visualizations using ggplot2 and Plotly to dynamically showcase higher education financial metrics. This project demonstrates my proficiency in integrating complex data pipelines, crafting interactive interfaces, and delivering insightful, user-friendly visualizations that guide future college financial planning.

Overview

In collaboration with Corey Cassell, our team developed an interactive tool tailored to support students in making informed decisions about their educational journey. This tool offers crucial financial insights, including salary and tuition estimators, as well as a debt calculator, empowering users to navigate their educational choices confidently. By exploring potential salaries, estimating tuition costs, and visualizing projected student debts, individuals can gain valuable perspectives on the financial aspects of their chosen career paths. Recognizing the significance of financial considerations in higher education, our tool comprises four essential components: salary estimator, tuition estimator, debt estimator, and debt calculator. Together, these components provide a comprehensive platform for prospective students to assess potential earnings, anticipate tuition expenses, calculate degree-related debt, and visualize future financial commitments aligned with their chosen majors.

College Salary, Tuition, & Debt Tool

Introduction and Setup

As students make crucial decisions about their higher education, it’s imperative to equip them with insights into the financial aspects of their chosen career paths. To address this need, we’ve developed an interactive tool comprising four components: the salary estimator, tuition estimator, debt estimator, and debt calculator. This setup section initializes the necessary libraries and performs data wrangling to prepare the datasets for visualization.

Setup + Wrangling
library(shiny)
library(tidyverse)
library(showtext)
library(ggtext)
library(RColorBrewer)
library(rsconnect)
library(colorspace)
library(plotly)
library(shinyWidgets)
library(scales)
library(ggplot2)

# Reading necessary files from GitHub
allAgesDf <- read_csv("../../../assets/datasets/all-ages.csv")
tuition_cost <- read_csv("../../../assets/datasets/tuition_income.csv")
tuition <- read_csv("../../../assets/datasets/tuition_cost.csv")
ds4 <- read_csv("../../../assets/datasets/salary_and_stats.csv")

# Wrangling Salary Potential
# This section prepares data related to salary estimates for various majors.
salary <- allAgesDf %>%
    dplyr::select(Major, P25th, Median, P75th) %>%
    pivot_longer(c(P25th, Median, P75th),
        names_to = "Percentile_Range", values_to = "Salary"
    ) %>%
    arrange(Major) %>%
    mutate(
        Percentile_Range = as.factor(Percentile_Range),
        Major = as.factor(Major)
    )

# Wrangling Potential Tuition Burden
# This part of the code prepares data related to tuition costs.
tuition_cost <- tuition_cost %>%
    filter(year == 2018 & net_cost > 0) %>%
    arrange(name) %>%
    mutate(
        income_lvl = as.factor(income_lvl),
        name = as.factor(name)
    )

# Adjusting income levels for readability
tuition_cost$income_lvl <- recode(tuition_cost$income_lvl,
    "0 to 30,000" = "$0 to $30,000",
    "30,001 to 48,000" = "$30,001 to $48,000",
    "48_001 to 75,000" = "$48,001 to $75,000",
    "75,001 to 110,000" = "$75,001 to $110,000",
    "Over 110,000" = "Over $110,000"
)

# Adjusting data for visualization
salary$Percentile_Range <- factor(salary$Percentile_Range, levels = c("P25th", "Median", "P75th"))
salary$Percentile_Range <- recode(salary$Percentile_Range,
    "P25th" = "Early Career",
    "Median" = "Middle Career",
    "P75th" = "Late Career"
)
salary$Major <- str_to_title(salary$Major)
salary$Major <- gsub("And", "and", salary$Major)

# Further data preparation for visualization
df <- tuition %>%
    group_by(state, degree_length, type) %>%
    filter(!is.na(state) & degree_length != "Other") %>%
    summarise(
        room_expenses = mean(room_and_board, na.rm = TRUE),
        inStateTotal = mean(in_state_total, na.rm = TRUE),
        outOfStateTotal = mean(out_of_state_total, na.rm = TRUE)
    )

df$degree_length <- as.factor(df$degree_length)
df$type <- as.factor(df$type)

df <- df %>% rename(
    "Room and Board" = room_expenses,
    "In State Tuition" = inStateTotal,
    "Out of State Tuition" = outOfStateTotal
)

Color Theme

This section defines the visual theme to maintain consistency across all plots and enhance readability.

Color Theme
# Definitions for visual theme
title <- 25
subtitle <- 20
facet_title <- 25
axis_title <- 18
tick_numbers <- 13
title_color <- "black"
background <- "gainsboro"
plot_background <- "gainsboro"
facet_header_background <- "gainsboro"
line_type <- "solid"

# Custom theme for plots
CoreyPlotTheme <- theme(
    text = element_text(family = "Futura"),
    plot.background = element_rect(fill = background),
    panel.background = element_blank(),
    panel.grid.major = element_line(size = .1, linetype = line_type, colour = "gainsboro"),
    panel.grid.minor = element_line(size = .1, linetype = line_type, colour = "black"),
    plot.title = element_text(color = title_color, size = title, family = "Futura", hjust = 0.5),
    plot.subtitle = element_text(color = title_color, size = subtitle, family = "Futura", hjust = 0.5),
    plot.caption = element_text(color = title_color, face = "bold", size = tick_numbers, family = "Futura", hjust = 0),
    strip.text = element_text(color = title_color, size = facet_title, family = "Futura"),
    strip.background = element_rect(fill = facet_header_background),
    axis.text = element_text(color = title_color, size = tick_numbers, family = "Futura"),
    axis.title = element_text(color = title_color, size = axis_title, family = "Futura"),
    axis.ticks.x = element_blank(),
    legend.title = element_text(color = title_color, size = subtitle, family = "Futura"),
    legend.background = element_rect(fill = plot_background),
    legend.text = element_text(size = tick_numbers, family = "Futura")
)

Interactive Inputs

This section presents the user interface elements allowing users to interact with the data and customize visualizations according to their preferences.

Salary Estimator Selectors

Salary Estimator Selectors
# Inputs for Salary Estimator plot
input1 <- inputPanel(
    selectInput("selectInput1",
        label = "Choose your major:",
        choices = unique(salary$Major),
        selected = "ART HISTORY AND CRITICISM"
    ),
    checkboxGroupInput("percentile_choice",
        label = "Pick your career level:",
        choices = list(
            "Early Career " = "Early Career",
            "Middle Career " = "Middle Career",
            "Late Career " = "Late Career"
        ),
        selected = c("Early Career", "Middle Career", "Late Career")
    ),
)

Tuition Estimator Options

Tuition Estimator Options
# Inputs for Tuition Estimator plot
input2 <- inputPanel(
    selectInput("money",
        label = "Select the type of expense:",
        choices = c(
            "Room and Board" = "Room and Board",
           

 "In State Tuition" = "In State Tuition",
            "Out of State Tuition" = "Out of State Tuition"
        ),
        selected = "In State Tuition"
    ),
    selectInput("state",
        label = "Pick your State:",
        choices = unique(df$state),
        selected = "Oregon"
    ),
)

Debt Estimator Levels

Debt Estimator Levels
# Inputs for Debt Estimator plot
input3 <- inputPanel(
    selectInput("selectInput2",
        label = "Select your university:",
        choices = unique(tuition_cost$name),
        selected = "Willamette University"
    ),
    checkboxGroupInput("checkGroup",
        label = "Select your household income bracket:",
        choices = list(
            "$0 to $30,000" = "$0 to $30,000",
            "$30,001 to $48,000" = "$30,001 to $48,000",
            "$48,001 to $75,000" = "$48,001 to $75,000",
            "$75,001 to $110,000" = "$75,001 to $110,000",
            "Over $110,000" = "Over $110,000"
        ),
        selected = c(
            "$0 to $30,000",
            "$30,001 to $48,000",
            "$48,001 to $75,000",
            "$75,001 to $110,000",
            "Over $110,000"
        )
    ),
)

Debt Calculator Choices

Debt Calculator Choices
# Inputs for Debt Calculator plot
input4 <- inputPanel(
    selectInput("major_category",
        label = "Pick a major category:",
        choices = unique(ds4$major_category),
        selected = "Computers & Mathematics"
    ),
)

Plots

These plots dynamically visualize various aspects of higher education finances based on user-selected inputs.

Salary Estimator

Salary Estimator
# Plot for Salary Estimator
plot1 <- renderPlot({
    salary %>%
        filter((Major %in% input$selectInput1) & (Percentile_Range %in% input$percentile_choice)) %>%
        ggplot(aes(x = Percentile_Range, y = Salary, fill = Percentile_Range)) +
        geom_col(width = 0.4, color = "black", show.legend = FALSE) +
        geom_label(
            aes(
                y = Salary,
                label = print(paste0("$", round(Salary / 1000, 2), "K"))
            ),
            show.legend = FALSE,
            size = 7,
            family = "Futura",
            fill = "white"
        ) +
        scale_y_continuous(labels = label_number(prefix = "$", suffix = "K", scale = 1e-3)) +
        labs(
            x = NULL,
            y = NULL,
            title = paste0("Estimated Salary for ", input$selectInput1),
            caption = "Source: TuitionTracker.org @ 2018"
        ) +
        CoreyPlotTheme +
        scale_fill_brewer(palette = "PuBuGn")
})

Tuition Estimator

Tuition Estimator
# Plot for Tuition Estimator
plot2 <- renderPlot({
    df %>%
        filter(state == input$state) %>%
        ggplot(aes(x = degree_length, y = .data[[input$money]], fill = degree_length)) +
        geom_col(width = 0.4, color = "black", show.legend = FALSE) +
        facet_wrap(~type) +
        geom_label(
            aes(
                y = .data[[input$money]],
                label = print(paste0("$", round(.data[[input$money]] / 1000, 2), "K"))
            ),
            family = "Oswald",
            size = 7,
            show.legend = FALSE,
            fill = "white"
        ) +
        scale_y_continuous(
            labels = label_number(prefix = "$", suffix = "K", scale = 1e-3),
            limits = c(0, 55000)
        ) +
        labs(
            x = NULL,
            y = NULL,
            title = paste0("Average ", input$money, " for ", input$state, " Universities"),
            subtitle = "For Undergraduate Degrees",
            caption = "Source: TuitionTracker.org @ 2018"
        ) +
        CoreyPlotTheme +
        scale_fill_brewer(palette = "PuBuGn")
})

Debt Estimator

Debt Estimator
# Plot for Debt Estimator
plot3 <- renderPlot({
    tuition_cost %>%
        filter((income_lvl %in% input$checkGroup) & (name %in% input$selectInput2)) %>%
        ggplot(aes(x = income_lvl, y = net_cost, fill = income_lvl)) +
        geom_col(color = "black", width = 0.4, position = "dodge", show.legend = FALSE) +
        geom_label(
            aes(
                y = net_cost,
                label = print(paste0("$", round(net_cost / 1000, 2), "K"))
            ),
            family = "Oswald",
            size = 7,
            show.legend = FALSE,
            fill = "white"
        ) +
        scale_y_continuous(labels = label_number(prefix = "$", suffix = "K", scale = 1e-3)) +
        labs(
            x = NULL,
            y = NULL,
            title = paste0("Median Student Loan Debt for ", input$selectInput2),
            subtitle = "After Completing Their Undergraduate Degree",
            caption = "Source: TuitionTracker.org @ 2018"
        ) +
        CoreyPlotTheme +
        scale_fill_brewer(palette = "PuBuGn")
})

Debt Calculator

Debt Calculator
# Plot for Debt Calculator
plot4 <- renderPlot({
    ds4 %>%
        filter(major_category == input$major_category) %>%
        ggplot(aes(perfect_payback_period, reorder(major, perfect_payback_period), fill = perfect_payback_period)) +
        geom_col(show.legend = FALSE) +
        geom_label(aes(label = paste(round(perfect_payback_period, 2), " yrs.")),
            show.legend = FALSE,
            fill = "white",
            hjust = 1.1
        ) +
        theme(
            axis.title.y = element_blank(),
            axis.text.x = element_blank()
        ) +
        labs(
            title = "How Long Will You Be In Debt?",
            subtitle = "Based on Your

 Major",
            x = "Time to pay off loans"
        ) +
        CoreyPlotTheme +
        theme(plot.title = element_text(hjust = 0.5)) +
        scale_fill_continuous_sequential("PuBuGn")
})

Conclusion

The interactive tool provides valuable resources for high school students considering higher education. By offering comprehensive tools for estimating salaries, tuition costs, and student debt accumulation, we empower students to make informed decisions about their future. This project showcases the power of interactive visualizations in providing crucial information to prospective college students, guiding them towards successful career paths and financial planning.

Data References

Atkins, Aron, Toph Allen, Hadley Wickham, Jonathan McPherson, and JJ Allaire. 2025. Rsconnect: Deploy Docs, Apps, and APIs to Posit Connect, Shinyapps.io, and RPubs. https://rstudio.github.io/rsconnect/.
Chang, Winston, Joe Cheng, JJ Allaire, Carson Sievert, Barret Schloerke, Yihui Xie, Jeff Allen, Jonathan McPherson, Alan Dipert, and Barbara Borges. 2024. Shiny: Web Application Framework for r. https://shiny.posit.co/.
Grolemund, Garrett, and Hadley Wickham. 2011. “Dates and Times Made Easy with lubridate.” Journal of Statistical Software 40 (3): 1–25. https://www.jstatsoft.org/v40/i03/.
Ihaka, Ross, Paul Murrell, Kurt Hornik, Jason C. Fisher, Reto Stauffer, Claus O. Wilke, Claire D. McWhite, and Achim Zeileis. 2024. Colorspace: A Toolbox for Manipulating and Assessing Colors and Palettes. https://colorspace.R-Forge.R-project.org/.
Müller, Kirill, and Hadley Wickham. 2023. Tibble: Simple Data Frames. https://tibble.tidyverse.org/.
Neuwirth, Erich. 2022. RColorBrewer: ColorBrewer Palettes. https://CRAN.R-project.org/package=RColorBrewer.
Perrier, Victor, Fanny Meyer, and David Granjon. 2024. shinyWidgets: Custom Inputs Widgets for Shiny. https://github.com/dreamRs/shinyWidgets.
Qiu, Yixuan, and authors/contributors of the included fonts. See file AUTHORS for details. 2020. Showtextdb: Font Files for the Showtext Package. https://CRAN.R-project.org/package=showtextdb.
———. 2024a. Sysfonts: Loading Fonts into r. https://github.com/yixuan/sysfonts.
Qiu, Yixuan, and authors/contributors of the included software. See file AUTHORS for details. 2024b. Showtext: Using Fonts More Easily in r Graphs. https://github.com/yixuan/showtext.
Sievert, Carson. 2020. Interactive Web-Based Data Visualization with r, Plotly, and Shiny. Chapman; Hall/CRC. https://plotly-r.com.
Sievert, Carson, Chris Parmer, Toby Hocking, Scott Chamberlain, Karthik Ram, Marianne Corvellec, and Pedro Despouy. 2024. Plotly: Create Interactive Web Graphics via Plotly.js. https://plotly-r.com.
Spinu, Vitalie, Garrett Grolemund, and Hadley Wickham. 2024. Lubridate: Make Dealing with Dates a Little Easier. https://lubridate.tidyverse.org.
Stauffer, Reto, Georg J. Mayr, Markus Dabernig, and Achim Zeileis. 2009. “Somewhere over the Rainbow: How to Make Effective Use of Colors in Meteorological Visualizations.” Bulletin of the American Meteorological Society 96 (2): 203–16. https://doi.org/10.1175/BAMS-D-13-00155.1.
Wickham, Hadley. 2016. Ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org.
———. 2023a. Forcats: Tools for Working with Categorical Variables (Factors). https://forcats.tidyverse.org/.
———. 2023b. Stringr: Simple, Consistent Wrappers for Common String Operations. https://stringr.tidyverse.org.
———. 2023c. Tidyverse: Easily Install and Load the Tidyverse. https://tidyverse.tidyverse.org.
Wickham, Hadley, Mara Averick, Jennifer Bryan, Winston Chang, Lucy D’Agostino McGowan, Romain François, Garrett Grolemund, et al. 2019. “Welcome to the tidyverse.” Journal of Open Source Software 4 (43): 1686. https://doi.org/10.21105/joss.01686.
Wickham, Hadley, Winston Chang, Lionel Henry, Thomas Lin Pedersen, Kohske Takahashi, Claus Wilke, Kara Woo, Hiroaki Yutani, Dewey Dunnington, and Teun van den Brand. 2024. Ggplot2: Create Elegant Data Visualisations Using the Grammar of Graphics. https://ggplot2.tidyverse.org.
Wickham, Hadley, Romain François, Lionel Henry, Kirill Müller, and Davis Vaughan. 2023. Dplyr: A Grammar of Data Manipulation. https://dplyr.tidyverse.org.
Wickham, Hadley, and Lionel Henry. 2025. Purrr: Functional Programming Tools. https://purrr.tidyverse.org/.
Wickham, Hadley, Jim Hester, and Jennifer Bryan. 2024. Readr: Read Rectangular Text Data. https://readr.tidyverse.org.
Wickham, Hadley, Thomas Lin Pedersen, and Dana Seidel. 2023. Scales: Scale Functions for Visualization. https://scales.r-lib.org.
Wickham, Hadley, Davis Vaughan, and Maximilian Girlich. 2024. Tidyr: Tidy Messy Data. https://tidyr.tidyverse.org.
Wilke, Claus O., and Brenton M. Wiernik. 2022. Ggtext: Improved Text Rendering Support for Ggplot2. https://wilkelab.org/ggtext/.
Zeileis, Achim, Jason C. Fisher, Kurt Hornik, Ross Ihaka, Claire D. McWhite, Paul Murrell, Reto Stauffer, and Claus O. Wilke. 2020. colorspace: A Toolbox for Manipulating and Assessing Colors and Palettes.” Journal of Statistical Software 96 (1): 1–49. https://doi.org/10.18637/jss.v096.i01.
Zeileis, Achim, Kurt Hornik, and Paul Murrell. 2009. “Escaping RGBland: Selecting Colors for Statistical Graphics.” Computational Statistics & Data Analysis 53 (9): 3259–70. https://doi.org/10.1016/j.csda.2008.11.033.