Level Requirements for Pokemon Go From 40-50

Written by alvations | Published 2023/03/04
Tech Story Tags: data-science | python | pokemon-go | the-grind-is-real | gaming | matplotlib | hackernoon-top-story | grinding-pokemon-go | web-monetization

TLDRAs a data scientist, your reflex action is to google (or maybe bing) What are the level requirements for Pokemon go from level 40-50? We used to talk normally until we regress into communicating with computers by dropping "stopwords" and SEO our keystrokes. And now you want us to go back to typing in full sentences so that computers can try to learn human language?!via the TL;DR App

Grinding your way from level 41-50 is a pain but seeing players on your friend list at level 50, you wonder when will you ever be on "PoGo mile-50 club".

As a data scientist, your reflex action is to google (or maybe bing)

pokemon go level requirements 40-50

Or if you prefer to ask bard / chatgpt, you would have typed:

What are the level requirements for pokemon go from level 40-50?

Cut-away: We used to talk normally until we regress into communicating with computers by dropping "stopwords" and SEO our keystrokes. And now you want us to go back to typing in full sentences so that computers can try to learn human language?! Maybe those AI models should start understanding:

(╯°□°)╯︵◓ 🪜 how?

Okay, back to proper plotting...

This GameRadar guide is a good start but it's just not "data-friendly", lets convert the information into a JSON.

https://www.gamesradar.com/pokemon-go-level-tasks-requirements-41-50/

level_guide = {
    41: {
        'xp': 6_000_000,
        'rewards': {
            'ultra_balls': 20,
            'max_potions': 20,
            'max_revives': 20,
            'razz_berries': 20,
            'incubator': 1,
            'xl_candy': 1
        },
        'tasks': ['Power up a Legendary Pokemon 20 times',
            'Win 30 raids',
            'Catch 200 Pokemon in a single day',
            'Earn 5 gold medals'
        ]
    },

    42: {
        'xp': 7_000_000,
        'rewards': {
            'ultra_balls': 20,
            'max_potions': 20,
            'max_revives': 20,
            'nanab_berries': 20,
            'incubator': 1,
            'premium_pass': 1,
            'xl_candy': 1
        },
        'tasks': ['Evolve Eevee into each of its unique evolutions',
            'Use items to evolve Pokemon 15 times',
            'Make 3 Excellent Throws',
            'Use 200 berries to help catch Pokemon'
        ]
    }, ...,

    50: {
        'xp': 30_000_000,
        'rewards': {
            'ultra_balls': 50,
            'max_potions': 50,
            'max_revives': 20,
            'super_incubator': 5,
            'xl_candy': 2,
            'elite_charged_tm': 1,
            'incense': 5,
            'lucky_egg': 5,
            'lure': 5
        },
        'tasks': ['Make 999 Excellent throws',
             'Catch a Legendary Pokemon in your next five Legendary Pokemon encounters',
             'Defeat a Team Go Rocket Leader three times using only Pokemon with 2,500 CP or less',
             'Reach Rank 10 in the Go Battle League'
        ]
    },

}

from pprint import pprint

pprint(level_guide[42])

{'rewards': {'incubator': 1,
             'max_potions': 20,
             'max_revives': 20,
             'nanab_berries': 20,
             'premium_pass': 1,
             'ultra_balls': 20,
             'xl_candy': 1},
 'tasks': ['Evolve Eevee into each of its unique evolutions',
           'Use items to evolve Pokemon 15 times',
           'Make 3 Excellent Throws',
           'Use 200 berries to help catch Pokemon'],
 'xp': 7000000}

Lets see how much more effort do I need to get to the next level

import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns


sns.set_theme(style="darkgrid")
plt.ticklabel_format(style='plain')

xp_needed = {k:level_guide[k]['xp'] for k in level_guide}
df_xp = pd.DataFrame(xp_needed.items(), columns=['Level', 'XP'])

ax = sns.lineplot(data=df_xp, x="Level", y="XP")
ax.yaxis.set_major_formatter(mpl.ticker.StrMethodFormatter('{x:,.0f}'))

ax.set_xlim(40, 51)

plt.show()

What?! It's exponential increase in the no. of XP needed?!!

Oh PoGo, your game designers and devs seriously knows how to keep players "sticky" to the app and buy those ever-inflationary Pokecoins!

So much sacrifice to gratify my childhood nostalgia for cute little monsters on a candy-bar phone.

For my grinding effort, what juicy binary rewards will I get?

pprint(level_guide[42]['rewards'])

{'incubator': 1,
 'max_potions': 20,
 'max_revives': 20,
 'nanab_berries': 20,
 'premium_pass': 1,
 'ultra_balls': 20,
 'xl_candy': 1}

Even reading the list of rewards is painful to know exactly how many pots, balls and revives I'll get after leveling up...

Lets try to put them into pictures. First collect the list of image urls and automate some downloading.

import shutil
import requests

import imageio.v2 as imageio
import numpy as np
import PIL
from PIL import Image
from IPython.display import Image as JupyterImage


def download_image(img_url, save_to, thumbnail_size=(25,25)):
    response = requests.get(img_url, stream = True)
    response.raw.decode_content = True
    with open(save_to,'wb') as fout:
        shutil.copyfileobj(response.raw, fout)
    
    # Create thumbnail
    if thumbnail_size:
        image = Image.open(save_to)  
        image.thumbnail(thumbnail_size)
        image.save(save_to.rpartition('.')[0] + '.thumbnail.png')
    

img_urls = {'golden_razz_berries': "https://www.serebii.net/brilliantdiamondshiningpearl/berries/16.png",
 'max_potions': 'https://static.wikia.nocookie.net/pokemon/images/a/a2/Dream_Max_Potion_Sprite.png',
 'max_revives': 'https://static.wikia.nocookie.net/pokemon/images/4/45/Dream_Max_Revive_Sprite.png',
 'nanab_berries': 'https://static.wikia.nocookie.net/pokemon/images/f/f6/NanabBerry-GO.png',
 'razz_berries': "https://static.wikia.nocookie.net/pokemon/images/3/32/Dream_Razz_Berry_Sprite.png",
 'silver_pinap_berries': 'https://pokemongohub.net/wp-content/uploads/2018/08/Item_0707.png',
 'pinap_berries': 'https://pokemongohub.net/wp-content/uploads/2018/03/Item_0705.png',
 'ultra_balls': 'https://static.wikia.nocookie.net/pokemon/images/f/f1/UltraBallArt.png'}


for i, url in img_urls.items():
    download_image(url, f'{i}.png')

Ah, I can use a scatter plot and add_artist to present the rewards.

From https://stackoverflow.com/questions/22566284/matplotlib-how-to-plot-images-instead-of-points

def fetch_num_items(level_guide_l, x):
    for r in level_guide_l['rewards']:
        if r.endswith(x):
            return level_guide_l['rewards'][r]
    return 0

ball_pots_revs = [{'levels': l, 
  'potions': fetch_num_items(level_guide[l], '_potions'),
  'revives': fetch_num_items(level_guide[l], '_revives'),
  'balls': fetch_num_items(level_guide[l], '_balls'),
  'berries': fetch_num_items(level_guide[l], '_berries'),
  'balls_img': next(r for r in level_guide[l]['rewards'] 
                      if r.endswith('_balls')) + '.thumbnail.png',
  'potions_img': next(r for r in level_guide[l]['rewards'] 
                      if r.endswith('_potions')) + '.thumbnail.png',
  'revives_img': next(r for r in level_guide[l]['rewards'] 
                      if r.endswith('_revives')) + '.thumbnail.png',
 }  for l in level_guide
]

df_bpr = pd.DataFrame.from_dict(ball_pots_revs)
df_bpr

And the plot…

import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox

def getImage(path, zoom=1):
    return OffsetImage(plt.imread(path), zoom=zoom)

# Substitute with `df_bpr['potions_img']` or `df_bpr['revives_img']`
paths = df_bpr['balls_img']
    
x = df_bpr['levels'] 
y = df_bpr['balls'] # Substitute with `df_bpr['potions']` or `df_bpr['revives']`

fig, ax = plt.subplots()
ax.scatter(x, y) 

for x0, y0, path in zip(x, y,paths):
    ab = AnnotationBbox(getImage(path), (x0, y0), frameon=False)
    ax.add_artist(ab)


Yeah that's nice, now do potions.

And revives!

What?! I get only 20 max revives for every level

I wonder how the game devs decide how many reward items to give for the levels. Maybe they did what my teacher used to grade our papers, hold the student essays, walk to the staircase, throw them down the stairs, the nearest get As, the furthest gets Fs.

The game devs must have done the same to the reward items and all the max revives plushies drops the bottom of the stairs.

Come to think of it, why ain't Pokemon Company churning out plushies for Pokemon items?

I would love to mix a bunch of different berries plushie and put them in the fridge whenever we run out of fruits before I go to the store to replenish them.

I guess I could generate them with “un-stable diffusion” on huggingface for now…


Reading the plots individual is tedious...

Can't you put all the items together?

paths = list(df_bpr['revives_img']) + list(df_bpr['potions_img']) + list(df_bpr['balls_img'])
    
x = list(df_bpr['levels']) + list(df_bpr['levels']) + list(df_bpr['levels'])
y = list(df_bpr['revives']) + list(df_bpr['potions']) + list(df_bpr['balls'])

fig, ax = plt.subplots()
ax.scatter(x, y) 

for x0, y0, path in zip(x, y,paths):
    ab = AnnotationBbox(getImage(path), (x0, y0), frameon=False)
    ax.add_artist(ab)

That looks better! Hmmm, something smells off...

待って! (Wait a minute!) Did the images slapped on each other when they are on the same point?!

Q: Can't you try to just group them together if they fall on the same point?!

A: I guess so, but do you really need some "beautiful" infographics just to know whether it's worth it for you to grind up to level 50?

Lets try to combine some images and group them together

From https://stackoverflow.com/questions/30227466/combine-several-images-horizontally-with-python

def combine_images(image_filenames, output_filename, pilmode='RGBA', how='v'):
    imgs    = [Image.fromarray(imageio.imread(i, pilmode=pilmode))
               for i in image_filenames]
    max_shape = sorted( [(np.sum(i.size), i.size) for i in imgs])[-1][-1]
    # Vertical
    if how[0].lower()=='v':
        imgs_comb = np.vstack([i.resize(max_shape) for i in imgs])
    # Horizontal
    elif how[0].lower()=='h':
        imgs_comb = np.hstack([i.resize(max_shape) for i in imgs])
    # Square
    elif how[0].lower()=='s':
        if len(image_filenames) % 2 != 0: # If odd, add a blank image.
            Image.new('RGBA', max_shape).save('blank.png')
            image_filenames += ['blank.png']
        combine_images(image_filenames[:len(image_filenames)//2], 'part1.png', how='h')
        combine_images(image_filenames[len(image_filenames)//2:], 'part2.png', how='h')
        imgs = [Image.fromarray(imageio.imread('part1.png', pilmode=pilmode)),
                Image.fromarray(imageio.imread('part2.png', pilmode=pilmode))]
        scale = len(image_filenames[:len(image_filenames)//2])
        max_shape =(max_shape[0]*scale, max_shape[1]*1)
        imgs_comb = np.vstack([i.resize(max_shape) for i in imgs])
    imgs_comb = Image.fromarray(imgs_comb)
    imgs_comb.save(output_filename)
  

Using the combine_images function

list_im = ['max_revives.thumbnail.png', 'max_potions.thumbnail.png', 
           'ultra_balls.thumbnail.png', 'golden_razz_berries.thumbnail.png']
combine_images(list_im, output_filename='rewards-s.png', how='square')
display(JupyterImage(filename='rewards-s.png'))

Cool! Now do the plots again.

We'll have to group the images together by (x,y) points instead of keeping them in a nice table.

def fetch_num_items(level_guide_l, x):
    for r in level_guide_l['rewards']:
        if r.endswith(x):
            return level_guide_l['rewards'][r]
    return 0

ball_pots_revs_ber = [{'levels': l, 
  'potions': fetch_num_items(level_guide[l], '_potions'),
  'revives': fetch_num_items(level_guide[l], '_revives'),
  'balls': fetch_num_items(level_guide[l], '_balls'),
  'berries': fetch_num_items(level_guide[l], '_berries'),
 }  for l in level_guide
]

df_bprb = pd.DataFrame.from_dict(ball_pots_revs_ber)

from collections import defaultdict

data_points = defaultdict(list)
    
for idx, row in df_bprb.iterrows():
    x = row['levels']

    for i in row.index:
        if i != 'levels':
            y = row[i]
            if y == 0:
                continue
            data_points[(x,y)].append(
                next(r for r in level_guide[x]['rewards'] if r.endswith(i)) + '.thumbnail.png'
            )

print(data_points)

[out]:

defaultdict(list,
            {(41, 20): ['max_potions.thumbnail.png',
              'max_revives.thumbnail.png',
              'ultra_balls.thumbnail.png',
              'razz_berries.thumbnail.png'],
             (42, 20): ['max_potions.thumbnail.png',
              'max_revives.thumbnail.png',
              'ultra_balls.thumbnail.png',
              'nanab_berries.thumbnail.png'],
             ...,
             (50, 50): ['max_potions.thumbnail.png',
              'ultra_balls.thumbnail.png'],
             (50, 20): ['max_revives.thumbnail.png']})

Now, we have the images we want to combine for every scatter point

data_points_imgs = {}
for k, v in data_points.items():
    fname = f"{'-'.join(map(str, k))}.png"
    if len(v) in [1,2]:
        combine_images(v, output_filename=fname, how='horizontal')
    else:
        combine_images(v, output_filename=fname, how='square')
    data_points_imgs[k] = fname

Go, go, go. Plot it!

import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox

import seaborn as sns

sns.set(rc={'figure.figsize':(11.7,8.27)})

x, y = zip(*data_points_imgs)

fig, ax = plt.subplots()
ax.scatter(x, y, s=0.01)
plt.xlabel('Level')
plt.ylabel('Rewards')
plt.xlim([40, 51])

ppp = data_points_imgs.values()

for x0, y0, path in zip(x, y,ppp):
    ab = AnnotationBbox(
        OffsetImage(plt.imread(path), zoom=1),
        (x0, y0), frameon=False)
    ax.add_artist(ab)

Now, you see the exponential grind and rewards, whatcha gonna do?

https://youtu.be/MpaHR-V_R-o?embedable=true

Also published here.


Written by alvations | Code, write, possibly stream someday.
Published by HackerNoon on 2023/03/04