Libraries

library(dplyr)
## Warning: package 'dplyr' was built under R version 4.3.3
## 
## 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(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.3.3
library(plotly)
## Warning: package 'plotly' was built under R version 4.3.3
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
library(packcircles)
## Warning: package 'packcircles' was built under R version 4.3.3
library(viridis)
## Warning: package 'viridis' was built under R version 4.3.3
## Loading required package: viridisLite
library(hrbrthemes)
## NOTE: Either Arial Narrow or Roboto Condensed fonts are required to use these themes.
##       Please use hrbrthemes::import_roboto_condensed() to install Roboto Condensed and
##       if Arial Narrow is not on your system, please see https://bit.ly/arialnarrow
library(scales)
## Warning: package 'scales' was built under R version 4.3.3
## 
## Attaching package: 'scales'
## The following object is masked from 'package:viridis':
## 
##     viridis_pal
library(gridExtra)
## Warning: package 'gridExtra' was built under R version 4.3.3
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
library(ggrepel)
## Warning: package 'ggrepel' was built under R version 4.3.3
library(reshape2)
## Warning: package 'reshape2' was built under R version 4.3.3
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(sf)
## Warning: package 'sf' was built under R version 4.3.3
## Linking to GEOS 3.11.2, GDAL 3.8.2, PROJ 9.3.1; sf_use_s2() is TRUE
library(rnaturalearth)
## Warning: package 'rnaturalearth' was built under R version 4.3.3
library(rnaturalearthdata)
## Warning: package 'rnaturalearthdata' was built under R version 4.3.3
## 
## Attaching package: 'rnaturalearthdata'
## The following object is masked from 'package:rnaturalearth':
## 
##     countries110
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.3.3
## Warning: package 'tidyr' was built under R version 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats 1.0.0     ✔ stringr 1.5.1
## ✔ purrr   1.0.2     ✔ tibble  3.2.1
## ✔ readr   2.1.4     ✔ tidyr   1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ readr::col_factor()  masks scales::col_factor()
## ✖ gridExtra::combine() masks dplyr::combine()
## ✖ purrr::discard()     masks scales::discard()
## ✖ plotly::filter()     masks dplyr::filter(), stats::filter()
## ✖ dplyr::lag()         masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(lubridate)
library(ggthemes)
## Warning: package 'ggthemes' was built under R version 4.3.3
library(scales)
library(reshape2)
library(readxl)
## Warning: package 'readxl' was built under R version 4.3.3
library(treemap)
## Warning: package 'treemap' was built under R version 4.3.3
library(treemapify)
## Warning: package 'treemapify' was built under R version 4.3.3

Intro

The Global Superstore dataset is a detailed collection of sales data from a fictonal retail company that operates around the world. The dataset includes lots of information about orders, customers, products, and shipments, allowing for many types of analysis.

Given that we can only present 3 answers to questions by visualizing data we have choosen to go with 2 umbrella topics from the Global Superstore Dataset: Customer Analysis & Product Analysis

df <-  read_excel('C:/Users/use/Desktop/Global Superstore.xls')

Dataset contains:

colnames(df)
##  [1] "Row ID"         "Order ID"       "Order Date"     "Ship Date"     
##  [5] "Ship Mode"      "Customer ID"    "Customer Name"  "Segment"       
##  [9] "City"           "State"          "Country"        "Postal Code"   
## [13] "Market"         "Region"         "Product ID"     "Category"      
## [17] "Sub-Category"   "Product Name"   "Sales"          "Quantity"      
## [21] "Discount"       "Profit"         "Shipping Cost"  "Order Priority"

For That We Will Answer The Following Questions:

Fixing The Sales Column So All Data Is Formatted Correctly

I also removed the $ so to convert the sales column into a numeric value

df$Sales <- gsub(",", "", df$Sales)
df$Sales <- gsub("\\$", "", df$Sales)
df$Sales <- as.numeric(df$Sales)
head(df$Sales)
## [1] 2309.650 3709.395 5175.171 2892.510 2832.960 2862.675

Same Process With Profit

df$Profit <- gsub(",", "", df$Profit)
df$Profit <- gsub("\\$", "", df$Profit)
df$Profit <- as.numeric(df$Profit)
head(df$Profit)
## [1]  762.1845 -288.7650  919.9710  -96.5400  311.5200  763.2750

The Discount Column Must Be Mutiplied By 100

df$Discount <- df$Discount * 100
head(df$Discount)
## [1]  0 10 10 10  0 10
df <- df %>%
  rename(Sub_Category = `Sub-Category`)

head(df)
## # A tibble: 6 × 24
##   `Row ID` `Order ID`      `Order Date`        `Ship Date`         `Ship Mode` 
##      <dbl> <chr>           <dttm>              <dttm>              <chr>       
## 1    32298 CA-2012-124891  2012-07-31 00:00:00 2012-07-31 00:00:00 Same Day    
## 2    26341 IN-2013-77878   2013-02-05 00:00:00 2013-02-07 00:00:00 Second Class
## 3    25330 IN-2013-71249   2013-10-17 00:00:00 2013-10-18 00:00:00 First Class 
## 4    13524 ES-2013-1579342 2013-01-28 00:00:00 2013-01-30 00:00:00 First Class 
## 5    47221 SG-2013-4320    2013-11-05 00:00:00 2013-11-06 00:00:00 Same Day    
## 6    22732 IN-2013-42360   2013-06-28 00:00:00 2013-07-01 00:00:00 Second Class
## # ℹ 19 more variables: `Customer ID` <chr>, `Customer Name` <chr>,
## #   Segment <chr>, City <chr>, State <chr>, Country <chr>, `Postal Code` <chr>,
## #   Market <chr>, Region <chr>, `Product ID` <chr>, Category <chr>,
## #   Sub_Category <chr>, `Product Name` <chr>, Sales <dbl>, Quantity <dbl>,
## #   Discount <dbl>, Profit <dbl>, `Shipping Cost` <dbl>, `Order Priority` <chr>

What Are The Top Performing Products Over The Years?

Top 5 winning Products

df <- df %>%
  mutate(Year = as.numeric(format(as.Date(`Order Date`), "%Y")))


yearly_product_profits <- df %>%
  group_by(Year,Sub_Category) %>%
  summarise(Total_Profit = sum(Profit, na.rm = TRUE)) %>%
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
top_5_profit_product_types <- yearly_product_profits %>%
  group_by(Year) %>%
  top_n(5, Total_Profit) %>%
  arrange(Year, desc(Total_Profit)) %>%
  ungroup()


top_product_types <- top_5_profit_product_types %>%
  select(Sub_Category) %>%
  distinct() %>%
  pull()


filtered_data <- yearly_product_profits %>%
  filter(Sub_Category %in% top_product_types)


plot <- plot_ly(filtered_data, x = ~Year, y = ~Total_Profit, color = ~Sub_Category, type = 'scatter', mode = 'lines+markers') %>%
  layout(title = "Top Products By Profit Per Year",
         xaxis = list(title = "Year"),
         yaxis = list(title = "Total Profit"),
         legend = list(title = list(text = 'Product Type')),
         margin = list(l = 50, r = 50, t = 50, b = 50))


plot

Generally we can say that there is an upward trends for the 5 product categories listed above but Accessories have had the highest growth.

What About Products With A Downwards Trend?

yearly_product_profits <- df %>%
  group_by(Year, Sub_Category) %>%
  summarise(Total_Profit = sum(Profit, na.rm = TRUE)) %>%
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
top_5_loss_product_types <- yearly_product_profits %>%
  group_by(Year) %>%
  top_n(-5, Total_Profit) %>%
  arrange(Year, Total_Profit) %>%
  ungroup()


top_loss_product_types <- top_5_loss_product_types %>%
  select(Sub_Category) %>%
  distinct() %>%
  pull()


filtered_loss_data <- yearly_product_profits %>%
  filter(Sub_Category %in% top_loss_product_types)


loss_plot <- plot_ly(filtered_loss_data, x = ~Year, y = ~Total_Profit, color = ~Sub_Category, type = 'scatter', mode = 'lines+markers') %>%
  layout(title = "Products With Loosing Profit Over Time",
         xaxis = list(title = "Year"),
         yaxis = list(title = "Total Loss"),
         legend = list(title = list(text = 'Product Type')),
         margin = list(l = 50, r = 50, t = 50, b = 50))


loss_plot

Tablets seem to have taken a significant hit from 2012 and onwards. Everything else seems to be keep the trending of slowly dying. Makes sense as most people now use email to communicate and there is very little demand for envelopes or labels.

What Are The Biggest Market Regions & Where It Would Be Suitable To Open Up A New Location?

I will treat this question as a top of a funnel approach. We will start to look at where are the top sales coming from and we can further drill down on the data.

Which Are The Most Profitable Markets By Sales Number

agg_data <- df %>%
  group_by(Region) %>%
  summarize(TotalSales = sum(Sales))

ggplot(agg_data, aes(x = TotalSales, y = Region, size = TotalSales, color = Region)) +
  geom_point(alpha = 0.6) +
  geom_text_repel(aes(label = Region), size = 3.5, box.padding = 0.5, point.padding = 0.9) +
  labs(title = "Bubble Chart of Sales by Region", x = "Total Sales", y = "Region") +
  theme_minimal() +
  scale_size_continuous(range = c(3, 15)) +
  scale_x_continuous(labels = scales::label_comma(), breaks = seq(0, max(agg_data$TotalSales), by = 1000000)) +
  guides(color = FALSE, size = FALSE) 
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

## Becase West, East and Central Refer To The US market we will merge the and view the bubble chart as a more simplified breakup of the markets by continent

#for that we will need to create a mapping
region_mapping <- c(
  "East" = "North America",
  "Oceania" = "Australia",
  "Central" = "North America",
  "Africa" = "Africa",
  "West" = "North America",
  "South" = "South America",
  "Central Asia" = "Asia",
  "EMEA" = "Europe",
  "North Asia" = "Asia",
  "North" = "North America",
  "Caribbean" = "North America",
  "Southeast Asia" = "Asia",
  "Canada" = "North America"
)
#PUTTING THEM TOGETHER
df <- df %>%
  mutate(Region = region_mapping[Region])
#CHECKING THE NEW REGIONS COLUMN
unique(df$Region)
## [1] "North America" "Australia"     "Africa"        "South America"
## [5] "Asia"          "Europe"
agg_data <- df %>%
  group_by(Region) %>%
  summarize(TotalSales = sum(Sales))

ggplot(agg_data, aes(x = TotalSales, y = Region, size = TotalSales, color = Region)) +
  geom_point(alpha = 0.6) +
  geom_text_repel(aes(label = Region), size = 3.5, box.padding = 0.5, point.padding = 0.9) +
  labs(title = "Bubble Chart of Sales by Region", x = "Total Sales", y = "Region") +
  theme_minimal() +
  scale_size_continuous(range = c(3, 15)) +
  scale_x_continuous(labels = scales::label_comma(), breaks = seq(0, max(agg_data$TotalSales), by = 1000000)) +
  guides(color = FALSE, size = FALSE)  # Hide the legends for color and size

## Using The Same Bubble Chart To Compare It With Profit

agg_data <- df %>%
  group_by(Region) %>%
  summarize(TotalProfit = sum(Profit))

ggplot(agg_data, aes(x = TotalProfit, y = Region, size = TotalProfit, color = Region)) +
  geom_point(alpha = 0.6) +
  geom_text_repel(aes(label = Region), size = 3.5, box.padding = 0.5, point.padding = 0.9) +
  labs(title = "Bubble Chart of Profit by Region", x = "Total Profits", y = "Region") +
  theme_minimal() +
  scale_size_continuous(range = c(3, 15)) +
  scale_x_continuous(labels = scales::label_comma(), breaks = seq(0, max(agg_data$TotalProfit), by = 100000)) +
  guides(color = FALSE, size = FALSE) 

## Since the North American region remains to be the leading market we will take a close look at the top states contributing to this profit

df <- df %>% filter(Country == "United States")
state_sales <- df %>%
  group_by(State) %>%
  summarize(TotalSales = sum(Sales), .groups = 'drop') %>%
  arrange(desc(TotalSales)) 

top_states <- head(state_sales, 10)
ggplot(top_states, aes(y = reorder(State, TotalSales), x = TotalSales, fill = TotalSales)) +
  geom_col() +
  geom_text(aes(label = comma(TotalSales), x = TotalSales + 0.05 * TotalSales), hjust = 0) +  # Adjust position dynamically
  labs(title = "Top Performing States in the US by Sales", x = "Total Sales", y = "State") +
  scale_fill_gradient(low = "#FFB6C1", high = "#D2042D", name = "Total Sales") +  # Light pink to red gradient
  scale_x_continuous(labels = label_comma(), 
                     limits = c(0, max(top_states$TotalSales) * 1.1)) +  # Extend the limit by 10%
  theme_minimal() +
  theme(axis.text.y = element_text(angle = 0, hjust = 1),
        legend.position = "none")

## Taking A Closer Look At Profit Will Reveal Intresting Insights For The US Market

df <- df %>% filter(Country == "United States")
state_profits <- df %>%
  group_by(State) %>%
  summarize(TotalProfit = sum(Profit), .groups = 'drop') %>%
  arrange(desc(TotalProfit)) 

top_profit <- head(state_profits, 10)
head(top_profit)
## # A tibble: 6 × 2
##   State      TotalProfit
##   <chr>            <dbl>
## 1 California      76381.
## 2 New York        74039.
## 3 Washington      33403.
## 4 Michigan        24463.
## 5 Virginia        18598.
## 6 Indiana         18383.
state_sales <- df %>%
  group_by(State) %>%
  summarize(TotalSales = sum(Sales), .groups = 'drop')

# Merge the sales data with the top profits data
top_states_data <- merge(top_profit, state_sales, by = "State")

# View the data to ensure it looks correct
print(head(top_states_data))
##        State TotalProfit TotalSales
## 1 California   76381.387  457687.63
## 2   Delaware    9977.375   27451.07
## 3    Georgia   16250.043   49095.84
## 4    Indiana   18382.936   53555.36
## 5   Kentucky   11199.697   36591.75
## 6   Michigan   24463.188   76269.61
top_states_long <- pivot_longer(top_states_data, 
                                cols = c(TotalProfit, TotalSales), 
                                names_to = "Metric", 
                                values_to = "Amount")
ggplot(top_states_long, aes(y = reorder(State, -Amount, FUN = max), x = Amount, fill = Metric)) +
  geom_col(position = position_dodge(width = 0.9)) +
  scale_x_continuous(labels = comma) +  # Ensures numbers are not in scientific notation
  scale_fill_manual(values = c("TotalProfit" = "#FFB6C1", "TotalSales" = "lightblue")) +
  labs(title = "Comparison of Sales vs. Profit for Top 10 States (Ranked by Profit)",
       y = "State",
       x = "Amount (USD)",
       fill = "Metric") +
  theme_minimal() +
  theme(axis.text.y = element_text(angle = 0, hjust = 1))

It’s interesting how 400k in sales turn out to less than 100k in profit. A good reason why Californians are leaving California.

But interestingly since the US is the biggest market for the Global Superstore we take it a step further and analyze where a new market must be launched, in which state. For this the profitability ratio must be calculated. PR= Total Profit/ Total Sales

state_metrics <- df %>%
  group_by(State) %>%
  summarize(TotalSales = sum(Sales), TotalProfit = sum(Profit), .groups = 'drop') %>%
  filter(TotalProfit > 0)

state_metrics <- state_metrics %>%
  mutate(SalesProfitRatio = (TotalProfit / TotalSales) * 100,  
         Rank = rank(-SalesProfitRatio))
top_states_by_ratio <- state_metrics %>%
  arrange(Rank) %>%
  top_n(15, SalesProfitRatio)
ggplot(top_states_by_ratio, aes(y = reorder(State, -SalesProfitRatio), x = SalesProfitRatio, fill = SalesProfitRatio)) +
  geom_col() +
  geom_text(aes(label = sprintf("%.1f%%", SalesProfitRatio), x = SalesProfitRatio + 1), hjust = 0, color = "black") +
  labs(title = "Top 10 States by Sales/Profit Ratio",
       x = "Sales to Profit Ratio (%)",
       y = "State") +
  scale_fill_gradient(low = "#FFB6C1", high = "#D2042D", name = "Sales/Profit Ratio (%)") +  
  scale_x_continuous(expand = expansion(add = 5)) +  
  theme_minimal() +
  theme(axis.text.y = element_text(angle = 0, hjust = 1),  
        legend.position = "right")  

## Where Not To Open A New store?

##first we find the worst profitability ratios
state_metrics <- df %>%
  group_by(State) %>%
  summarize(TotalSales = sum(Sales), TotalProfit = sum(Profit), .groups = 'drop') %>%
  filter(TotalProfit > 0) %>%
  mutate(SalesProfitRatio = (TotalProfit / TotalSales) * 100,  
         Rank = rank(SalesProfitRatio))
bottom_states_by_ratio <- state_metrics %>%
  arrange(Rank) %>%
  slice_head(n = 5)
ggplot(bottom_states_by_ratio, aes(y = reorder(State, SalesProfitRatio), x = SalesProfitRatio, fill = SalesProfitRatio)) +
  geom_col() +
  geom_text(aes(label = sprintf("%.1f%%", SalesProfitRatio), x = SalesProfitRatio + 1), hjust = 0, color = "black") +  # Offset labels to the right of bars
  labs(title = "Bottom 5 States by Sales/Profit Ratio",
       x = "Sales to Profit Ratio (%)",
       y = "State") +
  scale_fill_gradient(low = "#FFB6C1", high = "#D2042D", name = "Sales/Profit Ratio (%)") + 
  scale_x_continuous(expand = expansion(add = 5)) +  
  theme_minimal() +
  theme(axis.text.y = element_text(angle = 0, hjust = 1),  
        legend.position = "right")

## Based off this chart we can see that California has a low % of Sales to Profit ratio, yet this does not tell the full story. At The End Of The Day Investors Want To See $$, So For That Reason We Will Plot Top & Bottom 10 Profit & Margin by State in terms of Dollars

state_profits <- df %>%
  group_by(State) %>%
  summarise(TotalProfit = sum(Profit, na.rm = TRUE)) %>%
  ungroup()

top_states <- state_profits %>%
  top_n(10, TotalProfit)

bottom_states <- state_profits %>%
  top_n(-10, TotalProfit)

combined_states <- bind_rows(top_states, bottom_states) %>%
  arrange(desc(TotalProfit))
ggplot(combined_states, aes(y = reorder(combined_states$State, combined_states$TotalProfit), x = combined_states$TotalProfit, fill = combined_states$TotalProfit)) +
  geom_col() +
  geom_text(aes(label = scales::comma(combined_states$TotalProfit), x = combined_states$TotalProfit), hjust = -0.2, color = "black", size = 3.5) +
  scale_fill_gradient(low = "#FFB6C1", high = "#D2042D", name = "Profit (USD)") +
  labs(title = "Profit Comparison: Top 10 Best vs. Worst Performing States",
       y = "State",
       x = "Total Profit (USD)") +
  theme_minimal() +
  theme(axis.text.y = element_text(angle = 0, hjust = 1),
        legend.position = "right")
## Warning: Use of `combined_states$TotalProfit` is discouraged.
## ℹ Use `TotalProfit` instead.
## Warning: Use of `combined_states$State` is discouraged.
## ℹ Use `State` instead.
## Warning: Use of `combined_states$TotalProfit` is discouraged.
## ℹ Use `TotalProfit` instead.
## Use of `combined_states$TotalProfit` is discouraged.
## ℹ Use `TotalProfit` instead.
## Use of `combined_states$TotalProfit` is discouraged.
## ℹ Use `TotalProfit` instead.
## Use of `combined_states$TotalProfit` is discouraged.
## ℹ Use `TotalProfit` instead.
## Warning: Use of `combined_states$State` is discouraged.
## ℹ Use `State` instead.
## Warning: Use of `combined_states$TotalProfit` is discouraged.
## ℹ Use `TotalProfit` instead.
## Use of `combined_states$TotalProfit` is discouraged.
## ℹ Use `TotalProfit` instead.

Without diving too deep into calculations we have only use the profit as our measure of intrest here. Despite California being on the lower end of the Profit/Sales ratio it still sits on top of the charts when it comes to producing the most profit at the end of the day. Things like tax rates and California regulations might cause the company to have more overhead hence less profitability ratio.

What Products Are Often Bought At High Urgency?

critical_orders <- df %>%
  filter(`Order Priority` == "Critical")
critical_counts <- critical_orders %>%
  group_by(`Product Name`) %>%
  summarise(Critical_Count = n())
# Select top 5 products with the most Critical orders
top_5_critical_products <- critical_counts %>%
  top_n(5, wt = Critical_Count) %>%
  arrange(desc(Critical_Count))

print(top_5_critical_products)
## # A tibble: 17 × 2
##    `Product Name`                                                 Critical_Count
##    <chr>                                                                   <int>
##  1 "Staples"                                                                  23
##  2 "Bush Heritage Pine Collection 5-Shelf Bookcase, Albany Pine …              4
##  3 "Hewlett Packard LaserJet 3310 Copier"                                      4
##  4 "Logitech 910-002974 M325 Wireless Mouse for Web Scrolling"                 4
##  5 "ACCOHIDE 3-Ring Binder, Blue, 1\""                                         3
##  6 "Acco 6 Outlet Guardian Premium Plus Surge Suppressor"                      3
##  7 "Adams Telephone Message Book W/Dividers/Space For Phone Numb…              3
##  8 "GBC DocuBind P100 Manual Binding Machine"                                  3
##  9 "GBC DocuBind P50 Personal Binding Machine"                                 3
## 10 "Hon Deluxe Fabric Upholstered Stacking Chairs, Rounded Back"               3
## 11 "Ibico Plastic Spiral Binding Combs"                                        3
## 12 "Logitech G19 Programmable Gaming Keyboard"                                 3
## 13 "Safco Contoured Stacking Chairs"                                           3
## 14 "Tyvek  Top-Opening Peel & Seel Envelopes, Plain White"                     3
## 15 "Xerox 1912"                                                                3
## 16 "Xerox 212"                                                                 3
## 17 "XtraLife ClearVue Slant-D Ring Binders by Cardinal"                        3
treemap(top_5_critical_products,
        index = "Product Name",
        vSize = "Critical_Count",
        title = "Top 5 Products Bought at Critical Priority",
        #palette = "Reds",
        border.col = "black",
        fontsize.labels = 12,
        fontfamily.labels = "sans",
        align.labels = list(c("center", "center")),
        overlap.labels = 0.5,
        inflate.labels = TRUE)

A treemap like this shows the products we filtered in a tree like graph. The size of the boxes that make up the bigger picture show the count of observations.

Stapels intrestingly are bought at critical order priority? I wonder why!

Intrestingly we can also look at the returns using the same methods

subcategory_returns <- df %>%
  group_by(Sub_Category) %>%
  summarise(Returns = n()) 

subcategory_returns <- subcategory_returns %>%
  mutate(Percentage = Returns / sum(Returns) * 100,
         Label = paste0(Sub_Category, "\n", round(Percentage, 1), "%"))
library(showtext)
## Warning: package 'showtext' was built under R version 4.3.3
## Loading required package: sysfonts
## Warning: package 'sysfonts' was built under R version 4.3.3
## Loading required package: showtextdb
## Warning: package 'showtextdb' was built under R version 4.3.3
font_add_google(name = "Roboto", family = "roboto")
showtext_auto()
ggplot(subcategory_returns, aes(area = Returns, fill = Sub_Category, label = Label)) +
  geom_treemap() +
  geom_treemap_text(colour = "white", place = "centre", grow = TRUE, size = 0.5, family = "roboto") +
  labs(title = "No. of Returned Products by Subcategory") +
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(size = 16, face = "bold", hjust = 0.9, family = "roboto") 
  )

Here I have tried to show the graph with percentages. The subcategories make up the whole 100%.