Zmalski / NHL-API-Reference

Unofficial reference for the NHL API endpoints.
MIT License
256 stars 19 forks source link

Did NHL stop reporting blockedShots in the gamecenter boxscore?? #16

Open rigatony1 opened 8 months ago

rigatony1 commented 8 months ago

Great site! Thanks for putting it together.

Just curious have you (or anyone else) noticed that the JSON returned from https://[api-web.nhle.com/v1/gamecenter/2023020204/boxscore](https://api-web.nhle.com/v1/gamecenter/2023020204/boxscore) no longer includes blockedShots?

I know it was there until sometime recently, because I have that data all the way back to 2016 saved off in a dataframe. But when I call the API recently, blockedShots is no longer included (see below).

Just wondering if it is available somewhere else, or is I now have to aggregate the totals myself out of the play-by-play data?

cheers -Tony

Current boxscore for a single player below. 'blockedShots' used to appear right after "hits".

{ "playerId": 8475220, "sweaterNumber": 17, "name": { "default": "M. Foligno" }, "position": "L", "goals": 0, "assists": 0, "points": 0, "plusMinus": -1, "pim": 0, "hits": 9, "powerPlayGoals": 0, "shots": 0, "faceoffWinningPctg": 0, "toi": "15:29" },

rigatony1 commented 8 months ago

Grrr...... I think they've dropped some other data too. Not anyone's fault - just reporting it here in case others come across this issue. Following also used to be included but are now missing:

'powerPlayPoints', 'shorthandedGoals', 'shPoints', 'faceoffs', 'powerPlayToi', 'shorthandedToi',

timo-eloranta commented 7 months ago

Yep yep. The removal of faceoffs (= number of faceoffs taken) annoys me quite a bit. The faceoffWinningPctg field alone is worth very little - e.g. value 100% can mean 1/1 (= not news worthy) or 20/20 (= amazing). Would like to talk to the person who decided on these removals...

rigatony1 commented 7 months ago

In case anyone finds it useful, here's function I wrote to extract blocked shots from the play-by-play endpoint. Can be adapted pretty easily to pull out other totals.

def get_blockedshots(game_id,diag=False):
    # Get the blocked shots for every player in a game from the play-by-play data
    # and update the blockedshots column in skaterstats for the game_id
    # returns a dict of playerId:blockedshots

    global skaterstats

    url = f"https://api-web.nhle.com/v1/gamecenter/{game_id}/play-by-play"
    response = requests.get(url)
    if response.status_code != 200:
        print(f"Failed to retrieve play-by-play data from {url}. Status code:", response.status_code)
        return None

    playbyplay = response.json()
    plays = playbyplay['plays']
    blockedshots = {}
    for play in plays:
        if play['typeDescKey'] == 'blocked-shot':
            playerid = play['details']['blockingPlayerId']
            if playerid not in blockedshots:
                blockedshots[playerid] = 1
            else:
                blockedshots[playerid] += 1

    skaterstats.loc[(skaterstats['game_id'] == game_id), 'blockedShots'] = 0
    for playerId,bs in blockedshots.items():
        skaterstats.loc[(skaterstats['game_id'] == game_id) & (skaterstats['playerId'] == playerId), 'blockedShots'] = bs

    return blockedshots
timo-eloranta commented 7 months ago

Interestingly enough, the above function does not yield correct results, if with "correct" we mean the numbers included in NHL's own report, such as https://www.nhl.com/scores/htmlreports/20232024/ES021109.HTM

However, there's a logical reason for this. The play-by-play data uses the same blocked-shot type regardless of who is shooting. So, e.g. in the CAR-WSH game's play-by-play data - https://api-web.nhle.com/v1/gamecenter/2023021109/play-by-play - one finds e.g. this event:

    {
      "eventId": 453,
      "periodDescriptor": {
        "number": 1,
        "periodType": "REG"
      },
      "timeInPeriod": "19:23",
      "timeRemaining": "00:37",
      "situationCode": "1551",
      "homeTeamDefendingSide": "right",
      "typeCode": 508,
      "typeDescKey": "blocked-shot",
      "sortOrder": 305,
      "details": {
        "xCoord": -66,
        "yCoord": 13,
        "zoneCode": "O",
        "blockingPlayerId": 8477979,
        "shootingPlayerId": 8471214,
        "eventOwnerTeamId": 15
      }
    }

This happens to be the only event in the game, where Washington's Nicolas Aube-Kubel (8477979) managed to block a shot. Unfortunately the shootingPlayerId 8471214 belongs to one Alex Ovechkin... :)

If you run the function, it will tell that Aube-Kubel had 1 blocked shot, but in NHL's report - linked above - he is not credited with any blocks.

So, the fix to the function would be to take into account also the shootingPlayerId- or alternatively the eventOwnerTeamId- and to omit blocks where the blocker and the shooter are from the same team.