ME204 2026 Icon

💻 Week 02, Day 04 - Lab

Nested JSON with PokéAPI

Author

Dr Jon Cardoso-Silva

Last updated

23 July 2026

🥅 Learning Objectives

By the end of this lab, you should be able to: i) Run named functions that collect JSON and images, and notice how nice it is to know what a function does from its name, ii) Build one row of key fields for a Pokémon, wrap that step in a function, and join several Pokémon with pd.concat, iii) Flatten nested stats with pd.json_normalize the same way across the batch, iv) Move those functions into utils.py and import them after a kernel restart.

Thursday, 23 July 2026 | Check your timetable for your class time 📍 Check your timetable for the location of your class

This afternoon let’s practice writing functions and using pd.json_normalize to reshape JSON from a new API: PokéAPI (no API key needed).

Pikachu Gengar Eevee Squirtle Charmander

🛣️ Lab Roadmap

Part Time What you do
Part I ~25 min Collect JSON and images
Part II ~25 min One row of key fields, a function, then join the batch into a CSV
Part III ~25 min Flatten stats the same way across the batch
Part IV Remaining Move functions into utils.py, restart, import

Before you start

Open the starter notebook ME204_W02D04_Lab.ipynb in VS Code on Nuvolos (or your local copy of the course materials).

Work with the notebook folder as your working directory so data/ is created next to the notebook, then run the imports cell at the top before Part I.

Part I: Collect JSON and images

Collect one JSON file and one image per name in the batch under data/.

🎯 Action points

  1. Run collect_pokemon("pikachu"), then the loop over POKEMON_BATCH, and confirm you get one .json file per name under data/.

  2. Run download_pokemon_images the same way. You do not need to study the body of that function. Even if you skip reading the code inside it, that is a good name, isn’t it? Just notice how nice it is to know what a function does just by reading its name!

  3. List the PNGs under data/images/, display Pikachu, then open data/pikachu.json in the editor and scroll it as plain text before you reshape anything.

Part II: One row of key fields, then many

Start from the pokemon dict for Pikachu and end with data/pokemon_rows.csv (one row per Pokémon in the batch).

Try each step yourself first. Your class teacher will show or share a solution when the room is ready.

🎯 Action points

  1. Build pokemon_row for Pikachu with id, name, height, weight, and base_experience. Match the preview table in the notebook.

  2. Write pokemon_row_from_file(path) so one saved JSON file becomes that same table with a single row.

  3. Build pokemon_rows for the whole batch (one row per Pokémon), match the preview in the notebook, and write data/pokemon_rows.csv.

Part III: Stats for one Pokémon, then many

Flatten pokemon["stats"] with this morning’s pd.json_normalize pattern, then do the same for the whole batch.

Try each step yourself first. Your class teacher will show or share a solution when the room is ready.

🎯 Action points

  1. Turn pokemon["stats"] into a DataFrame named stats that matches the preview in the notebook.

  2. Write stats_from_file(path) that does the same for one saved JSON file.

  3. Build stats_all for every Pokémon in the batch. Optional: mean base_stat by Pokémon name with .groupby.

Part IV: A small utils.py

Move collect_pokemon, pokemon_row_from_file, stats_from_file, and download_pokemon_images into utils.py next to the notebook, restart the kernel, and import them.

🎯 Action points

  1. Create utils.py in the same folder as the notebook (not inside data/).

  2. Move into it: collect_pokemon, pokemon_row_from_file, stats_from_file, and download_pokemon_images, plus the imports and constants they need (DATA_DIR, IMAGES_DIR, BASE_URL).

  3. Save, then choose Kernel → Restart Kernel and Clear Outputs of All Cells.

  4. Run a fresh cell that imports from utils and call one function to prove it worked. Your cell should look like this:

from utils import (
    DATA_DIR,
    IMAGES_DIR,
    collect_pokemon,
    download_pokemon_images,
    pokemon_row_from_file,
    stats_from_file,
)

collect_pokemon("pikachu")

New tool: importing from a neighbouring .py file. from utils import collect_pokemon means “open utils.py and bring that name into this notebook.” Without a restart, Python may keep using the old function objects from earlier cells even after those cells are gone.

Closing

Before you leave: JSON under data/, images under data/images/, pokemon_rows.csv, a joined stats table in the notebook, and a working import from utils.py.

If the import step fails, ask your class teacher before you leave. The usual causes are utils.py in the wrong folder, a missing save, or skipping the kernel restart.