For imports and data cleaning, I set the code to not be visible so that you don’t get bored right from the first lines.

Imports

Data cleaning

Basic type conversions:

## 'data.frame':    97 obs. of  10 variables:
##  $ dateOp        : Date, format: "2024-03-28" "2024-03-27" ...
##  $ dateVal       : Date, format: "2024-03-28" "2024-03-27" ...
##  $ label         : chr  "CARTE 27/03/24 NYX*FDADISTRIBUTI CB*8014" "CARTE 26/03/24 CARREFOUR CITY CB*8014" "CARTE 25/03/24 CARREFOUR CITY CB*8014" "CARTE 25/03/24 L ATELIER DE MON CB*8014" ...
##  $ category      : chr  "Hébergement (hôtels, camping…)" "Alimentation" "Alimentation" "Contraventions" ...
##  $ categoryParent: chr  "Voyages & Transports" "Vie quotidienne" "Vie quotidienne" "Auto & Moto" ...
##  $ amount        : num  0.5 6.74 6.81 3.8 2.88 ...
##  $ comment       : logi  NA NA NA NA NA NA ...
##  $ accountNum    : int  40356809 40356809 40356809 40356809 40356809 40356809 40356809 40356809 40356809 40356809 ...
##  $ accountLabel  : chr  "Compte de Fonctionnement" "Compte de Fonctionnement" "Compte de Fonctionnement" "Compte de Fonctionnement" ...
##  $ accountbalance: num  538 538 545 545 545 ...
## NULL

Creating a new variable for the budget category of each spending:

mapping <- c("Carburant"="leisure", "Club / association (sport, hobby, art…)"="leisure", "Livres, CD/DVD, bijoux, jouets…"="leisure", "Vêtements et accessoires"="leisure", "Bien-être et soins (coiffeur, parfums…)"="leisure", "Agences de voyages"="leisure", "Restaurants, bars, discothèques…"="leisure", "Equipements sportifs et artistiques"="leisure",

"Hébergement (hôtels, camping…)" = "needs", "Alimentation" = "needs", " 
Contraventions" = "needs", "Transports quotidiens (métro, bus…)" = "needs", "Vie Quotidienne - Autres"= "needs", "Pharmacie et laboratoire"="needs", "Non catégorisé"="needs")


# the savings variable can not be created for now given that I don't save anything lol ; so my spendings either fall in the leisure or the needs category

data <- data %>%
  mutate(budget_category = case_when(
    category %in% names(mapping) ~ mapping[category],
    TRUE ~ "other"
  ))

Filtering to exclude incoming money:

# A df of spendings only for further use
spendings <- data %>% filter(!categoryParent %in% c("Mouvements internes créditeurs", "Virements reçus", "Allocations"))

Static plots: basic descriptive statistics

# Basic descriptive stats
summary(spendings)
##      dateOp              dateVal              label          
##  Min.   :2024-03-01   Min.   :2024-03-01   Length:93         
##  1st Qu.:2024-03-08   1st Qu.:2024-03-08   Class :character  
##  Median :2024-03-14   Median :2024-03-14   Mode  :character  
##  Mean   :2024-03-15   Mean   :2024-03-15                     
##  3rd Qu.:2024-03-22   3rd Qu.:2024-03-22                     
##  Max.   :2024-03-28   Max.   :2024-03-28                     
##    category         categoryParent         amount       comment       
##  Length:93          Length:93          Min.   : 0.500   Mode:logical  
##  Class :character   Class :character   1st Qu.: 1.200   NA's:93       
##  Mode  :character   Mode  :character   Median : 5.000                 
##                                        Mean   : 7.901                 
##                                        3rd Qu.:10.500                 
##                                        Max.   :70.070                 
##    accountNum       accountLabel       accountbalance    budget_category   
##  Min.   :40356809   Length:93          Min.   : -11.19   Length:93         
##  1st Qu.:40356809   Class :character   1st Qu.: 558.26   Class :character  
##  Median :40356809   Mode  :character   Median : 757.96   Mode  :character  
##  Mean   :40356809                      Mean   : 732.66                     
##  3rd Qu.:40356809                      3rd Qu.: 927.06                     
##  Max.   :40356809                      Max.   :1064.67
all_spendings <- spendings %>% 
  arrange(dateOp) %>% 
  mutate(cumsum_amount = cumsum(amount))

ggplot(all_spendings, aes(x=dateOp)) +
  geom_line(aes(y = cumsum_amount), size=1.2, color="pink") +
  geom_line(aes(y=accountbalance), size=1.2, color="brown") +
  labs(title="Monthly evolution of cumulative spendings VS account balance", x="Date", y="Amount") +
  my_theme()
## 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.

Static plots: spending per category

By parent category

# For each parent category of spending
grouped_amount_data <- data %>% 
  filter(!categoryParent %in% c("Mouvements internes créditeurs", "Virements reçus", "Allocations")) %>%
  group_by(categoryParent) %>% 
  summarise(mean_amount=mean(amount), sum_amount=sum(amount))

# Plotting mean spending per parent category of spending, per month
mean_amount_plot <- ggplot(grouped_amount_data, aes(x=categoryParent, y=mean_amount)) +
  geom_bar(stat="identity", aes(fill=categoryParent)) +
  labs(title="Mean monthly spending per parent category", x="Parent category", y="Mean monthly spending") +
  theme_minimal() +
  theme(axis.text.x=element_text(angle=45, hjust=1)) +
  my_theme()

# Plotting sum of spendings per parent category of spending, per month
sum_amount_plot <- ggplot(grouped_amount_data, aes(x=categoryParent, y=sum_amount), group=categoryParent, fill=categoryParent) +
  geom_bar(stat="identity", aes(fill=categoryParent)) +
  labs(title="Sum of monthly spendings per parent category", x="Parent category", y="Sum of monthly spendings") +
  theme_minimal() +
  theme(axis.text.x=element_text(angle=45, hjust=1)) +
  my_theme()


sum_amount_plot

mean_amount_plot

By category

# For each parent category of spending
grouped_amount_data_cat <- data %>% 
  filter(!categoryParent %in% c("Mouvements internes créditeurs", "Virements reçus", "Allocations")) %>%
  group_by(category) %>% 
  summarise(mean_amount=mean(amount), sum_amount=sum(amount))

# Plotting mean spending per parent category of spending, per month
mean_amount_plot_cat <- ggplot(grouped_amount_data_cat, aes(x=category, y=mean_amount)) +
  geom_bar(stat="identity", aes(fill=category)) +
  labs(title="Mean monthly spending per category", x="Category", y="Mean monthly spending") +
  theme_minimal() +
  theme(axis.text.x=element_text(angle=45, hjust=1)) +
  my_theme()

# Plotting sum of spendings per parent category of spending, per month
sum_amount_plot_cat <- ggplot(grouped_amount_data_cat, aes(x=category, y=sum_amount)) +
  geom_bar(stat="identity", aes(fill=category)) +
  labs(title="Sum of monthly spendings per category", x="Category", y="Sum of monthly spendings") +
  theme_minimal() +
  theme(axis.text.x=element_text(angle=45, hjust=1)) +
  my_theme()

mean_amount_plot_cat

sum_amount_plot_cat

Dynamic plots: spendings per date

Spendings per date, per parent category

# Data wrangling
grouped_amount_per_date <- data %>% 
  filter(!categoryParent %in% c("Mouvements internes créditeurs", "Virements reçus", "Allocations")) %>%
  group_by(categoryParent, dateOp) %>% 
  summarise(mean_amount=mean(amount), sum_amount=sum(amount)) %>% 
  replace_na(replace=list(dateOp=0L))
## `summarise()` has grouped output by 'categoryParent'. You can override using
## the `.groups` argument.
# Plots
mean_parent_spending_per_date_plot <- ggplot(grouped_amount_per_date, aes(x=dateOp, y=mean_amount, group=categoryParent, color=categoryParent)) +
  geom_line() +
  labs(title="Monthly evolution of spendings per parent category", x="Date", y="Mean spending") +
  my_theme()
mean_parent_spending_per_date_plot

Spendings per date, per category

# Data wrangling
grouped_amount_per_date_cat <- data %>% 
  filter(!categoryParent %in% c("Mouvements internes créditeurs", "Virements reçus", "Allocations")) %>%
  group_by(category, dateOp) %>% 
  summarise(mean_amount=mean(amount), sum_amount=sum(amount)) %>% 
  replace_na(replace=list(dateOp=0L))
## `summarise()` has grouped output by 'category'. You can override using the
## `.groups` argument.
# Plots
mean_cat_spending_per_date_plot <- ggplot(grouped_amount_per_date_cat, aes(x=dateOp, y=mean_amount, group=category, color=category)) +
  geom_line() +
  labs(title="Monthly evolution of spendings per category", x="Date", y="Mean spending") +
  my_theme()
mean_cat_spending_per_date_plot

mean_cat_spending_per_date_plot2 <- ggplot(spendings, aes(x=dateOp, y=amount, group=category, color=category)) +
  geom_line() +
  labs(title="Monthly evolution of spendings per category", x="Date", y="Mean spending") +
  my_theme()
mean_cat_spending_per_date_plot

Cumulative sum of spendings per date, per category

cumsum_spendings <- spendings %>% 
  group_by(category) %>% 
  arrange(dateOp) %>% 
  mutate(cumsum_amount = cumsum(amount), week = lubridate::week(dateOp))

cum_spendings_plot <- ggplot(cumsum_spendings, aes(x=dateOp, y=cumsum_amount, color=category)) +
  geom_line() +
  labs(title="Cumulative sum of spendings per date, per category", x="Date", y="Amount") +
  my_theme()
cum_spendings_plot

Goals

Plotting my spendings according to the 50/30/20 budget rule categories:

# Data filtering
data_piechart <- spendings %>% 
  group_by(budget_category) %>% 
  mutate(sum_amount=sum(amount)) %>%
  ungroup() %>% 
  mutate(perc=sum_amount/sum(amount)) %>% 
  mutate(labels=scales::percent(perc)) %>% 
  distinct(budget_category, perc, labels, .keep_all = TRUE)

# Plotting
library(RColorBrewer)
colors <- brewer.pal(n = 5, name = "Pastel1")

ggplot(data_piechart, aes(x = "", y = perc, group=budget_category, fill = budget_category)) +
  geom_col() +
  geom_text(aes(label = labels),
            position = position_stack(vjust = 0.5)) +
  coord_polar(theta="y") +
  scale_fill_manual(values = setNames(colors, unique(data_piechart$budget_category))) +
  my_theme()

Plotting the repartition of incoming money sources:

data_piechart_income <- data %>% 
  filter(categoryParent %in% c("Mouvements internes créditeurs", "Virements reçus", "Allocations")) %>% 
  group_by(categoryParent) %>% 
  mutate(sum_amount=sum(amount)) %>% 
  ungroup() %>% 
  mutate(perc=sum_amount/sum(amount)) %>% 
  mutate(labels=scales::percent(perc)) 


ggplot(data_piechart_income, aes(x = "", y = perc, group=label, fill = label)) +
  geom_col() +
  geom_text(aes(label = labels),
            position = position_stack(vjust = 0.5)) +
  coord_polar(theta="y") +
  scale_fill_manual(values = setNames(colors, unique(data_piechart_income$label))) +
  my_theme()