In [19]:
import pandas as pd
import matplotlib.pyplot as plt

# Load the data from Google Sheets
url = 'https://docs.google.com/spreadsheets/d/1yhcZ3klzIASrM4EEhBsI2KbhYd7pzcUEkSj7ZoNoWMU/export?format=csv'
df = pd.read_csv(url)

# Clean column names
df.columns = df.columns.str.replace('\n', '')

# Lists to store information for each generation
regions = ['Kanto', 'Johto', 'Hoenn', 'Sinnoh', 'Unova', 'Kalos', 'Alola', 'Galar', 'Paldea']
generation_starts = [1, 152, 252, 387, 494, 650, 722, 810, 906]
generation_ends = [151, 251, 386, 493, 649, 721, 809, 905, 1008]

# Lists to store our results
avg_heights = []
pokemon_counts = []
tallest_names = []
tallest_heights = []
shortest_names = []
shortest_heights = []

# Go through each generation
for i in range(9):
    gen_num = i + 1
    start = generation_starts[i]
    end = generation_ends[i]
    
    # Find all pokemon in this generation
    gen_pokemon = df[(df['NationalDex'] >= start) & (df['NationalDex'] <= end)]
    
    # Count pokemon
    count = len(gen_pokemon)
    pokemon_counts.append(count)
    
    # Calculate average height
    heights = gen_pokemon['Height (m)'].dropna()  # Remove missing values
    if len(heights) > 0:
        avg = heights.mean()
        avg_heights.append(avg)
        
        # Find tallest pokemon
        max_height = heights.max()
        tallest_row = gen_pokemon[gen_pokemon['Height (m)'] == max_height].iloc[0]
        tallest_names.append(tallest_row['PokemonName'])
        tallest_heights.append(max_height)
        
        # Find shortest pokemon
        min_height = heights.min()
        shortest_row = gen_pokemon[gen_pokemon['Height (m)'] == min_height].iloc[0]
        shortest_names.append(shortest_row['PokemonName'])
        shortest_heights.append(min_height)
    else:
        avg_heights.append(0)
        tallest_names.append("None")
        tallest_heights.append(0)
        shortest_names.append("None")
        shortest_heights.append(0)

# Find the top 5 tallest and shortest Pokemon overall
# Remove rows with missing heights
df_with_heights = df.dropna(subset=['Height (m)'])

# Sort by height to get tallest
df_sorted_tall = df_with_heights.sort_values('Height (m)', ascending=False)
top_5_tallest = df_sorted_tall.head(5)

# Sort by height to get shortest
df_sorted_short = df_with_heights.sort_values('Height (m)', ascending=True)
top_5_shortest = df_sorted_short.head(5)

# Function to find which generation a Pokemon is from
def find_generation(dex_num):
    for i in range(9):
        if generation_starts[i] <= dex_num <= generation_ends[i]:
            return i + 1
    return 0

# Calculate overall statistics
all_heights = df['Height (m)'].dropna()
overall_avg = all_heights.mean()

# Print overall statistics
print("=" * 60)
print("TOP 5 TALLEST POKEMON ACROSS ALL GENERATIONS")
print("=" * 60)
rank = 1
for index, pokemon in top_5_tallest.iterrows():
    gen = find_generation(pokemon['NationalDex'])
    print(f"\n#{rank}: {pokemon['PokemonName']}")
    print(f"  Height: {pokemon['Height (m)']}m")
    print(f"  National Dex #: {int(pokemon['NationalDex'])}")
    print(f"  Generation: {gen} ({regions[gen-1]})")
    rank += 1

print("\n" + "=" * 60)
print("TOP 5 SHORTEST POKEMON ACROSS ALL GENERATIONS")
print("=" * 60)
rank = 1
for index, pokemon in top_5_shortest.iterrows():
    gen = find_generation(pokemon['NationalDex'])
    print(f"\n#{rank}: {pokemon['PokemonName']}")
    print(f"  Height: {pokemon['Height (m)']}m")
    print(f"  National Dex #: {int(pokemon['NationalDex'])}")
    print(f"  Generation: {gen} ({regions[gen-1]})")
    rank += 1

print(f"\n" + "=" * 60)
print("OVERALL STATISTICS")
print("=" * 60)
print(f"Overall Average Height: {overall_avg:.2f}m")
print(f"Total Pokemon with Height Data: {len(all_heights)}")
height_difference = top_5_tallest.iloc[0]['Height (m)'] - top_5_shortest.iloc[0]['Height (m)']
print(f"Height difference between tallest and shortest: {height_difference:.2f}m")
print(f"The tallest Pokemon is {top_5_tallest.iloc[0]['Height (m)']/top_5_shortest.iloc[0]['Height (m)']:.1f}x taller than the shortest!")

# Print the results by generation
print("\n" + "=" * 60)
print("GENERATION-BY-GENERATION ANALYSIS")
print("=" * 60)
for i in range(9):
    print(f"\nGeneration {i+1} ({regions[i]}):")
    print(f"Number of Pokemon: {pokemon_counts[i]}")
    print(f"Average Height: {avg_heights[i]:.2f}m")
    print(f"Tallest: {tallest_names[i]} ({tallest_heights[i]}m)")
    print(f"Shortest: {shortest_names[i]} ({shortest_heights[i]}m)")

# Make a bar chart
plt.figure(figsize=(12, 8))

plt.subplot(2, 1, 1)
generations = list(range(1, 10))
bars = plt.bar(generations, avg_heights)
plt.title('Average Pokemon Height by Generation')
plt.xlabel('Generation')
plt.ylabel('Average Height (meters)')

# Add a horizontal line for overall average
plt.axhline(y=overall_avg, color='red', linestyle='--', 
            label=f'Overall Average: {overall_avg:.2f}m')
plt.legend()

# Add labels on the bars
for i, bar in enumerate(bars):
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width()/2, height,
             f'{height:.2f}m', ha='center', va='bottom')

# Count pokemon by size
# tiny: 0-1m, small: 1-2m, medium: 2-4m, large: 4-8m, huge: 8m+
plt.subplot(2, 1, 2)

# Lists for each size category
tiny_counts = []
small_counts = []
medium_counts = []
large_counts = []
huge_counts = []

for i in range(9):
    start = generation_starts[i]
    end = generation_ends[i]
    
    # Get pokemon for this generation
    gen_pokemon = df[(df['NationalDex'] >= start) & (df['NationalDex'] <= end)]
    
    # Count pokemon in each size category
    tiny = len(gen_pokemon[(gen_pokemon['Height (m)'] >= 0) & (gen_pokemon['Height (m)'] < 1)])
    small = len(gen_pokemon[(gen_pokemon['Height (m)'] >= 1) & (gen_pokemon['Height (m)'] < 2)])
    medium = len(gen_pokemon[(gen_pokemon['Height (m)'] >= 2) & (gen_pokemon['Height (m)'] < 4)])
    large = len(gen_pokemon[(gen_pokemon['Height (m)'] >= 4) & (gen_pokemon['Height (m)'] < 8)])
    huge = len(gen_pokemon[gen_pokemon['Height (m)'] >= 8])
    
    tiny_counts.append(tiny)
    small_counts.append(small)
    medium_counts.append(medium)
    large_counts.append(large)
    huge_counts.append(huge)

# Make stacked bar chart
width = 0.8
plt.bar(generations, tiny_counts, width, label='tiny')
plt.bar(generations, small_counts, width, bottom=tiny_counts, label='small')

# Calculate bottoms for stacking
bottom_for_medium = [tiny_counts[i] + small_counts[i] for i in range(9)]
plt.bar(generations, medium_counts, width, bottom=bottom_for_medium, label='medium')

bottom_for_large = [bottom_for_medium[i] + medium_counts[i] for i in range(9)]
plt.bar(generations, large_counts, width, bottom=bottom_for_large, label='large')

bottom_for_huge = [bottom_for_large[i] + large_counts[i] for i in range(9)]
plt.bar(generations, huge_counts, width, bottom=bottom_for_huge, label='huge')

plt.title('Pokemon Size Distribution by Generation')
plt.xlabel('Generation')
plt.ylabel('Number of Pokemon')
plt.legend()

plt.tight_layout()
plt.show()

# Print size distribution percentages
print("\n" + "=" * 60)
print("HEIGHT DISTRIBUTION STATISTICS")
print("=" * 60)
size_names = ['Tiny (0-1m)', 'Small (1-2m)', 'Medium (2-4m)', 'Large (4-8m)', 'Huge (8m+)']
all_counts = [tiny_counts, small_counts, medium_counts, large_counts, huge_counts]

for j, size_name in enumerate(size_names):
    print(f"\n{size_name}:")
    for i in range(9):
        count = all_counts[j][i]
        total = pokemon_counts[i]
        if total > 0:
            percentage = (count / total) * 100
        else:
            percentage = 0
        print(f"Gen {i+1}: {count} Pokemon ({percentage:.1f}%)")

# Print fun facts at the end
print("\n" + "=" * 60)
print("FUN HEIGHT FACTS")
print("=" * 60)

# Find which generation has the most giants and tiny Pokemon
max_huge = max(huge_counts)
max_tiny = max(tiny_counts)
gen_with_most_huge = huge_counts.index(max_huge) + 1
gen_with_most_tiny = tiny_counts.index(max_tiny) + 1

print(f"Generation with most huge Pokemon (8m+): Gen {gen_with_most_huge} with {max_huge} Pokemon")
print(f"Generation with most tiny Pokemon (0-1m): Gen {gen_with_most_tiny} with {max_tiny} Pokemon")

# Find how many Pokemon are taller than average
taller_than_avg = len(df[df['Height (m)'] > overall_avg])
shorter_than_avg = len(df[df['Height (m)'] < overall_avg])
print(f"\nPokemon taller than average ({overall_avg:.2f}m): {taller_than_avg}")
print(f"Pokemon shorter than average: {shorter_than_avg}")
============================================================
TOP 5 TALLEST POKEMON ACROSS ALL GENERATIONS
============================================================

#1: Eternatus
  Height: 20.0m
  National Dex #: 890
  Generation: 8 (Galar)

#2: Wailord
  Height: 14.5m
  National Dex #: 321
  Generation: 3 (Hoenn)

#3: Dondozo
  Height: 12.0m
  National Dex #: 977
  Generation: 9 (Paldea)

#4: Exeggutor (Alolan)
  Height: 10.9m
  National Dex #: 103
  Generation: 1 (Kanto)

#5: Steelix (Mega)
  Height: 10.5m
  National Dex #: 208
  Generation: 2 (Johto)

============================================================
TOP 5 SHORTEST POKEMON ACROSS ALL GENERATIONS
============================================================

#1: Ash-Greninja
  Height: 0.0m
  National Dex #: 658
  Generation: 6 (Kalos)

#2: Gimmighoul (Roaming)
  Height: 0.1m
  National Dex #: 999
  Generation: 9 (Paldea)

#3: Comfey
  Height: 0.1m
  National Dex #: 764
  Generation: 7 (Alola)

#4: Flabébé
  Height: 0.1m
  National Dex #: 669
  Generation: 6 (Kalos)

#5: Cutiefly
  Height: 0.1m
  National Dex #: 742
  Generation: 7 (Alola)

============================================================
OVERALL STATISTICS
============================================================
Overall Average Height: 1.28m
Total Pokemon with Height Data: 1214
Height difference between tallest and shortest: 20.00m
The tallest Pokemon is infx taller than the shortest!

============================================================
GENERATION-BY-GENERATION ANALYSIS
============================================================

Generation 1 (Kanto):
Number of Pokemon: 202
Average Height: 1.30m
Tallest: Exeggutor (Alolan) (10.9m)
Shortest: Diglett (0.2m)

Generation 2 (Johto):
Number of Pokemon: 112
Average Height: 1.27m
Tallest: Steelix (Mega) (10.5m)
Shortest: Natu (0.2m)

Generation 3 (Hoenn):
Number of Pokemon: 162
Average Height: 1.37m
Tallest: Wailord (14.5m)
Shortest: Azurill (0.2m)

Generation 4 (Sinnoh):
Number of Pokemon: 128
Average Height: 1.21m
Tallest: Dialga (Origin) (7.0m)
Shortest: Budew (0.2m)

Generation 5 (Unova):
Number of Pokemon: 179
Average Height: 1.08m
Tallest: Kyurem (White) (3.6m)
Shortest: Joltik (0.1m)

Generation 6 (Kalos):
Number of Pokemon: 96
Average Height: 1.16m
Tallest: Hoopa (Unbound) (6.5m)
Shortest: Ash-Greninja (0.0m)

Generation 7 (Alola):
Number of Pokemon: 107
Average Height: 1.42m
Tallest: Celesteela (9.2m)
Shortest: Cutiefly (0.1m)

Generation 8 (Galar):
Number of Pokemon: 111
Average Height: 1.44m
Tallest: Eternatus (20.0m)
Shortest: Sinistea (0.1m)

Generation 9 (Paldea):
Number of Pokemon: 113
Average Height: 1.29m
Tallest: Dondozo (12.0m)
Shortest: Gimmighoul (Roaming) (0.1m)
C:\Users\Tony\AppData\Local\Temp\ipykernel_16212\2101290192.py:116: RuntimeWarning: divide by zero encountered in scalar divide
  print(f"The tallest Pokemon is {top_5_tallest.iloc[0]['Height (m)']/top_5_shortest.iloc[0]['Height (m)']:.1f}x taller than the shortest!")
No description has been provided for this image
============================================================
HEIGHT DISTRIBUTION STATISTICS
============================================================

Tiny (0-1m):
Gen 1: 73 Pokemon (36.1%)
Gen 2: 56 Pokemon (50.0%)
Gen 3: 73 Pokemon (45.1%)
Gen 4: 66 Pokemon (51.6%)
Gen 5: 84 Pokemon (46.9%)
Gen 6: 48 Pokemon (50.0%)
Gen 7: 57 Pokemon (53.3%)
Gen 8: 51 Pokemon (45.9%)
Gen 9: 51 Pokemon (45.1%)

Small (1-2m):
Gen 1: 105 Pokemon (52.0%)
Gen 2: 44 Pokemon (39.3%)
Gen 3: 67 Pokemon (41.4%)
Gen 4: 45 Pokemon (35.2%)
Gen 5: 81 Pokemon (45.3%)
Gen 6: 38 Pokemon (39.6%)
Gen 7: 28 Pokemon (26.2%)
Gen 8: 32 Pokemon (28.8%)
Gen 9: 44 Pokemon (38.9%)

Medium (2-4m):
Gen 1: 19 Pokemon (9.4%)
Gen 2: 9 Pokemon (8.0%)
Gen 3: 15 Pokemon (9.3%)
Gen 4: 11 Pokemon (8.6%)
Gen 5: 14 Pokemon (7.8%)
Gen 6: 6 Pokemon (6.2%)
Gen 7: 15 Pokemon (14.0%)
Gen 8: 27 Pokemon (24.3%)
Gen 9: 15 Pokemon (13.3%)

Large (4-8m):
Gen 1: 3 Pokemon (1.5%)
Gen 2: 1 Pokemon (0.9%)
Gen 3: 5 Pokemon (3.1%)
Gen 4: 6 Pokemon (4.7%)
Gen 5: 0 Pokemon (0.0%)
Gen 6: 4 Pokemon (4.2%)
Gen 7: 5 Pokemon (4.7%)
Gen 8: 0 Pokemon (0.0%)
Gen 9: 2 Pokemon (1.8%)

Huge (8m+):
Gen 1: 2 Pokemon (1.0%)
Gen 2: 2 Pokemon (1.8%)
Gen 3: 2 Pokemon (1.2%)
Gen 4: 0 Pokemon (0.0%)
Gen 5: 0 Pokemon (0.0%)
Gen 6: 0 Pokemon (0.0%)
Gen 7: 2 Pokemon (1.9%)
Gen 8: 1 Pokemon (0.9%)
Gen 9: 1 Pokemon (0.9%)

============================================================
FUN HEIGHT FACTS
============================================================
Generation with most huge Pokemon (8m+): Gen 1 with 2 Pokemon
Generation with most tiny Pokemon (0-1m): Gen 5 with 84 Pokemon

Pokemon taller than average (1.28m): 453
Pokemon shorter than average: 761
In [18]:
# Lists to store type information
type_names = []
type_total_heights = []
type_counts = []
type_tallest_names = []
type_tallest_heights = []
type_shortest_names = []
type_shortest_heights = []

# Get all unique types
all_types = set()
for _, pokemon in df.iterrows():
    if pd.notna(pokemon['Type I']):
        all_types.add(pokemon['Type I'])
    if pd.notna(pokemon['Type II']):
        all_types.add(pokemon['Type II'])

# Convert to sorted list
all_types = sorted(list(all_types))

# Calculate stats for each type
for poke_type in all_types:
    heights_for_type = []
    names_for_type = []
    
    # Go through all Pokemon and find ones with this type
    for _, pokemon in df.iterrows():
        if pd.notna(pokemon['Height (m)']):
            # Check if this Pokemon has our type
            has_type = False
            if pd.notna(pokemon['Type I']) and pokemon['Type I'] == poke_type:
                has_type = True
            if pd.notna(pokemon['Type II']) and pokemon['Type II'] == poke_type:
                has_type = True
            
            if has_type:
                heights_for_type.append(pokemon['Height (m)'])
                names_for_type.append(pokemon['PokemonName'])
    
    # Calculate statistics for this type
    if len(heights_for_type) > 0:
        type_names.append(poke_type)
        type_counts.append(len(heights_for_type))
        
        # Average
        avg = sum(heights_for_type) / len(heights_for_type)
        type_total_heights.append(avg)
        
        # Find tallest
        max_height = max(heights_for_type)
        max_index = heights_for_type.index(max_height)
        type_tallest_names.append(names_for_type[max_index])
        type_tallest_heights.append(max_height)
        
        # Find shortest
        min_height = min(heights_for_type)
        min_index = heights_for_type.index(min_height)
        type_shortest_names.append(names_for_type[min_index])
        type_shortest_heights.append(min_height)

# Sort types by average height using bubble sort (beginner-friendly)
for i in range(len(type_names)):
    for j in range(0, len(type_names) - i - 1):
        if type_total_heights[j] > type_total_heights[j + 1]:
            # Swap all related lists
            type_names[j], type_names[j + 1] = type_names[j + 1], type_names[j]
            type_total_heights[j], type_total_heights[j + 1] = type_total_heights[j + 1], type_total_heights[j]
            type_counts[j], type_counts[j + 1] = type_counts[j + 1], type_counts[j]
            type_tallest_names[j], type_tallest_names[j + 1] = type_tallest_names[j + 1], type_tallest_names[j]
            type_tallest_heights[j], type_tallest_heights[j + 1] = type_tallest_heights[j + 1], type_tallest_heights[j]
            type_shortest_names[j], type_shortest_names[j + 1] = type_shortest_names[j + 1], type_shortest_names[j]
            type_shortest_heights[j], type_shortest_heights[j + 1] = type_shortest_heights[j + 1], type_shortest_heights[j]

# Print results
print("\n" + "=" * 80)
print("POKEMON TYPES SORTED BY AVERAGE HEIGHT (SHORTEST TO TALLEST)")
print("=" * 80)

for i in range(len(type_names)):
    print(f"\n{type_names[i]} Type:")
    print(f"  Average Height: {type_total_heights[i]:.2f}m")
    print(f"  Number of Pokemon: {type_counts[i]}")
    print(f"  Shortest: {type_shortest_names[i]} ({type_shortest_heights[i]:.2f}m)")
    print(f"  Tallest: {type_tallest_names[i]} ({type_tallest_heights[i]:.2f}m)")

# Create bar chart
plt.figure(figsize=(15, 8))
bars = plt.bar(type_names, type_total_heights)
plt.xticks(rotation=45, ha='right')
plt.title('Average Pokemon Height by Type')
plt.xlabel('Type')
plt.ylabel('Average Height (meters)')

# Add labels on bars
for i, bar in enumerate(bars):
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width()/2, height,
             f'{height:.2f}m', ha='center', va='bottom')

plt.tight_layout()
plt.show()
================================================================================
POKEMON TYPES SORTED BY AVERAGE HEIGHT (SHORTEST TO TALLEST)
================================================================================

Fairy Type:
  Average Height: 0.91m
  Number of Pokemon: 79
  Shortest: Flabébé (0.10m)
  Tallest: Weezing (Galarian) (3.00m)

Bug Type:
  Average Height: 0.94m
  Number of Pokemon: 108
  Shortest: Joltik (0.10m)
  Tallest: Slither Wing (3.20m)

Electric Type:
  Average Height: 1.02m
  Number of Pokemon: 85
  Shortest: Joltik (0.10m)
  Tallest: Xurkitree (3.80m)

Normal Type:
  Average Height: 1.03m
  Number of Pokemon: 151
  Shortest: Azurill (0.20m)
  Tallest: Dudunsparce (Three Segment) (4.50m)

Grass Type:
  Average Height: 1.03m
  Number of Pokemon: 141
  Shortest: Budew (0.20m)
  Tallest: Exeggutor (Alolan) (10.90m)

Rock Type:
  Average Height: 1.23m
  Number of Pokemon: 92
  Shortest: Dwebble (0.30m)
  Tallest: Onix (8.80m)

Fire Type:
  Average Height: 1.24m
  Number of Pokemon: 95
  Shortest: Castform (Sunny) (0.30m)
  Tallest: Groudon (Primal) (5.00m)

Flying Type:
  Average Height: 1.31m
  Number of Pokemon: 146
  Shortest: Natu (0.20m)
  Tallest: Celesteela (9.20m)

Ghost Type:
  Average Height: 1.34m
  Number of Pokemon: 84
  Shortest: Sinistea (0.10m)
  Tallest: Giratina (Origin) (6.90m)

Psychic Type:
  Average Height: 1.34m
  Number of Pokemon: 130
  Shortest: Cosmoem (0.10m)
  Tallest: Necrozma (Ultra) (7.50m)

Dark Type:
  Average Height: 1.36m
  Number of Pokemon: 89
  Shortest: Ash-Greninja (0.00m)
  Tallest: Gyarados (Mega) (6.50m)

Poison Type:
  Average Height: 1.36m
  Number of Pokemon: 91
  Shortest: Budew (0.20m)
  Tallest: Eternatus (20.00m)

Fighting Type:
  Average Height: 1.40m
  Number of Pokemon: 90
  Shortest: Pawmo (0.40m)
  Tallest: Slither Wing (3.20m)

Water Type:
  Average Height: 1.44m
  Number of Pokemon: 175
  Shortest: Ash-Greninja (0.00m)
  Tallest: Wailord (14.50m)

Ice Type:
  Average Height: 1.49m
  Number of Pokemon: 65
  Shortest: Castform (Snowy) (0.30m)
  Tallest: Cetitan (4.50m)

Ground Type:
  Average Height: 1.67m
  Number of Pokemon: 90
  Shortest: Diglett (0.20m)
  Tallest: Steelix (Mega) (10.50m)

Steel Type:
  Average Height: 1.71m
  Number of Pokemon: 84
  Shortest: Diglett (Alolan) (0.20m)
  Tallest: Steelix (Mega) (10.50m)

Dragon Type:
  Average Height: 2.54m
  Number of Pokemon: 86
  Shortest: Applin (0.20m)
  Tallest: Eternatus (20.00m)
No description has been provided for this image