Introduction

The video game industry has grown significantly over the past few decades, generating billions of dollars in global revenue. This project analyzes historical video game sales data to identify trends across genres, gaming platforms, publishers, and regions. Through a variety of visualizations, the report highlights patterns in sales performance and demonstrates effective data visualization techniques using R.

Import the Data

library(readr)

games <- read_csv("vgsales.csv")

glimpse(games)
## Rows: 16,598
## Columns: 11
## $ Rank         <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17…
## $ Name         <chr> "Wii Sports", "Super Mario Bros.", "Mario Kart Wii", "Wii…
## $ Platform     <chr> "Wii", "NES", "Wii", "Wii", "GB", "GB", "DS", "Wii", "Wii…
## $ Year         <chr> "2006", "1985", "2008", "2009", "1996", "1989", "2006", "…
## $ Genre        <chr> "Sports", "Platform", "Racing", "Sports", "Role-Playing",…
## $ Publisher    <chr> "Nintendo", "Nintendo", "Nintendo", "Nintendo", "Nintendo…
## $ NA_Sales     <dbl> 41.49, 29.08, 15.85, 15.75, 11.27, 23.20, 11.38, 14.03, 1…
## $ EU_Sales     <dbl> 29.02, 3.58, 12.88, 11.01, 8.89, 2.26, 9.23, 9.20, 7.06, …
## $ JP_Sales     <dbl> 3.77, 6.81, 3.79, 3.28, 10.22, 4.22, 6.50, 2.93, 4.70, 0.…
## $ Other_Sales  <dbl> 8.46, 0.77, 3.31, 2.96, 1.00, 0.58, 2.90, 2.85, 2.26, 0.4…
## $ Global_Sales <dbl> 82.74, 40.24, 35.82, 33.00, 31.37, 30.26, 30.01, 29.02, 2…

Data Cleaning

library(dplyr)

games <- games %>%
  filter(!is.na(Year)) %>%
  mutate(Year = as.numeric(Year))

summary(games)
##       Rank           Name             Platform              Year     
##  Min.   :    1   Length:16598       Length:16598       Min.   :1980  
##  1st Qu.: 4151   Class :character   Class :character   1st Qu.:2003  
##  Median : 8300   Mode  :character   Mode  :character   Median :2007  
##  Mean   : 8301                                         Mean   :2006  
##  3rd Qu.:12450                                         3rd Qu.:2010  
##  Max.   :16600                                         Max.   :2020  
##                                                        NA's   :271   
##     Genre            Publisher            NA_Sales          EU_Sales      
##  Length:16598       Length:16598       Min.   : 0.0000   Min.   : 0.0000  
##  Class :character   Class :character   1st Qu.: 0.0000   1st Qu.: 0.0000  
##  Mode  :character   Mode  :character   Median : 0.0800   Median : 0.0200  
##                                        Mean   : 0.2647   Mean   : 0.1467  
##                                        3rd Qu.: 0.2400   3rd Qu.: 0.1100  
##                                        Max.   :41.4900   Max.   :29.0200  
##                                                                           
##     JP_Sales         Other_Sales        Global_Sales    
##  Min.   : 0.00000   Min.   : 0.00000   Min.   : 0.0100  
##  1st Qu.: 0.00000   1st Qu.: 0.00000   1st Qu.: 0.0600  
##  Median : 0.00000   Median : 0.01000   Median : 0.1700  
##  Mean   : 0.07778   Mean   : 0.04806   Mean   : 0.5374  
##  3rd Qu.: 0.04000   3rd Qu.: 0.04000   3rd Qu.: 0.4700  
##  Max.   :10.22000   Max.   :10.57000   Max.   :82.7400  
## 

Visualization 1: Top 10 Video Game Genres by Global Sales

genre_sales <- games %>%
  group_by(Genre) %>%
  summarise(TotalSales = sum(Global_Sales, na.rm = TRUE)) %>%
  arrange(desc(TotalSales))

ggplot(genre_sales,
       aes(x = reorder(Genre, TotalSales),
           y = TotalSales)) +
  geom_col(fill = "steelblue") +
  coord_flip() +
  labs(
    title = "Top Video Game Genres by Global Sales",
    x = "Genre",
    y = "Global Sales (Millions of Units)"
  ) +
  theme_minimal()

Visualization 2: Global Video Game Sales Trend by Release Year

year_sales <- games %>%
  group_by(Year) %>%
  summarise(TotalSales = sum(Global_Sales, na.rm = TRUE))

ggplot(year_sales, aes(x = Year, y = TotalSales)) +
  geom_line(color = "darkgreen", linewidth = 1) +
  geom_point(color = "darkgreen", size = 2) +
  labs(
    title = "Global Video Game Sales by Release Year",
    x = "Release Year",
    y = "Global Sales (Millions of Units)"
  ) +
  theme_minimal()

Visualization 3: Distribution of Global Sales by Genre

ggplot(games, aes(x = Genre, y = Global_Sales)) +
  geom_boxplot(fill = "skyblue", outlier.color = "red") +
  labs(
    title = "Distribution of Global Video Game Sales by Genre",
    x = "Genre",
    y = "Global Sales (Millions of Units)"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Visualization 4: Top 10 Gaming Platforms by Global Sales

platform_sales <- games %>%
  group_by(Platform) %>%
  summarise(TotalSales = sum(Global_Sales, na.rm = TRUE)) %>%
  arrange(desc(TotalSales)) %>%
  slice_head(n = 10)

ggplot(platform_sales,
       aes(x = reorder(Platform, TotalSales),
           y = TotalSales)) +
  geom_col(fill = "darkorange") +
  coord_flip() +
  labs(
    title = "Top 10 Gaming Platforms by Global Sales",
    x = "Platform",
    y = "Global Sales (Millions of Units)"
  ) +
  theme_minimal()

# Visualization 5: Correlation Between Regional Sales

library(ggplot2)

corr <- cor(
  games[, c("NA_Sales", "EU_Sales", "JP_Sales", "Other_Sales")],
  use = "complete.obs"
)

corr_df <- as.data.frame(as.table(corr))

ggplot(corr_df,
       aes(Var1, Var2, fill = Freq)) +
  geom_tile() +
  geom_text(aes(label = round(Freq, 2)),
            color = "white",
            size = 5) +
  scale_fill_gradient(
    low = "lightblue",
    high = "darkblue"
  ) +
  labs(
    title = "Correlation Between Regional Video Game Sales",
    x = "",
    y = ""
  ) +
  theme_minimal()

Visualization 6: Regional Sales by Genre

library(tidyr)

genre_region <- games %>%
  group_by(Genre) %>%
  summarise(
    NorthAmerica = sum(NA_Sales),
    Europe = sum(EU_Sales),
    Japan = sum(JP_Sales),
    Other = sum(Other_Sales)
  ) %>%
  pivot_longer(
    cols = NorthAmerica:Other,
    names_to = "Region",
    values_to = "Sales"
  )

ggplot(genre_region,
       aes(x = Genre, y = Sales, fill = Region)) +
  geom_col() +
  labs(
    title = "Regional Sales by Video Game Genre",
    x = "Genre",
    y = "Sales (Millions of Units)"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Visualization 7: Top 15 Publishers by Global Sales

publisher_sales <- games %>%
  group_by(Publisher) %>%
  summarise(TotalSales = sum(Global_Sales, na.rm = TRUE)) %>%
  arrange(desc(TotalSales)) %>%
  slice_head(n = 15)

ggplot(publisher_sales,
       aes(x = reorder(Publisher, TotalSales),
           y = TotalSales)) +
  geom_segment(aes(
    x = Publisher,
    xend = Publisher,
    y = 0,
    yend = TotalSales
  ),
  color = "gray") +
  geom_point(size = 4, color = "red") +
  coord_flip() +
  labs(
    title = "Top 15 Publishers by Global Sales",
    x = "Publisher",
    y = "Global Sales (Millions of Units)"
  ) +
  theme_minimal()

# Visualization 8: Interactive Global Sales Scatter Plot

library(plotly)

p <- ggplot(games,
            aes(x = Year,
                y = Global_Sales,
                color = Genre,
                text = Name)) +
  geom_point(alpha = 0.7) +
  labs(
    title = "Interactive Scatter Plot of Video Game Sales",
    x = "Release Year",
    y = "Global Sales (Millions of Units)"
  ) +
  theme_minimal()

ggplotly(p, tooltip = c("text", "x", "y"))

Conclusion

This project explored historical video game sales using multiple visualization techniques. The analysis showed that Action and Sports games generated the highest global sales, while platforms such as the PlayStation 2 and Nintendo DS dominated the market. Sales trends increased steadily until the late 2000s before declining in subsequent years. Regional comparisons revealed that North America contributed the largest share of global sales, with Europe following closely. The interactive visualization further enabled detailed exploration of individual games across genres and release years. Overall, the project demonstrates how data visualization can effectively communicate meaningful insights from large datasets.