Analyze Video Game Sales with Python

Load, clean, and visualize 16,000+ video game sales records in Python.

Introduction

30 Second Summary

Video games generate billions in sales across different regions, genres, and platforms. The patterns hidden in that data tell fascinating stories about cultural preferences and industry shifts.

In this project, you will analyze a dataset of 16,000+ video game sales records using Python and pandas to uncover trends in the gaming industry and produce publication-quality visualizations.

What You'll Build

When you run the final notebook, you see bar charts of top-selling genres, a heatmap of regional preferences, and line plots showing the rise and fall of gaming platforms over decades.

By the end of this project, you'll have:

  • A polished Jupyter Notebook with markdown narrative and code cells that takes raw CSV data from load to story.
  • Bar charts and line plots revealing which genres dominate global sales and how platforms rise and fall over time.
  • A regional heatmap comparing how gaming tastes differ between North America, Europe, and Japan.
  • A cleaned dataset exported and ready for future analysis projects.
  • Secret Mission: Build a "Cultural Clash" scatter plot that finds games wildly popular in one region but ignored in another.

Are there any prerequisites?

You should be comfortable with basic Python concepts like variables, functions, and loops. Familiarity with object-oriented programming (like classes and methods) will help you understand how pandas works under the hood.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters to you.

Taking a moment to set your intention makes the hands-on work ahead more focused and purposeful.

Set Up Your Data Science Environment

To analyze video game sales data, you need a workspace that keeps your project's packages isolated and a notebook environment for running code interactively.

In this step, you will create a dedicated project folder, set up a Python virtual environment, install the data science libraries (pandas, matplotlib, seaborn), and configure Jupyter in VS Code so you can write analysis code in cells.

In this step, get ready to:
  • Create a project folder with an isolated virtual environment.
  • Install pandas, matplotlib, and seaborn.
  • Create your first Jupyter Notebook and verify everything works.
Create a project folder and virtual environment
  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Visual Studio Code and press Enter to open it.
  • Open the integrated terminal by pressing Ctrl+` (the backtick key, to the left of 1 on your keyboard).

Every new project folder should live on your Desktop so you can find it easily.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir vg-sales-analysis
cd vg-sales-analysis
  • Confirm the folder exists by running:
pwd

You should see a path ending in vg-sales-analysis.

  • Now open this folder in VS Code. Click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop, select the vg-sales-analysis folder, and click Open.

VS Code reloads with vg-sales-analysis as the workspace. You should see the folder name in the Explorer sidebar on the left.

  • Open a fresh terminal by pressing Ctrl+` again.

A virtual environment keeps your project's packages separate from your system Python. This prevents version conflicts between projects.

  • Create and activate your virtual environment by running the commands for your operating system:

macOS

python3 -m venv .venv
source .venv/bin/activate

After activation, you should see (.venv) at the start of your terminal prompt.

Windows

python -m venv .venv
.venv\Scripts\activate

After activation, you should see (.venv) at the start of your terminal prompt.

Don't see (.venv) in your prompt?

Make sure you ran the activation command (not just the python -m venv line). On macOS, the command starts with source. On Windows, it starts with .venv\Scripts\activate.

If you see a permissions error on Windows, try running Set-ExecutionPolicy -Scope CurrentUser RemoteSigned first, then retry activation.

Help me fix my virtual environment activation

Install packages and Jupyter extension

With your virtual environment active, any packages you install go into .venv and stay isolated from the rest of your system.

  • Install the three data science packages by running:
pip install pandas matplotlib seaborn

What are these packages?

  • pandas loads and transforms tabular data (like spreadsheets) in Python.
  • matplotlib draws charts and plots from your data.
  • seaborn builds on matplotlib with better defaults and more chart types.

You will see a stream of download and installation messages. This may take a minute.

  • Verify all three packages installed correctly by running:
python -c "import pandas; import matplotlib; import seaborn; print('All good:', pandas.__version__)"

You should see All good: followed by a version number. No errors means all three packages are working.

Seeing a ModuleNotFoundError?

This usually means your virtual environment is not active. Check for (.venv) in your terminal prompt. If it is missing, re-run the activation command from the previous substep, then retry the install.

Help me debug my package installation

Now you need two VS Code extensions that let you run Jupyter notebooks directly in the editor.

  • Click the Extensions icon in the left sidebar (it looks like four squares).
  • Type Python in the search bar and find the one published by Microsoft.
  • Click Install if it is not already installed.
  • Search for Jupyter and install the one published by Microsoft.

Both extensions show a green checkmark or Disable button once installed.

Create your first notebook and verify

A Jupyter Notebook lets you write and run code in cells, seeing results immediately below each cell. This is ideal for data exploration.

  • Open the Command Palette by pressing Cmd+Shift+P (macOS) or Ctrl+Shift+P (Windows).
  • Type Create: New Jupyter Notebook and select it from the list.
  • A new untitled notebook opens. Save it immediately with Cmd+S (macOS) or Ctrl+S (Windows).
  • Name the file analysis.ipynb and save it in the vg-sales-analysis folder.

You need to tell the notebook which Python to use. This is called selecting a kernel.

  • Look at the top-right corner of the notebook editor for the kernel picker.
  • Click it and select the .venv Python interpreter from the list (it shows ('.venv') in its name).

What is a kernel?

A kernel is the Python process that actually runs your notebook code. By selecting .venv as the kernel, your notebook uses the same virtual environment where you installed pandas, matplotlib, and seaborn.

Time to run your first cell. This confirms the notebook, kernel, and all packages are working together.

  • Click the first empty cell in the notebook and paste the following code:
# Cell 1 - Imports and Setup
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_theme(style='whitegrid')

print("pandas:", pd.__version__)

What does this code do?

  • import pandas as pd loads the pandas library and gives it the short alias pd.
  • import matplotlib.pyplot as plt loads the plotting functions from matplotlib.
  • import seaborn as sns loads seaborn for more polished charts.
  • sns.set_theme(style='whitegrid') applies a clean grid background to all your future plots.
  • The final print line confirms pandas loaded successfully by showing its version.

Before you run this cell, what do you expect to see printed below it?

  • Run the cell by pressing Shift+Enter.

You should see pandas: followed by a version number (like 2.3.3 or 3.0.5) printed directly below the cell. No errors means your entire data science environment is working.

Seeing a ModuleNotFoundError in the notebook?

This means the notebook kernel is not pointing to your .venv. Click the kernel picker in the top-right corner and make sure you select the interpreter with ('.venv') in its name. Then re-run the cell.

If you do not see .venv in the kernel list, try reloading VS Code (Cmd+Shift+P or Ctrl+Shift+P, then type Developer: Reload Window).

Help me troubleshoot my notebook imports

✔️ Awesome, I've got everything!

Great. Double check you have saved analysis.ipynb and that the output below Cell 1 shows a pandas version number.

ⓧ I'd like to double check the full code

Your analysis.ipynb should have one cell with this exact code:

# Cell 1 - Imports and Setup
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_theme(style='whitegrid')

print("pandas:", pd.__version__)

Your data science environment is ready. Next up, you will load 16,000+ rows of video game sales data and start exploring what is inside.

Load and Explore the Dataset

Your data science environment is ready to go. Now it's time to meet your dataset.

Before you can analyze anything, you need to see what you're working with. Loading the data and running quick inspections gives you a mental model of the dataset's shape, columns, and quirks.

In this step, get ready to:
  • Load 16,000+ video game sales records into a pandas DataFrame.
  • Inspect the dataset's structure, data types, and missing values.
  • Identify the top 10 best-selling games of all time.
Load the CSV into a DataFrame

pandas can load data directly from a URL with a single line of code. No file downloads, no manual imports.

  • Create a new code cell in analysis.ipynb below Cell 1.
  • Load the dataset and preview the first rows by pasting this code and pressing Shift+Enter to run:
# Cell 2 - Load Data
df = pd.read_csv('https://raw.githubusercontent.com/cajjster/data_files/main/vgsales.csv')
df.head()

What does this code do?

pd.read_csv() fetches the CSV file from GitHub and loads all 16,000+ rows into a DataFrame called df. A DataFrame is a table of rows and columns that pandas uses to organize data.

df.head() prints just the first 5 rows so you can quickly see what the data looks like without flooding your screen.

You should see a table with columns like Name, Platform, Year, Genre, and sales figures for different regions.

Seeing a ConnectionError or timeout?

The dataset loads from GitHub, so you need an internet connection. If you're behind a firewall or VPN, try disconnecting and running the cell again.

If the error persists, check that you copied the URL exactly as shown in the code above.

Help me debug my pandas read_csv connection error

Inspect the data structure

You can see rows of data, but how big is the dataset really? And are there any problems lurking in it?

  • Before you run the next cell, predict: how many rows and columns do you think this dataset has based on what you saw in df.head()?
  • Create a new cell and inspect the shape and data types by running:
# Cell 3 - Explore Structure
print("Shape:", df.shape)
print()
df.info()

You should see Shape: (16598, 10) confirming 16,598 rows and 10 columns. Below that, df.info() lists every column with its data type and non-null count.

What should I notice in df.info()?

Look at the Non-Null Count column. Most columns show 16,598 non-null values, meaning no missing data. But Year and Publisher have fewer. Those are the messy spots you'll clean in the next step.

  • Create another cell and run the summary statistics:
# Cell 4 - Summary Stats
df.describe()

What does describe show?

df.describe() calculates the mean, min, max, and percentiles for every numeric column. Notice how Global Sales has a mean around 0.5 million but a max of over 80 million. Most games sell modestly while a few blockbusters dominate.

Seeing fewer than 16,598 rows?

Make sure you haven't accidentally re-run a cell from a later step that modifies df. In Jupyter, cells share state. If your count is off, restart the kernel from the toolbar and run all cells from the top.

Help me understand why my DataFrame row count doesn't match what I expected

Ask your first question with data

Numbers and column names are useful, but the real fun starts when you ask a question. Let's find out which games sold the most copies worldwide.

  • Create a new cell and find the top 10 best-selling games by running:
# Cell 5 - Top 10 Best Sellers
df.nlargest(10, 'Global Sales')[['Name', 'Platform', 'Year', 'Genre', 'Global Sales']]

What does this code do?

df.nlargest(10, 'Global Sales') sorts the entire DataFrame by the Global Sales column and returns only the top 10 rows. The bracket notation at the end selects just the columns you care about, keeping the output clean.

You should see Wii Sports sitting at the top with over 80 million copies sold. Familiar titles like Mario Kart and Tetris round out the list.

  • Add a Markdown cell above Cell 5 to narrate your finding. Click the + Markdown button in the notebook toolbar.
  • Write a short sentence describing what you noticed, such as: "Wii Sports dominates with 82.74M copies sold globally."
  • Run the markdown cell to render it as formatted text.

Why add markdown cells?

A good notebook tells a story. Markdown cells narrate your thought process between code cells. This makes your analysis readable by others and by future-you coming back to it months later.

Not sure where the Markdown button is?

In VS Code's Jupyter interface, hover between two cells and you'll see + Code and + Markdown buttons appear. Click + Markdown to insert a text cell.

Help me add a markdown cell in VS Code Jupyter

✔️ Awesome, I've got everything!

Great. Double check you've saved analysis.ipynb with all 5 code cells intact.

ⓧ I'd like to double check the full code

Here's what your notebook should contain through Cell 5. Each section below is a separate cell in your notebook.

# Cell 1 - Imports and Setup
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_theme(style='whitegrid')

print("pandas:", pd.__version__)
# Cell 2 - Load Data
df = pd.read_csv('https://raw.githubusercontent.com/cajjster/data_files/main/vgsales.csv')
df.head()
# Cell 3 - Explore Structure
print("Shape:", df.shape)
print()
df.info()
# Cell 4 - Summary Stats
df.describe()
# Cell 5 - Top 10 Best Sellers
df.nlargest(10, 'Global Sales')[['Name', 'Platform', 'Year', 'Genre', 'Global Sales']]

You've got a handle on the dataset's structure and already spotted some interesting patterns. Next up, you'll clean those missing values so your analysis doesn't break when you start grouping and plotting.

Clean the Messy Data

Your dataset has missing values lurking in the Year and Publisher columns. If you try to build trend charts from this data, those rows will either break your visualizations or get silently excluded, leaving gaps in your story.

In this step, you will clean the missing data so every chart and calculation you build from here is trustworthy. You will drop rows without a year (since they cannot contribute to time-based analysis) and fill missing publishers with a placeholder.

In this step, get ready to:
  • Inspect the scope of missing data across all columns.
  • Clean the Year and Publisher columns using different strategies.
  • Verify the dataset has zero nulls and still has 16,000+ rows.
Inspect the missing values

Before you clean anything, you need to understand the scope of the problem. A quick null check shows exactly which columns are affected and how many rows are involved.

  • Click the + Code button at the top of your notebook to create a new cell below Cell 5.
  • Check the missing values across all columns by typing this code:
# Cell 6 - Check Missing Values
print("Missing values:")
print(df.isnull().sum())
  • Run the cell by pressing Shift+Enter.

What does this output tell you?

You should see a count of missing values for each column. Year shows around 271 missing values and Publisher shows around 58. All other columns (Name, Platform, sales figures) have 0 missing values.

This tells you the data is mostly clean. Only two columns need attention.

Seeing a NameError for df?

This means the cells above have not been run in order. Click Run All at the top of the notebook to re-run all cells from Cell 1.

Why is my df variable not defined even though I see the code above?

Clean the Year and Publisher columns

Two different columns need two different cleaning strategies. Year values are missing entirely, so those rows cannot help with time-based analysis and should be dropped. Publisher values are just labels, so you can fill them with a placeholder.

  • Create a new code cell below Cell 6.
  • Clean both columns and verify the result by typing this code:
# Cell 7 - Clean Data
df = df.dropna(subset=['Year'])
df['Year'] = df['Year'].astype(int)
df['Publisher'] = df['Publisher'].fillna('Unknown')

print("After cleaning:")
print(df.isnull().sum())
print(f"\nRows remaining: {len(df)}")

What does this code do?

  • df.dropna(subset=['Year']) removes any row where Year is missing. These rows cannot appear on a timeline chart.
  • .astype(int) converts Year from a decimal (like 2008.0) to a clean integer (2008). Charts look better with whole years.
  • .fillna('Unknown') replaces missing Publisher values with the string 'Unknown' instead of dropping the row. These games still have valid sales data worth keeping.
  • The print statements at the end confirm the cleaning worked by showing the null count and remaining row count.

Before you run this cell, what do you expect the missing value counts to show after cleaning? How many rows do you think will remain?

  • Run the cell with Shift+Enter.

You should see every column showing 0 missing values. The row count should be 16,000+ rows, confirming you only lost the ~271 rows that had no year.

Why drop Year but fill Publisher?

Year is a numeric value that you will use as a chart axis. You cannot plot a game on a timeline if you do not know when it was released. Dropping is the only honest choice.

Publisher is a categorical label. A game with an unknown publisher still has valid sales data worth analyzing. Filling with 'Unknown' keeps the row in your dataset without pretending you know who published it.

Seeing a ValueError on astype(int)?

This means the dropna line did not run first. Make sure all three cleaning lines are in the same cell and the dropna comes before astype(int). You cannot convert a column to integer while it still contains NaN values.

Why am I getting a ValueError when converting Year to int in my pandas DataFrame?

✔️ Awesome, I've got everything!

Great. Double check your notebook is saved by pressing Ctrl+S (Windows) or Cmd+S (macOS).

ⓧ I'd like to double check the full code

Your notebook should have these cells in order. Scroll through your notebook and confirm each one is present:

  • Cell 1 - Imports and Setup (imports pandas, matplotlib, seaborn, sets theme, prints version).
  • Cell 2 - Load Data (reads CSV from URL into df, shows head).
  • Cell 3 - Explore Structure (prints shape and info).
  • Cell 4 - Summary Stats (describe on numeric columns).
  • Cell 5 - Top 10 Best Sellers (nlargest 10 by Global Sales).
  • Cell 6 - Check Missing Values (prints null counts per column).
  • Cell 7 - Clean Data (drops Year nulls, converts to int, fills Publisher, prints verification).

Your dataset is now clean and ready for analysis. Next up, you will use groupby to collapse thousands of rows into clear patterns about genres, platforms, and regions.

Analyze Sales Trends with Groupby

You have 16,000+ rows of clean data, but scrolling through individual games tells you nothing about the bigger picture. To find real patterns, you need to group rows together and ask questions like "which genre sells the most overall?" or "which platforms dominated over time?"

The pandas groupby method does exactly this. It groups rows by a column value, then lets you run calculations (sum, mean, count) on each group. In this step, you will transform raw rows into clear, summarized insights about the gaming industry.

In this step, get ready to:
  • Group games by genre to find which genres sell the most globally.
  • Identify the top 5 gaming platforms by total sales.
  • Compare how game preferences differ across North America, Europe, and Japan.
Find the top genres by total global sales

Your first question: which game genres generate the most sales worldwide? Answering this requires grouping all games by their Genre column, summing Global Sales for each group, and sorting the result.

  • Create a new cell below Cell 7 by clicking the + Code button in the toolbar (or pressing Escape then B).
  • Add this code to group games by genre and display the results:
# Cell 8 - Genre Sales Analysis
genre_sales = df.groupby('Genre')['Global Sales'].sum().sort_values(ascending=False)
print(genre_sales)

Before you run this, which genre do you think sells the most globally?

  • Run the cell by pressing Shift+Enter.

You should see a sorted list of genres with Action at the top, followed by Sports and Shooter.

What does this code do?

This line does three things in sequence:

  • groupby('Genre') splits the DataFrame into separate groups, one per genre.
  • ['Global Sales'].sum() totals the sales column within each group.
  • sort_values(ascending=False) puts the highest-selling genre first.

Seeing a KeyError?

Make sure you type 'Global Sales' with a space between the words. The column name in this dataset uses a space, not an underscore.

If the cell runs but you see an empty Series, confirm that Cell 7 (your cleaning cell) was run successfully before this one.

Why isn't my groupby producing output?

Analyze platform lifecycles

Now you know which genres dominate. The next question: which gaming platforms generated the most sales across their lifetimes? You will identify the top 5 platforms and build a filtered DataFrame that tracks their yearly performance.

  • Create a new cell below Cell 8 by clicking + Code.
  • Add this code to find the top 5 platforms and filter the data to just those:
# Cell 10 - Platform Lifecycle Data
top_platforms = df.groupby('Platform')['Global Sales'].sum().nlargest(5).index.tolist()
platform_year = df[df['Platform'].isin(top_platforms)].groupby(['Year', 'Platform'])['Global Sales'].sum().reset_index()
  • Run the cell by pressing Shift+Enter.
  • The cell runs without visible output because both lines are assignments. To verify it worked, type top_platforms in the new cell that your cursor moved to and press Shift+Enter.

You should see a list of 5 platform names (like PS2, X360, PS3, Wii, and DS).

What does this code do?

  • The first line groups all games by platform, sums their global sales, picks the top 5, and extracts just the platform names as a list.
  • The second line filters the full DataFrame to only games on those 5 platforms, then groups by both year and platform to get annual sales totals. This gives you the data you need to plot platform lifecycles in the next step.

Seeing a TypeError or empty list?

Check that .tolist() is at the end of the first line. Without it, top_platforms is an Index object instead of a plain list, which can cause issues downstream.

Help me debug my platform lifecycle groupby code

Compare regional preferences

Different regions have very different tastes in games. Japan's best-selling genres look nothing like North America's. You will group by genre and sum the regional sales columns to reveal these differences.

  • Delete the temporary top_platforms verification cell (click on it, then press Escape followed by DD to delete).
  • Click back into your Cell 10 (the platform lifecycle cell) and add this code below the existing lines:

# Regional Genre Preferences
region_genre = df.groupby('Genre')[['NA_Sales', 'EU_Sales', 'JP_Sales']].sum()
  • Run the cell by pressing Shift+Enter.
  • In the next cell, type region_genre and press Shift+Enter to see the grouped data.

You should see a table with genres as rows and three columns showing total sales for NA, EU, and JP. Notice how Role-Playing has much higher JP_Sales relative to NA_Sales compared to other genres.

What patterns do you notice?

Look at the Action and Shooter rows. North America dominates those. Now look at Role-Playing. Japan's sales are much closer to (or exceed) the other regions.

This single DataFrame already tells a cultural story. You will turn it into a heatmap visualization in the next step to make the contrast even more obvious.

Columns not found?

Make sure you use the exact column names NA_Sales, EU_Sales, and JP_Sales with underscores. These columns use underscores (unlike Global Sales which has a space).

Help me fix my regional genre preferences groupby

  • Delete the temporary region_genre verification cell (click it, press Escape then DD).

✔️ Awesome, I've got everything!

Great. Make sure you have saved your notebook (Ctrl+S or Cmd+S).

ⓧ I'd like to double check the full code

Your notebook should now have Cells 1 through 10. Scroll through and confirm these cells are present in order:

  • Cells 1-7 (unchanged from the previous step): imports, load, explore, stats, top 10, missing values check, and cleaning.
  • Cell 8 - Genre Sales Analysis:
  • Cell 10 - Platform Lifecycle Data + Regional Genre Preferences:
# Cell 8 - Genre Sales Analysis
genre_sales = df.groupby('Genre')['Global Sales'].sum().sort_values(ascending=False)
print(genre_sales)
# Cell 10 - Platform Lifecycle Data
top_platforms = df.groupby('Platform')['Global Sales'].sum().nlargest(5).index.tolist()
platform_year = df[df['Platform'].isin(top_platforms)].groupby(['Year', 'Platform'])['Global Sales'].sum().reset_index()

# Regional Genre Preferences
region_genre = df.groupby('Genre')[['NA_Sales', 'EU_Sales', 'JP_Sales']].sum()

Make sure no temporary verification cells remain between these. If you see stray cells with just top_platforms or region_genre, delete them.

You now have clean, grouped data that reveals the gaming industry's structure. Next up, you will turn these numbers into polished visualizations that tell the story at a glance.

Visualize Your Findings

You have crunched the numbers. Genre rankings, platform lifecycles, and regional breakdowns are sitting in your notebook as sorted Series and DataFrames. The problem is that a table of numbers is forgettable.

A well-designed chart communicates the same pattern in a single glance. In this step, you will turn your analytical results into three publication-quality visualizations that tell the story of global gaming.

In this step, get ready to:
  • Create a horizontal bar chart ranking genres by total global sales.
  • Plot platform lifecycles as a multi-line chart showing rises and falls over time.
  • Build a heatmap revealing how gaming tastes differ between NA, EU, and Japan.
Create a bar chart of top genres

Your genre_sales Series is already sorted from highest to lowest. A horizontal bar chart is the perfect match for ranked categorical data because long genre names stay readable on the y-axis.

  • In your notebook, find Cell 9 (the placeholder cell). Replace its contents entirely with the following bar chart code:
# Cell 9 - Top Genres Bar Chart
fig, ax = plt.subplots(figsize=(10, 6))
genre_sales.plot(kind='barh', ax=ax, color='steelblue')
ax.set_xlabel('Total Global Sales (millions)')
ax.set_ylabel('Genre')
ax.set_title('Video Game Sales by Genre (1980-2020)')
ax.invert_yaxis()
plt.tight_layout()
plt.show()

What does this code do?

  • plt.subplots(figsize=(10, 6)) creates a figure and axes object at a specific size (10 inches wide, 6 tall).
  • genre_sales.plot(kind='barh') tells pandas to draw horizontal bars directly from the Series.
  • ax.invert_yaxis() flips the y-axis so the highest-selling genre (Action) appears at the top instead of the bottom.
  • plt.tight_layout() prevents labels from getting clipped at the edges of the figure.
  • Run the cell with Shift+Enter.

You should see a horizontal bar chart with Action clearly leading, followed by Sports and Shooter.

Don't see a chart?

  • Make sure you ran Cell 8 first (it computes genre_sales). If the variable isn't in memory, the chart cell will throw a NameError.
  • Check that plt.show() is the last line in the cell. Without it, some environments suppress the output.

Still stuck? Why isn't my matplotlib chart showing in a Jupyter notebook?

Create a line plot of platform lifecycles

A line plot shows how each platform's sales rose and fell over the decades. You already have platform_year filtered to the top 5 platforms. Now you will draw one line per platform.

  • Create a new cell below Cell 10. This becomes Cell 11. Paste the following code:
# Cell 11 - Platform Lifecycle Line Plot
fig, ax = plt.subplots(figsize=(12, 6))
for platform in top_platforms:
    data = platform_year[platform_year['Platform'] == platform]
    ax.plot(data['Year'], data['Global Sales'], label=platform, linewidth=2)

ax.set_xlabel('Year')
ax.set_ylabel('Total Sales (millions)')
ax.set_title('Rise and Fall of Gaming Platforms')
ax.legend()
ax.set_xlim(1995, 2020)
plt.tight_layout()
plt.show()

What does this code do?

  • The for loop draws a separate line for each of the 5 platforms, filtering platform_year to one platform at a time.
  • ax.set_xlim(1995, 2020) zooms in on the era where these platforms were active, cutting out sparse early years.
  • ax.legend() adds a color-coded legend so you can identify which line belongs to which platform.
  • Run Cell 11 with Shift+Enter.

You should see 5 colored lines showing distinct lifecycles. The Wii peaks dramatically around 2008-2009, then drops off. The DS follows a similar arc.

Lines look flat or missing?

  • If all lines are hugging zero, confirm Cell 10 ran successfully. Run it again (Shift+Enter in Cell 10) to repopulate top_platforms and platform_year.
  • If you see a NameError for top_platforms, run all cells above this one first (Run All from the notebook toolbar).

Need help? My line plot looks wrong or throws an error.

Create a heatmap of regional genre preferences

Raw sales totals are hard to compare across regions because NA has higher total volume than Japan. Normalizing each column to proportions puts all three regions on the same 0-1 scale. A seaborn heatmap then color-codes those proportions so patterns jump out visually.

  • In Cell 10, find and delete these two lines at the bottom of the cell:
# Regional Genre Preferences
region_genre = df.groupby('Genre')[['NA_Sales', 'EU_Sales', 'JP_Sales']].sum()
  • Cell 10 should now only contain the platform lifecycle data (top_platforms and platform_year).
  • Create a new cell below Cell 11. This becomes Cell 12. Paste the following code to compute normalized regional preferences:
# Cell 12 - Regional Genre Preferences
region_genre = df.groupby('Genre')[['NA_Sales', 'EU_Sales', 'JP_Sales']].sum()
region_genre_pct = region_genre.div(region_genre.sum(axis=0), axis=1)
  • Run Cell 12 with Shift+Enter. No visible output yet, but region_genre_pct is now in memory.
  • Create one more cell below (Cell 13). Paste the heatmap code:
# Cell 13 - Regional Heatmap
fig, ax = plt.subplots(figsize=(10, 8))
sns.heatmap(
    region_genre_pct,
    annot=True,
    fmt='.2f',
    cmap='YlOrRd',
    ax=ax
)
ax.set_title('Genre Preferences by Region (proportion of total sales)')
ax.set_xlabel('Region')
ax.set_ylabel('Genre')
plt.tight_layout()
plt.show()

What does this code do?

  • region_genre.div(region_genre.sum(axis=0), axis=1) divides each cell by its column total, converting raw sales into proportions (0 to 1). This lets you compare regions fairly despite different total volumes.
  • annot=True prints the numeric value inside each heatmap cell so you can read exact proportions.
  • cmap='YlOrRd' uses a yellow-to-red color scale. Darker red means a higher share of that region's total sales goes to that genre.

Before you run Cell 13, predict: which genre do you think will have the darkest cell in the JP column?

  • Run Cell 13 with Shift+Enter.

You should see a color-coded grid. Japan's Role-Playing cell stands out immediately as the darkest in the JP column. NA and EU lean toward Action and Sports instead.

Heatmap looks blank or throws an error?

  • If you see a NameError for region_genre_pct, make sure you ran Cell 12 first. The heatmap cell depends on that variable.
  • If annotations overlap or look garbled, double-check figsize=(10, 8) in the first line. A smaller figure squishes the text.

Still stuck? My seaborn heatmap isn't rendering correctly in Jupyter.

✔️ Awesome, I've got everything!

Great. Make sure all cells are saved (Ctrl+S) and your notebook shows Cells 1 through 13.

ⓧ I'd like to double check the full code

Scroll through your notebook and confirm these cells are present in order:

  • Cell 1 - Imports and Setup (pandas, matplotlib, seaborn imports with sns.set_theme).
  • Cell 2 - Load Data (pd.read_csv from URL).
  • Cell 3 - Explore Structure (df.shape and df.info()).
  • Cell 4 - Summary Stats (df.describe()).
  • Cell 5 - Top 10 Best Sellers.
  • Cell 6 - Check Missing Values.
  • Cell 7 - Clean Data (drop nulls, convert Year, fill Publisher).
  • Cell 8 - Genre Sales Analysis (genre_sales groupby).
  • Cell 9 - Top Genres Bar Chart (horizontal bar chart with invert_yaxis).
  • Cell 10 - Platform Lifecycle Data (top_platforms and platform_year only).
  • Cell 11 - Platform Lifecycle Line Plot (for loop drawing 5 lines).
  • Cell 12 - Regional Genre Preferences (region_genre and region_genre_pct normalization).
  • Cell 13 - Regional Heatmap (sns.heatmap with YlOrRd colormap and annotations).

Your data now tells a visual story. Anyone glancing at these charts can instantly see that Action games dominate globally, the Wii had a meteoric rise, and Japan has a dramatically different taste in genres. Next up, take on the Secret Mission to dig even deeper into those cultural differences.

Secret mission

The Cultural Clash Analysis

Your heatmap revealed that Japan's gaming tastes differ from the rest of the world. But which specific games are massive hits in one region and completely ignored in another? In this mission, you'll engineer a regional dominance metric and build a scatter plot that exposes the most extreme cultural clashes in gaming history.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally, so there are no ongoing costs.

Resources you used:

  • vg-sales-analysis project folder (contains virtual environment, notebook, and installed packages).
  • Jupyter extension for VS Code (by Microsoft).
  • Python extension for VS Code (by Microsoft).

Keep everything running

No action needed. Choose this if you plan to continue exploring the dataset or want to keep the notebook as a reference.

  • Your vg-sales-analysis folder stays on your Desktop with all your charts and analysis intact.
  • The Jupyter and Python extensions remain available for future Python notebooks.
  • Consider pushing the folder to GitHub as a portfolio artifact.

Pause - I'll come back to this later

Deactivate your virtual environment to free up the terminal session. Your files stay on disk and you can reactivate later.

  • In the VS Code terminal, run the following command to deactivate the virtual environment:
deactivate
  • Close VS Code. When you return, reopen the vg-sales-analysis folder and reactivate the environment with .venv\Scripts\activate (Windows) or source .venv/bin/activate (macOS/Linux).

Delete - I don't want to use this again

Remove all project files and optionally uninstall the VS Code extensions you added for this project.

  • Close VS Code.
  • Delete the project folder. On macOS/Linux, open a terminal and run:
rm -rf ~/Desktop/vg-sales-analysis
  • On Windows, open PowerShell and run:
Remove-Item -Recurse -Force ~\Desktop\vg-sales-analysis
  • To uninstall the Jupyter and Python extensions, open VS Code and press Ctrl+Shift+X to open the Extensions view.
  • Find the Jupyter extension, click the gear icon on its tile, then select Uninstall.
  • Repeat for the Python extension if you no longer need Python support in VS Code.

That's a Wrap!

That's a Wrap!

Nice work! You just transformed 16,000+ rows of raw video game sales data into a polished analytical notebook with charts that tell a real story about the gaming industry.

You've learned how to:

  • Loaded and cleaned a real-world dataset using pandas, handling missing values and type conversions to make your analysis trustworthy.
  • Used groupby aggregation to transform thousands of rows into clear patterns across genres, platforms, and regions.
  • Created publication-quality data visualizations (bar charts, line plots, and heatmaps) with matplotlib and seaborn that communicate insights at a glance.
  • Secret Mission: Built a Cultural Clash scatter plot revealing how gaming tastes differ dramatically between Japan and North America.

Ready to quiz yourself?