---
title: "Maven Marketing Dashboard"
format:
html:
engine: shiny
theme: flatly
css: styles.css
toc: true
toc-depth: 2
toc-title: "Dashboard Navigation"
code-fold: true
code-tools: true
page-layout: full
---
```{r}
#| label: setup
#| include: false
library (tidyverse)
library (shiny)
library (readxl)
library (plotly)
library (DT)
library (flexdashboard)
library (highcharter)
library (bslib)
library (ggplot2)
dashboard_theme <- theme_minimal () +
theme (
panel.background = element_rect (fill = "#f9fafb" , color = NA ), # very light gray panel background
plot.background = element_rect (fill = "#e6f2ff" , color = NA ), # very light blue plot background
panel.grid.major = element_line (color = "#cce6ff" ), # subtle blue grid lines
panel.grid.minor = element_blank (),
text = element_text (color = "#1e293b" ), # dark slate text
axis.text = element_text (color = "#1e293b" ),
legend.background = element_rect (fill = "#e6f2ff" , color = NA ),
legend.key = element_rect (fill = "#f9fafb" , color = NA )
)
# Read the data
marketing_data <- read_excel ("Maven_Marketing_Data.xlsx" , sheet = "marketing_data" )
# Data cleaning and preparation
marketing_data_clean <- marketing_data %>%
mutate (
Age = 2023 - Year_Birth, # Assuming current year is 2023
Total_Spent = MntWines + MntFruits + MntMeatProducts + MntFishProducts +
MntSweetProducts + MntGoldProds,
Total_Children = Kidhome + Teenhome,
Total_Purchases = NumDealsPurchases + NumWebPurchases +
NumCatalogPurchases + NumStorePurchases,
Dt_Customer = as.Date (Dt_Customer),
Customer_For = as.numeric (difftime (Sys.Date (), Dt_Customer, units = "days" ) / 30 ),
Marital_Status = case_when (
Marital_Status %in% c ("Married" , "Together" ) ~ "Partnered" ,
Marital_Status %in% c ("Single" , "Divorced" , "Widow" , "Alone" , "YOLO" ) ~ "Single" ,
TRUE ~ Marital_Status
)
) %>%
filter (Income < 200000 ) %>% # Remove outliers
drop_na (Income)
```
# Introduction {.tabset .tabset-fade}
## About This Dashboard
### đ What This Dashboard Solves
| Business Challenge | How This Helps |
|------------------------------|------------------------------------------|
| Identifying high-value customers | Visual segmentation by spending, demographics, and purchase frequency |
| Measuring campaign ROI | Clear performance metrics for all marketing initiatives |
| Optimizing product mix | Spending breakdown across 6 product categories |
| Improving channel strategy | Purchase method analysis (web/store/catalog) |
### đ Tab Overview
**1. Customer Profiles**\
- Age/income distributions\
- Education and marital status breakdowns\
- Geographic concentration maps
**2. Spending Patterns**\
- Total revenue by product category\
- Income-to-spending correlations\
- Customer lifetime value estimates
**3. Campaign Analytics**\
- Acceptance rates for 5 campaigns\
- Response rate by demographic\
- Country-level performance heatmap
### âšī¸ Data Notes
- Source: Maven Marketing (2,240 customers)\
- Timeframe: 2012-2014
**Data Source:** [ Download Full Data Dictionary ](https://mavenanalytics.io/data-playground?accessType=open&dataStructure=Single%20table&order=date_added%2Cdesc&page=2&pageSize=5&tags=Business)
# Customer Overview Tab
```{r}
#| label: customer-overview
#| title: "Customer Overview"
library (ggplot2)
library (plotly)
ggplot (marketing_data_clean, aes (x = Age, fill = Education, text = paste ("Age:" , Age, "<br>Education:" , Education))) +
geom_histogram (binwidth = 5 , alpha = 0.8 ) +
labs (title = "Customer Age Distribution by Education Level" , x = "Age" , y = "Count" ) +
dashboard_theme -> plot1
ggplotly (plot1, tooltip = "text" )
plot2 <- ggplot (marketing_data_clean, aes (x = Marital_Status, y = Income, fill = Marital_Status)) +
geom_boxplot () +
labs (title = "Income Distribution by Marital Status" , x = "Marital Status" , y = "Income" ) +
dashboard_theme
ggplotly (plot2) %>% layout (plot_bgcolor = "#f0f8ff" , paper_bgcolor = "#e6f2ff" )
```
#### **Customer Demographics Charts**
**Problems Tackled**:
- **"Who are our best customers?"**
- **"Where should we focus acquisition?"**
**Actionable Insights**:
- Target 35-55yo professionals with premium offers
- Adjust messaging for single vs. partnered customers
- Allocate regional budgets based on customer concentration
# Spending Analysis Tab
```{r}
#| label: spending-analysis
#| title: "Spending Analysis"
plot3 <- marketing_data_clean %>%
select (starts_with ("Mnt" )) %>%
summarise (across (everything (), sum)) %>%
pivot_longer (everything (), names_to = "Category" , values_to = "Amount" ) %>%
mutate (Category = str_remove_all (Category, "Mnt|Prods" )) %>%
ggplot (aes (x = reorder (Category, Amount), y = Amount, fill = Category)) +
geom_col () +
coord_flip () +
labs (title = "Total Spending by Product Category" , x = "" , y = "Total Amount Spent" ) +
dashboard_theme
ggplotly (plot3) %>% layout (plot_bgcolor = "#f0f8ff" , paper_bgcolor = "#e6f2ff" )
plot4 <- ggplot (marketing_data_clean, aes (x = Income, y = Total_Spent, color = Education)) +
geom_point (alpha = 0.5 ) +
geom_smooth (method = "lm" , formula = y ~ x, color = "red" ) +
labs (title = "Total Spending vs. Income" , x = "Income" , y = "Total Spending" ) +
dashboard_theme
ggplotly (plot4) %>% layout (plot_bgcolor = "#f0f8ff" , paper_bgcolor = "#e6f2ff" )
```
#### **Spending Analysis Charts**
**Problems Tackled**:
- **"Which products drive revenue?"**
- **"How does income affect spending?"**
**Actionable Insights**:
- Bundle low-performing categories with wines
- Create income-tiered loyalty programs
- Flag outliers for potential data errors
# Campaign Performance Tab
```{r}
#| label: campaign-performance
#| title: "Campaign Performance"
# Campaign acceptance rates
campaign_means <- marketing_data_clean %>%
select (starts_with ("AcceptedCmp" )) %>%
summarise (across (everything (), mean))
response_rate <- mean (marketing_data_clean$ Response == "Yes" )
campaign_data <- campaign_means %>%
pivot_longer (everything (), names_to = "Campaign" , values_to = "Acceptance_Rate" ) %>%
add_row (Campaign = "Response" , Acceptance_Rate = response_rate) %>%
mutate (Campaign = case_when (
Campaign == "AcceptedCmp1" ~ "Campaign 1" ,
Campaign == "AcceptedCmp2" ~ "Campaign 2" ,
Campaign == "AcceptedCmp3" ~ "Campaign 3" ,
Campaign == "AcceptedCmp4" ~ "Campaign 4" ,
Campaign == "AcceptedCmp5" ~ "Campaign 5" ,
Campaign == "Response" ~ "Latest Campaign" ,
TRUE ~ Campaign
))
plot5 <- ggplot (campaign_data, aes (x = reorder (Campaign, Acceptance_Rate), y = Acceptance_Rate, fill = Campaign)) +
geom_col () +
coord_flip () +
scale_y_continuous (labels = scales:: percent) +
labs (title = "Campaign Acceptance Rates" , x = "" , y = "Acceptance Rate" ) +
dashboard_theme
ggplotly (plot5) %>%
layout (
plot_bgcolor = "#f0f8ff" ,
paper_bgcolor = "#e6f2ff"
)
plot6 <- marketing_data_clean %>%
group_by (Country) %>%
summarise (Response_Rate = mean (Response == "Yes" )) %>%
ggplot (aes (x = reorder (Country, Response_Rate), y = Response_Rate, fill = Country)) +
geom_col () +
coord_flip () +
scale_y_continuous (labels = scales:: percent) +
labs (title = "Response Rate by Country" , x = "" , y = "Response Rate" ) +
dashboard_theme
ggplotly (plot6) %>% layout (plot_bgcolor = "#f0f8ff" , paper_bgcolor = "#e6f2ff" )
```
#### **Campaign Performance Charts**
**Problems Tackled**:
- **"Which campaigns work best?"**
- **"Where do campaigns fail?"**
**Actionable Insights**:
- Replicate Campaign 3's successful tactics
- Retire underperforming campaigns (save 15-20% budget)
- Localize creatives for low-response regions
# Purchase Channel Analysis
### Channel Preferrence
```{r}
#| label: purchase-channels
#| title: "Revenue by Purchase Channel"
# Calculate revenue by channel
channel_revenue <- marketing_data_clean %>%
summarise (
` Deals Purchases ` = sum (NumDealsPurchases * (Total_Spent/ Total_Purchases), na.rm = TRUE ),
` Web Purchases ` = sum (NumWebPurchases * (Total_Spent/ Total_Purchases), na.rm = TRUE ),
` Catalog Purchases ` = sum (NumCatalogPurchases * (Total_Spent/ Total_Purchases), na.rm = TRUE ),
` Store Purchases ` = sum (NumStorePurchases * (Total_Spent/ Total_Purchases), na.rm = TRUE )
) %>%
pivot_longer (everything (), names_to = "Channel" , values_to = "Revenue" )
channel_plot <- channel_revenue %>%
ggplot (aes (x = reorder (Channel, Revenue), y = Revenue, fill = Channel,
text = paste ("Channel:" , Channel, "<br>Revenue: $" , round (Revenue/ 1000 ,1 ), "K" ))) +
geom_col () +
coord_flip () +
scale_fill_brewer (palette = "Set2" ) +
labs (title = "Total Revenue by Purchase Channel" ,
x = "" , y = "Total Revenue ($)" ) +
dashboard_theme +
theme (legend.position = "none" )
ggplotly (channel_plot, tooltip = "text" ) %>%
layout (
plot_bgcolor = "#f0f8ff" ,
paper_bgcolor = "#e6f2ff"
)
```
### Channel vs. Customer Value
```{r}
#| label: channel-value
#| title: "Customer Value by Channel"
avg_spend <- marketing_data_clean %>%
summarise (
` Deals ` = mean (Total_Spent[NumDealsPurchases > 0 ], na.rm = TRUE ),
` Web ` = mean (Total_Spent[NumWebPurchases > 0 ], na.rm = TRUE ),
` Catalog ` = mean (Total_Spent[NumCatalogPurchases > 0 ], na.rm = TRUE ),
` Store ` = mean (Total_Spent[NumStorePurchases > 0 ], na.rm = TRUE )
) %>%
pivot_longer (everything (), names_to = "Channel" , values_to = "Avg_Spend" )
value_plot <- avg_spend %>%
ggplot (aes (x = reorder (Channel, Avg_Spend), y = Avg_Spend, fill = Channel,
text = paste ("Channel:" , Channel, "<br>Avg Spend: $" , round (Avg_Spend)))) +
geom_col () +
coord_flip () +
scale_fill_brewer (palette = "Set2" ) +
labs (title = "Average Customer Spending by Preferred Channel" ,
x = "" , y = "Average Total Spend ($)" ) +
dashboard_theme +
theme (legend.position = "none" )
ggplotly (value_plot, tooltip = "text" ) %>%
layout (
plot_bgcolor = "#f0f8ff" ,
paper_bgcolor = "#e6f2ff"
)
```
#### **Purchase Channel Charts**
**Problems Tackled**:
- **"Where do customers buy?"**
- **"Which channels drive quality sales?"**
**Actionable Insights**:
- Shift budget from web to catalog for high-value customers
- Improve in-store experience for younger demographics
- Optimize deal-focused buyer retention