toddrob99 / MLB-StatsAPI

Python wrapper for MLB Stats API
GNU General Public License v3.0
533 stars 100 forks source link

Postseason bracket #64

Closed WardBrian closed 2 years ago

WardBrian commented 2 years ago

Is there a good way to get the information one would need to draw a bracket? Something like:

Let's assume for starters I want to do it at the conclusion of a season/for a past season.

Something like (I can obviously handle the drawing, more of a data question - none of the endpoints seem to be ideal for this):

WC 2 -----|
          |--- Winner ---|
WC 1 -----|              | --- Winner ---|
               1 seed ---|               |
                                         | NL Champ
               2 seed ---|               |
                         | --- Winner ---|
               3 seed ---|
toddrob99 commented 2 years ago

NHL's implementation of StatsAPI includes a tournaments endpoint, but the MLB StatsAPI doesn't. I don't think there's an easy way to find the data you're looking for... I think you'll need to use the schedule endpoint and piece it together. You can get wildcard games like this: https://statsapi.mlb.com/api/v1/schedule?sportId=1&season=2021&hydrate=game(seriesSummary),seriesStatus&gameType=F, then again with gameType=D for division series, etc. You can find all the gameTypes here: https://statsapi.mlb.com/api/v1/gameTypes.

WardBrian commented 2 years ago

Here is what I ended up going with - I couldn't get specifying a gameType to actually work, so I just grabbed the entire schedule and did some pretty janky processing after the fact (also because I couldn't get abbreviations to populate in this endpoint):

import statsapi 

teams = statsapi.get('teams', {'sportIds':1})['teams']
TEAM_ABBR_LN = {t['name']:t['abbreviation'] for t in teams}

postseason_data = statsapi.get(
    "schedule_postseason_series",
    {
        "season": 2021,
        "hydrate": "league,team",
        "fields": "series,id,gameType,games,description,teams,home,away,team,isWinner,name",
    },
)

AL = League(postseason_data, "AL")
NL = League(postseason_data, "NL")

class League:
    """Grabs postseason bracket info for one league based on the schedule"""

    def __init__(self, data, league):
        self.name = league
        self.wc1, self.wc2 = self.get_seeds(data, "F", league)
        self.ds_one, self.wc_winner = self.get_seeds(data, "D", league, "'A'")
        self.ds_two, self.ds_three = self.get_seeds(data, "D", league, "'B'")
        self.l_one, self.l_two = self.get_seeds(data, "L", league)
        self.champ = self.get_league_champ(data, league)

    @staticmethod
    def get_league_champ(data, league):
        series = next(s for s in data["series"] if s["series"]["gameType"] == "L" and league in s["series"]["id"])
        game = series["games"][-1]
        champ = f"{league}C"
        if game["teams"]["home"].get("isWinner"):
            champ = League.get_abbr(game["teams"]["home"]["team"]["name"])
        elif game["teams"]["away"].get("isWinner"):
            champ = League.get_abbr(game["teams"]["home"]["team"]["name"])
        return champ

    @staticmethod
    def get_seeds(data, gametype, league="", series=""):
        series = next(
            s
            for s in data["series"]
            if s["series"]["gameType"] == gametype and league in s["series"]["id"] and series in s["series"]["id"]
        )

        teams = (
            series["games"][0]["teams"]["home"]["team"]["name"],
            series["games"][0]["teams"]["away"]["team"]["name"],
        )
        if gametype == "F":
            default1 = default2 = "WCW"
        else:
            default1 = league + "^"
            default2 = league + "∨"
        return (League.get_abbr(teams[0], default1), League.get_abbr(teams[1], default2))

    def __str__(self):
        return f"""{self.wc2} ---|
       |--- {self.wc_winner} ---|
{self.wc1} ---|           | --- {self.l_two} ---|
            {self.ds_one} ---|            |
                                | {self.champ}
            {self.ds_two} ---|            |
                   | --- {self.l_one} ---|
            {self.ds_two} ---|
        """

    @staticmethod
    def get_abbr(name, default="???"):
        try:
            return f"{teams.TEAM_ABBR_LN[name]:>3}"
        except:
            return default

Thanks for the pointers!

toddrob99 commented 2 years ago

Nice job. I totally forgot there were postseason schedule endpoints. If you would like to add any functions to the library, feel free to submit a pull request (please format with black first).