Lab 11: JSON and Baseball

The Major League Baseball season has been cancelled due to COVID-19. This lab will reminisce about the sport by building an easy-to-use MLB player search program. The best part of the lab is that we do not have any data files. Instead, you'll be making LIVE queries to a web server database to get the information you need. The lab will use a few of our recently learned skills: JSON, web queries, and classes.

Goal

Let's start with the goal this week, and then the instructions will step you through it. We want a program that searches for a team, and then searches for players on that team based on their positions. Your program should look like this when run (red is user input):

Team? Orioles
Position? CF
Keon Broxton (CF)	bats R	height 6'3''	weight 195
Adam Jones   (CF)	bats R	height 6'2''	weight 215
Cedric Mullins (CF)	bats S	height 5'8''	weight 175
Stevie Wilkerson (CF)	bats S	height 6'1''	weight 195
Position? C
Caleb Joseph (C)	bats R	height 6'3''	weight 180
Pedro Severino (C)	bats R	height 6'1''	weight 219
Chance Sisco (C)	bats L	height 6'2''	weight 195
Jesus Sucre  (C)	bats R	height 6'0''	weight 200
Andrew Susac (C)	bats R	height 6'1''	weight 215
Austin Wynns (C)	bats R	height 6'2''	weight 205
Position? 2B
Hanser Alberto (2B)	bats R	height 5'11''	weight 215
Corban Joseph (2B)	bats L	height 6'0''	weight 185
Jose Rondon  (2B)	bats R	height 6'1''	weight 195
Luis Sardinas (2B)	bats S	height 6'1''	weight 180
Jonathan Schoop (2B)	bats R	height 6'1''	weight 225
Breyvic Valera (2B)	bats S	height 5'11''	weight 160
Jonathan Villar (2B)	bats S	height 6'1''	weight 215
Position? 1B
Chris Davis  (1B)	bats L	height 6'3''	weight 230
Position? SS
Tim Beckham  (SS)	bats R	height 6'1''	weight 205
Drew Jackson (SS)	bats R	height 6'2''	weight 200
Manny Machado (SS)	bats R	height 6'3''	weight 215
Richie Martin (SS)	bats R	height 5'11''	weight 190
Engelb Vielma (SS)	bats S	height 5'11''	weight 155
Position? quit
  

Step 1: Write the get_team_ids function

Team? Orioles

When the user enters their team, we have to first find the team's ID in the baseball database. We want to ask for all the players on this team, but we can't do that without knowing the team's ID first. Step one is thus to ask for ALL known team IDs from the Web database. You'll then save these in a dictionary.

Required: Write a function called get_team_ids():

  1. This function takes zero arguments.
  2. This function returns a dictionary of team names mapped to IDs.

The function's only job is to query the baseball website, process the JSON of teams that the website returns, and then build a dictionary that maps team names (strings) to IDs (ints). The function returns this dictionary.

You'll need this code to make the website call and get the JSON:

import requests
      
params = { 'sport_code':"'mlb'", 'sort_order':'name_asc', 'season':'2019' }
r = requests.get(url="http://lookup-service-prod.mlb.com/json/named.team_all_season.bam", params=params)
data = r.json()

That's all you need to get the data. Now climb through the data variable (a dictionary) and get those names and IDs! It's up to you to figure out the format that was returned. Use print() liberally as you debug to see what it has!

In this step you must (1) write your function, (2) call your function, and (3) print out the resulting dictionary. Your output for this Step should look like this:

$ python3 mlb.py
{'AL Champion': '', 'AL Div. Winner #1': '', 'AL Div. Winner #2': '', 'AL Div. Winner #3': '', 'AL Higher Seed': '', 'AL Lower Seed': '', 'AL Wild Card': '', 'AL All-Stars': '', 'D-backs': '109', 'Braves': '144', 'Orioles': '110', 'Red Sox': '111', 'Cubs': '112', 'White Sox': '145', 'Reds': '113', 'Indians': '114', 'Rockies': '115', 'Tigers': '116', 'Astros': '117', 'Royals': '118', 'Lg Champ #1': '', 'Lg Champ #2': '', 'Angels': '108', 'Dodgers': '119', 'Marlins': '146', 'Brewers': '158', 'Twins': '142', 'NL Central Winner': '', 'NL Champion': '', 'NL Div. Winner #1': '', 'NL Div. Winner #2': '', 'NL Higher Seed': '', 'NL Lower Seed': '', 'NL Wild Card': '', 'NL All-Stars': '', 'Mets': '121', 'Yankees': '147', 'Athletics': '133', 'OOC': '', 'Phillies': '143', 'Pirates': '134', 'Padres': '135', 'Giants': '137', 'Mariners': '136', 'Cardinals': '138', 'Rays': '139', 'Rangers': '140', 'Blue Jays': '141', 'Nationals': '120'}  

Step 2: Write the get_players function

Position? CF

After Step 1, you have a dictionary of teams so you can lookup the user's team ID in it. The user will then enter a position. You must now query for all players on that team. This is one more remote call to the website.

Required: Write a function called get_players(id):

  1. It has one argument: a team's int ID (e.g., 118)
  2. It must return a List of Player objects

Your function will query the MLB website for the given team's ID, process the JSON of all the players, and build a List of Player objects. You need the query code, so here it is:

params = { 'start_season':2018, 'end_season':2019, 'team_id':team_id }
r = requests.get(url="http://lookup-service-prod.mlb.com/json/named.roster_team_alltime.bam", params=params)
data = r.json()

Look at the team_id variable in the params dictionary. That should be your ID given to the function, so adjust the name accordingly to your variable.

Your function must return a List of Player objects. This is new! You will make an object Player for each player in the JSON, and put them in a list. We are giving you the Player class. Feel free to copy this into the top of your program. You don't need to make any changes to it. Your job here is to use the class we give you to then create a list of Player instances/objects.

class Player:
    def __init__(self, name, position, bats, heightf, heightin, weight):
        self.name = name
        self.position = position
        self.bats = bats
        self.heightin = int(heightf)*12 + int(heightin)
        self.weight = int(weight)

    def pretty_print(self):
        pname = self.name
        while len(pname) < 12:
            pname += ' '
        print("%s (%s)\tbats %s\theight %d'%d''\tweight %d" % (pname, self.position, self.bats, self.heightin//12, self.heightin%12, self.weight))

Still confused? Well I want you to explore the JSON that is returned. In order to make a Player object, you need to give it 6 different values (see the __init__ function?) ... so your job is to find those 6 values in the JSON for each player. Then make a Player object and append it to a list that you'll return after looping over the JSON.

Still confused? You might want to review the examples on the bottom of the lecture notes. Those examples are looping over JSON values of baseball teams. You'll do something similar but obviously with different dictionary attributes for the players.

Step 3: Complete the program

You're almost finished. You now have a function to get team IDs and a function to get all players for one team. This final step is to write the core program that interacts with the user. The main loop that asks the user for their player positions is straightforward. Remember, they just enter a team name once at the start, and then you loop for player positions until they type "quit".

Required: your output should match EXACTLY the program output at the top of this lab.

(optional) Extra Credit: make it more useful

  1. Allow the user to switch to a different team without quitting the program. You can makeup a new user command as needed.
  2. When you print the matching players, sort them by height. Search the Web for how to sort a list of custom objects like we have here.
  3. The API for the baseball database is here. Add some other neat search feature...up to you!

Document what you did if you completed any of this extra credit. Include instructions on the proper user commands to execute your features. Points awarded will be based on difficulty and substance. #1 above is minimal, but #3 is more.

What to turn in

Visit the submit website and upload your python program.