Analyze Global Development Trends

Load, clean, and visualize 55 years of global health and wealth data.

Introduction

30 Second Summary

Have you ever wondered which parts of the world are getting healthier, wealthier, or falling behind? The answers are hiding in decades of global data, waiting for someone to chart them.

In this project, you will write a Python script that loads real development data for 200+ countries, cleans a messy category, and produces publication-quality charts revealing 55 years of global change.

What You'll Build

You'll run a single script and watch two charts appear on your screen: one showing life expectancy rising across five continents, and another revealing the striking link between a country's wealth and its citizens' lifespan.

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

  • A running pandas script that charts life expectancy trends across five continents from 1952 to 2007, showing exactly which regions improved fastest.
  • A scatter plot revealing the relationship between a country's wealth and its citizens' lifespan, with 100+ colored dots you can interpret at a glance.
  • Saved PNG chart files you can share in a portfolio, drop into a presentation, or post online.
  • Secret Mission: Build the famous Hans Rosling bubble chart where each country's population determines its bubble size.

Are there any prerequisites?

You should be comfortable with basic Python concepts like variables, loops, functions, and lists. No data analysis experience is needed.

Before We Start

Before We Start...

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

Set Up Your Environment

To analyze data in Python, you need two libraries. pandas handles loading and manipulating tabular data. matplotlib handles creating charts and visualizations.

In this step, you'll install both libraries, create your script file, and verify everything is connected before touching any real data.

In this step, get ready to:
  • Install pandas and matplotlib.
  • Create the analysis.py script file.
  • Verify both libraries load correctly.
Install pandas and matplotlib
  • Open a terminal in VS Code by pressing Ctrl+` (backtick key, next to the 1 key on your keyboard).
  • Install both libraries by running this command:
pip install pandas==3.0.3 matplotlib==3.11.0

You'll see download progress bars followed by a "Successfully installed" message listing both packages.

Seeing 'command not found' for pip?

Try pip3 instead of pip. On some systems, Python 3's package manager is named pip3.

If that doesn't work, make sure Python 3.13 is installed correctly by running python --version or python3 --version.

help me fix a pip command not found error in my VS Code terminal

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

You should see the data-analysis folder listed in the output. The folder is empty for now.

  • Create your script file by running:
touch analysis.py
  • Open analysis.py in VS Code's editor by clicking on it in the Explorer sidebar on the left. If the Explorer doesn't show your folder, click File in the top menu, then Open Folder, and select the data-analysis folder on your Desktop.
  • Add this verification code to analysis.py:
import pandas as pd
import matplotlib.pyplot as plt

print("pandas version:", pd.__version__)
print("matplotlib version:", plt.matplotlib.__version__)
print("\nSetup complete! Ready to analyze data.")

What does this code do?

  • import pandas as pd loads the pandas library and gives it the shorthand pd so you can type less.
  • import matplotlib.pyplot as plt loads matplotlib's plotting module as plt.
  • The print statements confirm each library is installed by printing its version number.
  • Save analysis.py by pressing Cmd+S (macOS) or Ctrl+S (Windows).

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

Your analysis.py should look exactly like this:

import pandas as pd
import matplotlib.pyplot as plt

print("pandas version:", pd.__version__)
print("matplotlib version:", plt.matplotlib.__version__)
print("\nSetup complete! Ready to analyze data.")
Run the script and confirm the setup

Before you run this script, what do you think will print in the terminal? How many lines of output do you expect?

  • Run your script by entering this command in the terminal:
python analysis.py

You should see output like this:

pandas version: 3.0.3
matplotlib version: 3.11.0

Setup complete! Ready to analyze data.

What should I see?

The first two lines confirm pandas 3.0.3 and matplotlib 3.11.0 are installed and importable. The final line proves both libraries loaded without errors.

Seeing ModuleNotFoundError?

This means Python can't find pandas or matplotlib. Make sure you ran the pip install command in the same terminal session. If you used pip3 to install, try running with python3 analysis.py instead.

help me fix a ModuleNotFoundError when importing pandas or matplotlib in my Python script

Your environment is ready. Next up, you'll load a real dataset with thousands of rows and explore what's inside it.

Load the Data and Get a First Look

Your environment is set up and ready to go. Now it's time to bring in real data and start asking questions about it.

Before you can analyze anything, you need to get the data into Python and understand its structure. What columns exist? How many rows? What types of values are you working with? This step answers all of those questions.

In this step, get ready to:
  • Load a real-world dataset with 3,300+ rows into a pandas DataFrame.
  • Print the dataset's shape, columns, and data types.
  • Generate summary statistics and check for missing values.
Load the Gapminder dataset into a DataFrame

The Gapminder dataset contains life expectancy, GDP per capita, and population data for over 200 countries from 1952 to 2007. You'll load it directly from a URL into a pandas DataFrame.

  • In analysis.py, select and delete the three print statements below the imports (the version checks from Step 1).
  • Replace them with the following code that loads the dataset and prints its basic structure:
# Load the dataset
url = "https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv"
df = pd.read_csv(url)

# Explore the data
print("Dataset shape:", df.shape)
print("\nFirst 5 rows:")
print(df.head())
print("\nData types:")
print(df.dtypes)

What does this code do?

  • pd.read_csv(url) downloads the CSV file from the URL and loads it into a DataFrame called df. A DataFrame is a table structure with rows and columns, like a spreadsheet in Python.
  • df.shape tells you how many rows and columns the dataset has.
  • df.head() prints the first 5 rows so you can see what the data looks like.
  • df.dtypes shows the data type of each column (text, integers, decimals).
  • Save analysis.py.
  • Run the script by entering this command in your terminal:
python analysis.py

You should see Dataset shape: (3313, 6) followed by a table showing the first 5 rows with columns like country, continent, year, lifeExp, pop, and gdpPercap.

Seeing a connection error?

The script downloads data from the internet. Make sure you have an active internet connection.

If you see a NameError about pd, check that your import pandas as pd line is still at the top of the file.

help me debug a connection or NameError when loading a CSV with pandas

Add summary statistics and missing value checks

Knowing the shape and columns is a start, but you also need to understand the range of values and whether any data is missing.

  • Add the following code at the bottom of analysis.py, below your existing print statements:
print("\nBasic statistics:")
print(df.describe())
print("\nUnique continents:", df["continent"].unique())
print("\nRows per continent:")
print(df["continent"].value_counts())
print("\nMissing values:")
print(df.isnull().sum())

What does this code do?

  • df.describe() generates statistics (mean, min, max, standard deviation) for every numeric column at once.
  • df["continent"].unique() lists every distinct value in the continent column so you can spot anything unexpected.
  • df["continent"].value_counts() shows how many rows belong to each continent, revealing the data distribution.
  • df.isnull().sum() counts missing values per column. Gaps in data can skew your analysis if not handled.

Before you run, take a guess: how many continents do you think exist in this dataset?

  • Save analysis.py and run the script again:
python analysis.py

Scroll through the output. You should see the dataset shape (3313 rows x 6 columns), the first 5 rows, data types, and summary statistics for all numeric columns.

Now look at the "Unique continents" line. You'll see 6 values: Africa, Americas, Asia, Europe, FSU, and Oceania. That FSU stands for "Former Soviet Union." It's not a real continent. This is a data quality issue you'll fix in a later step.

Why does FSU matter?

The dataset labels 14 countries (Russia, Ukraine, Kazakhstan, etc.) with "FSU" instead of their geographic continent. If you charted this data right now, you'd get a misleading 6th line on your graph representing a political grouping, not a geographic one.

Spotting inconsistencies like this is the most common data cleaning task in real analytics work.

Not seeing all the output?

If your terminal output is cut off, scroll up in the terminal to see earlier lines. On macOS, use Cmd+Up. On Windows, use Ctrl+Up or the scrollbar.

help me see the full terminal output from my Python script in VS Code

✔️ Awesome, I've got everything!

Great. Double check you've saved analysis.py and move on to the next step.

ⓧ I'd like to double check the full code

Here's the complete analysis.py at this point:

import pandas as pd
import matplotlib.pyplot as plt

# Load the dataset
url = "https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv"
df = pd.read_csv(url)

# Explore the data
print("Dataset shape:", df.shape)
print("\nFirst 5 rows:")
print(df.head())
print("\nData types:")
print(df.dtypes)
print("\nBasic statistics:")
print(df.describe())
print("\nUnique continents:", df["continent"].unique())
print("\nRows per continent:")
print(df["continent"].value_counts())
print("\nMissing values:")
print(df.isnull().sum())

You've loaded 3,313 rows of real-world data and already spotted a quality issue hiding in it. Next up, you'll turn this data into a line chart that makes 55 years of global health trends visible at a glance.

Visualize Life Expectancy by Continent

In the previous step, you loaded the Gapminder dataset and explored its structure. You discovered 6 continent values including a suspicious "FSU" label.

The fastest way to spot patterns in data is to chart it. In this step, you will group the data by continent and year, compute average life expectancy, and plot a line chart. The result will reveal a data quality problem hiding in plain sight.

In this step, get ready to:
  • Filter the dataset to consistent 5-year intervals so every country has comparable data points.
  • Group data by continent and year and calculate average life expectancy.
  • Plot a multi-line chart and discover a continent that should not exist.
Filter the data to standard 5-year intervals

The dataset has uneven year coverage. Some countries report data annually while others report every 5 years. Filtering to the standard 5-year intervals (1952, 1957, ..., 2007) ensures every country contributes one data point per interval, making cross-country comparisons fair.

  • In analysis.py, add the following code at the bottom of your file (below the print(df.isnull().sum()) line):
# Filter to standard 5-year intervals
standard_years = [1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987, 1992, 1997, 2002, 2007]
df_filtered = df[df["year"].isin(standard_years)]

What does this code do?

standard_years is a list of every 5th year from 1952 to 2007.

df[df["year"].isin(standard_years)] keeps only rows where the year column matches one of those values. The result, stored in df_filtered, is a smaller, consistent slice of the data that you will use for all your charts.

Group by continent and year, then plot the chart

To see life expectancy trends over time, you need one average value per continent per year. The groupby method in pandas does exactly this. Then matplotlib draws a line for each continent.

  • Add the following visualization code directly below the filtering code you just wrote:
# Visualization 1: Life expectancy by continent over time
continent_avg = df_filtered.groupby(["continent", "year"])["lifeExp"].mean().reset_index()

plt.figure(figsize=(10, 6))
for continent in continent_avg["continent"].unique():
    data = continent_avg[continent_avg["continent"] == continent]
    plt.plot(data["year"], data["lifeExp"], marker="o", label=continent)

plt.xlabel("Year")
plt.ylabel("Life Expectancy (years)")
plt.title("Average Life Expectancy by Continent (1952-2007)")
plt.legend()
plt.tight_layout()
plt.show()

What does this code do?

  • groupby(["continent", "year"])["lifeExp"].mean() groups all countries by continent and year, then computes the average life expectancy for each group.
  • reset_index() converts the grouped result back into a flat DataFrame so you can loop through it easily.
  • The for loop draws one line per continent using plt.plot() with circle markers and a label for the legend.
  • plt.tight_layout() prevents labels from being cut off at the edges.
  • plt.show() opens a window displaying the chart. Your script pauses here until you close the chart window.

Chart window blocks your script

When plt.show() runs, a separate window opens with your chart. Your terminal will appear to "hang" because the script waits for you to close the chart window before it finishes. This is normal. Close the chart window when you are done examining it and the script will complete.

  • Save analysis.py.

Before you run the script, think about this: how many lines do you expect to see on the chart? You know there are 5 real continents (Africa, Americas, Asia, Europe, Oceania). Do you think that is what you will get?

  • Run the script by executing this command:
python analysis.py

A chart window opens showing 6 lines, not 5. "FSU" appears as its own continent alongside the real ones.

This is the data quality problem in action. Countries from the Former Soviet Union are labeled with continent "FSU" instead of their geographic continent (Europe or Asia). Your chart is technically correct given the data, but it is misleading because "FSU" is not a real continent.

  • Close the chart window to let the script finish.

Don't see a chart window?

  • Make sure you saved analysis.py before running.
  • Check that your plt.show() line is not indented inside the for loop. It should be at the same indentation level as plt.xlabel().
  • If the window opens and closes instantly, your system may be running in interactive mode. Try running from the VS Code terminal rather than a separate terminal app.

Why isn't my matplotlib chart showing up?

✔️ Awesome, I've got everything!

Great. Double check you have saved analysis.py and that the chart showed 6 continent lines including FSU.

ⓧ I'd like to double check the full code

Here is what your complete analysis.py should look like at this point:

import pandas as pd
import matplotlib.pyplot as plt

# Load the dataset
url = "https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv"
df = pd.read_csv(url)

# Explore the data
print("Dataset shape:", df.shape)
print("\nFirst 5 rows:")
print(df.head())
print("\nData types:")
print(df.dtypes)
print("\nBasic statistics:")
print(df.describe())
print("\nUnique continents:", df["continent"].unique())
print("\nRows per continent:")
print(df["continent"].value_counts())
print("\nMissing values:")
print(df.isnull().sum())
# Filter to standard 5-year intervals
standard_years = [1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987, 1992, 1997, 2002, 2007]
df_filtered = df[df["year"].isin(standard_years)]

# Visualization 1: Life expectancy by continent over time
continent_avg = df_filtered.groupby(["continent", "year"])["lifeExp"].mean().reset_index()

plt.figure(figsize=(10, 6))
for continent in continent_avg["continent"].unique():
    data = continent_avg[continent_avg["continent"] == continent]
    plt.plot(data["year"], data["lifeExp"], marker="o", label=continent)

plt.xlabel("Year")
plt.ylabel("Life Expectancy (years)")
plt.title("Average Life Expectancy by Continent (1952-2007)")
plt.legend()
plt.tight_layout()
plt.show()

Your chart works, but it is telling a misleading story. In the next step, you will clean the data by mapping FSU countries to their real geographic continents, then regenerate the chart with 5 clean lines.

Clean the Data and Fix the Chart

Your line chart from the previous step revealed something odd. "FSU" appeared as its own continent alongside Africa, Americas, Asia, Europe, and Oceania.

Those 14 FSU countries are real places (Russia, Ukraine, Estonia, and more) that belong to Europe or Asia geographically. The raw data labels them as "FSU" (Former Soviet Union), which is a political grouping, not a continent. Fixing inconsistent categories like this is the most common real-world data cleaning task.

In this step, get ready to:
  • Create a mapping that reassigns FSU countries to their correct continents.
  • Fix the line chart so it shows exactly 5 real continents.
  • Save the corrected chart as a PNG file.
Map FSU countries to their geographic continents

Each of the 14 FSU countries belongs to either Europe or Asia based on its geographic location. You will create a dictionary that maps each country name to its correct continent, then apply that mapping to every matching row in the DataFrame.

  • In analysis.py, find the line that says # Filter to standard 5-year intervals.
  • Add the following code directly above that line:
# Clean the data: map FSU countries to geographic continents
fsu_to_continent = {
    "Armenia": "Asia",
    "Azerbaijan": "Asia",
    "Belarus": "Europe",
    "Estonia": "Europe",
    "Georgia": "Asia",
    "Kazakhstan": "Asia",
    "Latvia": "Europe",
    "Lithuania": "Europe",
    "Moldova": "Europe",
    "Russia": "Europe",
    "Tajikistan": "Asia",
    "Turkmenistan": "Asia",
    "Ukraine": "Europe",
    "Uzbekistan": "Asia",
}

mask = df["country"].isin(fsu_to_continent.keys())
df.loc[mask, "continent"] = df.loc[mask, "country"].map(fsu_to_continent)

What does this code do?

The dictionary fsu_to_continent maps each FSU country name to either "Europe" or "Asia" based on where it sits geographically.

The mask line creates a True/False filter that selects only rows where the country name appears in the dictionary. Then df.loc[mask, "continent"] overwrites the "continent" column for those rows with the correct value from the dictionary.

  • Now find the line that says df_filtered = df[df["year"].isin(standard_years)] and add this print statement directly below it:
print(f"\nCleaned dataset: {df_filtered.shape[0]} rows across {df_filtered['continent'].nunique()} continents")

What does this print confirm?

This line reports how many rows remain after filtering and how many unique continents exist. If the cleaning worked, you should see 5 continents instead of 6.

  • Save analysis.py.
  • Run the script to see whether the cleaning worked:
python analysis.py

The chart that appears should now have exactly 5 lines, one for each real continent (Africa, Americas, Asia, Europe, Oceania). The "FSU" line is gone.

In your terminal output, look for the new confirmation line. It should read something like Cleaned dataset: 2436 rows across 5 continents.

Still seeing 6 lines on the chart?

  • Make sure the cleaning code is placed above the # Filter to standard 5-year intervals line. If it runs after filtering, the FSU rows are already in df_filtered uncleaned.
  • Check that df.loc[mask, "continent"] uses df.loc (not df_filtered.loc). The cleaning must happen on the original DataFrame before filtering.

Why is my chart still showing FSU after cleaning?

Save the chart as a PNG file

Your chart looks correct on screen, but it disappears when you close the window. Saving it as a PNG means you can share it or include it in a portfolio without re-running the script.

  • In analysis.py, find this line near the bottom:
plt.show()
  • Replace it with these three lines so the chart is saved to disk before it displays, and a confirmation prints afterward:
plt.savefig("life_expectancy_by_continent.png", dpi=150)
plt.show()
print("Saved: life_expectancy_by_continent.png")

Why does savefig come before show?

Calling plt.show() renders the figure and clears it from memory. If you call plt.savefig() after that, you get a blank file. Always save first, then show.

The dpi=150 setting creates a crisp image suitable for sharing. The default (100 dpi) looks blurry on high-resolution screens.

  • Save analysis.py.

Before you run the script again, what do you expect to see differently this time compared to the last run?

  • Run the script to confirm the chart saves:
python analysis.py

The chart still shows 5 continents (same as before). But now your terminal also prints Saved: life_expectancy_by_continent.png after you close the chart window.

  • Confirm the PNG file was created by running:
ls *.png

You should see life_expectancy_by_continent.png listed in the output.

Don't see the PNG file?

  • Make sure plt.savefig("life_expectancy_by_continent.png", dpi=150) appears before plt.show(), not after. Saving after show produces a blank file.
  • Check that your terminal is in the same folder as analysis.py. The PNG saves to whichever directory the script runs from.

Help me figure out why my PNG file is missing or blank after running analysis.py.

✔️ Awesome, I've got everything!

Great. Double check you have saved analysis.py and that life_expectancy_by_continent.png appears when you run ls *.png.

ⓧ I'd like to double check the full code

Your analysis.py should now have these sections in this exact order. Scroll through your file and confirm each one is present:

  • Imports (import pandas as pd and import matplotlib.pyplot as plt).
  • Load the dataset (pd.read_csv(url)).
  • Explore the data (all the print() statements for shape, head, dtypes, describe, unique continents, value_counts, isnull).
  • Clean the data (fsu_to_continent dictionary, mask, and df.loc[mask, "continent"] assignment).
  • Filter to standard 5-year intervals (standard_years list and df_filtered).
  • Print cleaned dataset confirmation (print(f"\nCleaned dataset: ...")).
  • Visualization 1 (groupby, plt.figure, loop with plt.plot, labels, savefig, show, print).

Your chart is clean and saved. Next up, you will build a scatter plot that reveals the relationship between a country's wealth and the life expectancy of its citizens.

Create a Wealth vs Health Scatter Plot

Your line chart revealed trends over time, showing how life expectancy improved across continents over 55 years. Now you'll ask a different kind of question: do richer countries have healthier citizens?

A scatter plot reveals relationships between two variables at once. By plotting GDP per capita against life expectancy for the year 2007, you'll see whether wealth and health are connected across 100+ countries.

In this step, get ready to:
  • Filter your cleaned dataset to the most recent year (2007).
  • Plot GDP per capita vs life expectancy as colored scatter dots by continent.
  • Save the scatter plot as a PNG file.
Filter the data and set up the scatter plot

Your dataset spans 1952 to 2007, but a scatter plot works best as a snapshot of one moment in time. You'll filter to just 2007, the most recent year, and define a color for each continent so the chart is readable at a glance.

  • In analysis.py, scroll to the bottom of the file (after the print("Saved: life_expectancy_by_continent.png") line).
  • Add this code to filter to 2007 and define your continent colors:
# Visualization 2: Wealth vs health scatter plot (2007)
df_2007 = df_filtered[df_filtered["year"] == 2007]

plt.figure(figsize=(10, 6))
colors = {
    "Africa": "brown",
    "Americas": "green",
    "Asia": "red",
    "Europe": "blue",
    "Oceania": "purple",
}

What does this code do?

df_filtered[df_filtered["year"] == 2007] creates a new DataFrame containing only the 2007 rows. This gives you one data point per country for the scatter plot.

The colors dictionary maps each continent to a specific color. You'll loop through this dictionary to plot each continent separately, so they appear as distinct groups on the chart.

  • Save analysis.py.
Plot each continent as colored scatter dots

Now you'll loop through each continent, grab its subset of countries, and plot them as dots on the chart. You'll also apply a logarithmic scale to the x-axis because GDP values range from a few hundred to over 50,000 dollars.

  • Add this code directly below the colors dictionary in analysis.py:
for continent in colors:
    subset = df_2007[df_2007["continent"] == continent]
    plt.scatter(
        subset["gdpPercap"],
        subset["lifeExp"],
        label=continent,
        color=colors[continent],
        alpha=0.7,
    )

plt.xscale("log")
plt.xlabel("GDP per Capita (USD, log scale)")
plt.ylabel("Life Expectancy (years)")
plt.title("Wealth vs Health in 2007")
plt.legend()
plt.tight_layout()
plt.savefig("wealth_vs_health_2007.png", dpi=150)
plt.show()
print("Saved: wealth_vs_health_2007.png")

What does this code do?

  • The for continent in colors: loop iterates through all 5 continents. For each one, it filters df_2007 to just that continent's countries and calls plt.scatter().
  • alpha=0.7 makes dots slightly transparent so overlapping countries are still visible.
  • plt.xscale("log") switches the x-axis to a logarithmic scale. Without this, most countries would be crammed to the left because a few very rich countries stretch the axis.
  • plt.savefig("wealth_vs_health_2007.png", dpi=150) saves the chart as a PNG file before plt.show() displays it.

Why use a log scale?

GDP per capita ranges from under $1,000 to over $50,000. On a linear scale, poor countries would be bunched into a tiny sliver on the left. A log scale spreads out low values and compresses high values, making patterns visible across the full range.

Before you run this, think: if wealthier countries truly have higher life expectancy, what shape would you expect the dots to form on the chart?

  • Save analysis.py.
  • Run the script in your terminal:
python analysis.py

You'll see the life expectancy line chart appear first (close it to continue). Then the scatter plot appears with colored dots by continent, a logarithmic x-axis, and a clear upward trend from left to right.

Notice how rich countries (right side) generally have higher life expectancy, but the pattern differs by continent. African countries cluster lower even at similar GDP levels.

  • Confirm that wealth_vs_health_2007.png was saved by running:
ls

You should see both life_expectancy_by_continent.png and wealth_vs_health_2007.png listed alongside analysis.py.

Chart window not appearing?

  • On Windows, the chart opens in a separate window. Check your taskbar for a Python or matplotlib window.
  • Make sure you close the first chart (the line chart) by clicking the X on its window. The scatter plot only appears after the first chart is closed.
  • If you see a NameError mentioning colors or df_2007, check that you pasted the filter and dictionary code above the loop.

Help me debug my scatter plot code.

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

Your analysis.py is now quite long. Scroll through your file and confirm these sections are present in order:

  • Imports (pandas and matplotlib).
  • Load the dataset from the URL.
  • Explore the data (shape, head, dtypes, describe, unique continents, value_counts, isnull).
  • Clean the data: fsu_to_continent dictionary and the mapping logic.
  • Filter to standard_years and print cleaned dataset stats.
  • Visualization 1: the life expectancy line chart (groupby, loop, savefig, show).
  • Visualization 2: filter to 2007, colors dictionary, scatter loop, log scale, savefig, show.

You now have two publication-quality charts saved as PNG files. Your line chart showed trends over time, and your scatter plot reveals the wealth-health connection in a single snapshot. Next up, the Secret Mission takes this further with a famous visualization technique.

Secret mission

Build the Hans Rosling Bubble Chart

Your scatter plot shows wealth vs health, but it treats every country the same size. The famous Gapminder bubble chart adds a third dimension: population. China and India become giant bubbles while small nations shrink to dots, revealing the world's story in a single image.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your files for future reference, or delete them to tidy up your machine.

Resources you used:

  • analysis.py - your data analysis script (local file, no cost).
  • life_expectancy_by_continent.png - line chart image (local file).
  • wealth_vs_health_2007.png - scatter plot image (local file).
  • bubble_chart_2007.png - bubble chart image, if you completed the Secret Mission (local file).
  • pandas and matplotlib Python packages (installed via pip).

Keep everything running

No action needed. Choose this if you plan to keep experimenting with your analysis script or want to reuse the charts.

  • Your files stay where they are.
  • pandas and matplotlib remain installed and available for future Python projects.

Pause - I'll come back to this later

Since everything is local, there is nothing to pause. Your files and packages will be waiting for you when you return.

  • Close VS Code when you are done.
  • Your script and chart files remain on disk, ready to run again anytime.

Delete - I don't want to use this again

Remove all project files and uninstall the Python packages to start fresh.

  • Delete the project files by running this command in your VS Code terminal (from the same directory where your files live):

macOS

rm analysis.py life_expectancy_by_continent.png wealth_vs_health_2007.png bubble_chart_2007.png

Windows

del analysis.py, life_expectancy_by_continent.png, wealth_vs_health_2007.png, bubble_chart_2007.png
  • Uninstall the Python packages by running:
pip uninstall pandas matplotlib -y
  • Confirm the files are gone by running ls (macOS) or dir (Windows) in the same directory. You should no longer see analysis.py or any .png chart files.

Nice Work!

Nice Work!

You just built a complete data analysis pipeline that transforms raw global development data into publication-quality visualizations. From loading a CSV to producing charts that reveal 55 years of human progress, you now have a repeatable workflow for turning data into insight.

You've learned how to:

  • Discover and fix a real data quality issue (the FSU mislabeling) using dictionary mapping in pandas, the most common cleaning task in professional analytics.
  • Create a multi-line time-series chart showing life expectancy trends across 5 continents from 1952 to 2007 using groupby aggregations and matplotlib.
  • Build a scatter plot with a logarithmic scale revealing the relationship between a country's wealth and its citizens' lifespan.
  • Secret Mission: You recreated the famous Hans Rosling bubble chart with population-scaled markers, adding a third data dimension to a single visualization.

Ready to quiz yourself?