1 """
2 Introduction
3 ============
4 An API to retrieve and read NFL Game Center JSON data.
5 It can work with real-time data, which can be used for fantasy football.
6
7 nflgame works by parsing the same JSON data that powers NFL.com's live
8 GameCenter. Therefore, nflgame can be used to report game statistics while
9 a game is being played.
10
11 The package comes pre-loaded with game data from every pre- and regular
12 season game from 2009 up until August 28, 2012. Therefore, querying such data
13 does not actually ping NFL.com.
14
15 However, if you try to search for data in a game that is being currently
16 played, the JSON data will be downloaded from NFL.com at each request (so be
17 careful not to inspect for data too many times while a game is being played).
18 If you ask for data for a particular game that hasn't been cached to disk
19 but is no longer being played, it will be automatically cached to disk
20 so that no further downloads are required.
21
22 nflgame requires Python 2.6 or Python 2.7. It does not (yet) work with
23 Python 3.
24
25 Examples
26 ========
27
28 Finding games
29 -------------
30 Games can be selected in bulk, e.g., every game in week 1 of 2010::
31
32 games = nflgame.games(2010, week=1)
33
34 Or pin-pointed exactly, e.g., the Patriots week 17 whomping against the Bills::
35
36 game = nflgame.game(2011, 17, "NE", "BUF")
37
38 This season's (2012) pre-season games can also be accessed::
39
40 pregames = nflgame.games(2012, kind='PRE')
41
42 Find passing leaders of a game
43 ------------------------------
44 Given some game, the player statistics can be easily searched. For example,
45 to find the passing leaders of a particular game::
46
47 for p in game.players.passing().sort("passing_yds"):
48 print p, p.passing_att, p.passing_cmp, p.passing_yds, p.passing_tds
49
50 Output::
51
52 T.Brady 35 23 338 3
53 R.Fitzpatrick 46 29 307 2
54 B.Hoyer 1 1 22 0
55
56 See every player that made an interception
57 ------------------------------------------
58 We can filter all players on whether they had more than zero defensive
59 interceptions, and then sort those players by the number of picks::
60
61 for p in game.players.filter(defense_int=lambda x:x>0).sort("defense_int"):
62 print p, p.defense_int
63
64 Output::
65
66 S.Moore 2
67 A.Molden 1
68 D.McCourty 1
69 N.Barnett 1
70
71 Finding weekly rushing leaders
72 ------------------------------
73 Sequences of players can be added together, and their sum can then be used
74 like any other sequence of players. For example, to get every player
75 that played in week 10 of 2009::
76
77 week10 = nflgame.games(2009, 10)
78 players = nflgame.combine(week10)
79
80 And then to list all rushers with at least 10 carries sorted by rushing yards::
81
82 rushers = players.rushing()
83 for p in rushers.filter(rushing_att=lambda x: x > 10).sort("rushing_yds"):
84 print p, p.rushing_att, p.rushing_yds, p.rushing_tds
85
86 And the final output::
87
88 A.Peterson 18 133 2
89 C.Johnson 26 132 2
90 S.Jackson 26 131 1
91 M.Jones-Drew 24 123 1
92 J.Forsett 17 123 1
93 M.Bush 14 119 0
94 L.Betts 26 114 1
95 F.Gore 25 104 1
96 J.Charles 18 103 1
97 R.Williams 20 102 0
98 K.Moreno 18 97 0
99 L.Tomlinson 24 96 2
100 D.Williams 19 92 0
101 R.Rice 20 89 1
102 C.Wells 16 85 2
103 J.Stewart 11 82 2
104 R.Brown 12 82 1
105 R.Grant 19 79 0
106 K.Faulk 12 79 0
107 T.Jones 21 77 1
108 J.Snelling 18 61 1
109 K.Smith 12 55 0
110 C.Williams 14 52 1
111 M.Forte 20 41 0
112 P.Thomas 11 37 0
113 R.Mendenhall 13 36 0
114 W.McGahee 13 35 0
115 B.Scott 13 33 0
116 L.Maroney 13 31 1
117
118 You could do the same for the entire 2009 season::
119
120 players = nflgame.combine(nflgame.games(2009))
121 for p in players.rushing().sort("rushing_yds").limit(35):
122 print p, p.rushing_att, p.rushing_yds, p.rushing_tds
123
124 And the output::
125
126 C.Johnson 322 1872 12
127 S.Jackson 305 1361 4
128 A.Peterson 306 1335 17
129 T.Jones 305 1324 12
130 M.Jones-Drew 296 1309 15
131 R.Rice 240 1269 7
132 R.Grant 271 1202 10
133 C.Benson 272 1118 6
134 D.Williams 210 1104 7
135 R.Williams 229 1090 11
136 R.Mendenhall 222 1014 7
137 F.Gore 206 1013 8
138 J.Stewart 205 1008 9
139 K.Moreno 233 897 5
140 M.Turner 177 864 10
141 J.Charles 165 861 5
142 F.Jackson 205 850 2
143 M.Barber 200 841 7
144 B.Jacobs 218 834 5
145 M.Forte 242 828 4
146 J.Addai 213 788 9
147 C.Williams 190 776 4
148 C.Wells 170 774 7
149 A.Bradshaw 156 765 7
150 L.Maroney 189 735 9
151 J.Harrison 161 735 4
152 P.Thomas 141 733 5
153 L.Tomlinson 221 729 12
154 Kv.Smith 196 678 4
155 L.McCoy 154 633 4
156 M.Bell 155 626 5
157 C.Buckhalter 114 624 1
158 J.Jones 163 602 2
159 F.Jones 101 594 2
160 T.Hightower 137 574 8
161
162 Load data into Excel
163 --------------------
164 Every sequence of Players can be easily dumped into a file formatted
165 as comma-separated values (CSV). CSV files can then be opened directly
166 with programs like Excel, Google Docs, Open Office and Libre Office.
167
168 You could dump every statistic from a game like so::
169
170 game.players.csv('player-stats.csv')
171
172 Or if you want to get crazy, you could dump the statistics of every player
173 from an entire season::
174
175 nflgame.combine(nflgame.games(2010)).csv('season2010.csv')
176 """
177
178 try:
179 from collections import OrderedDict
180 except:
181 from ordereddict import OrderedDict
182 import itertools
183
184 import nflgame.game
185 import nflgame.live
186 import nflgame.player
187 import nflgame.schedule
188 import nflgame.seq
189
190 VERSION = "1.1.4"
191
192 NoPlayers = nflgame.seq.GenPlayerStats(None)
193 """
194 NoPlayers corresponds to the identity element of a Players sequences.
195
196 Namely, adding it to any other Players sequence has no effect.
197 """
198
199 players = nflgame.player._create_players()
200 """
201 A dict of all players and meta information about each player keyed
202 by GSIS ID. (The identifiers used by NFL.com GameCenter.)
203 """
204
205 teams = [
206 ['ARI', 'Arizona', 'Cardinals', 'Arizona Cardinals'],
207 ['ATL', 'Atlanta', 'Falcons', 'Atlana Falcons'],
208 ['BAL', 'Baltimore', 'Ravens', 'Baltimore Ravens'],
209 ['BUF', 'Buffalo', 'Bills', 'Buffalo Bills'],
210 ['CAR', 'Carolina', 'Panthers', 'Caroline Panthers'],
211 ['CHI', 'Chicago', 'Bears', 'Chicago Bears'],
212 ['CIN', 'Cincinnati', 'Bengals', 'Cincinnati Bengals'],
213 ['CLE', 'Cleveland', 'Browns', 'Cleveland Browns'],
214 ['DAL', 'Dallas', 'Cowboys', 'Dallas Cowboys'],
215 ['DEN', 'Denver', 'Broncos', 'Denver Broncos'],
216 ['DET', 'Detroit', 'Lions', 'Detroit Lions'],
217 ['GB', 'Green Bay', 'Packers', 'Green Bay Packers', 'G.B.'],
218 ['HOU', 'Houston', 'Texans', 'Houston Texans'],
219 ['IND', 'Indianapolis', 'Colts', 'Indianapolis Colts'],
220 ['JAC', 'Jacksonville', 'Jaguars', 'Jacksonville Jaguars', 'JAX'],
221 ['KC', 'Kansas City', 'Chiefs', 'Kansas City Chiefs', 'K.C.'],
222 ['MIA', 'Miami', 'Dolphins', 'Miami Dolphins'],
223 ['MIN', 'Minnesota', 'Vikings', 'Minnesota Vikings'],
224 ['NE', 'New England', 'Patriots', 'New England Patriots', 'N.E.'],
225 ['NO', 'New Orleans', 'Saints', 'New Orleans Saints', 'N.O.'],
226 ['NYG', 'Giants', 'New York Giants', 'N.Y.G.'],
227 ['NYJ', 'Jets', 'New York Jets', 'N.Y.J.'],
228 ['OAK', 'Oakland', 'Raiders', 'Oakland Raiders'],
229 ['PHI', 'Philadelphia', 'Eagles', 'Philadelphia Eagles'],
230 ['PIT', 'Pittsburgh', 'Steelers', 'Pittsburgh Steelers'],
231 ['SD', 'San Diego', 'Chargers', 'San Diego Chargers', 'S.D.'],
232 ['SEA', 'Seattle', 'Seahawks', 'Seattle Seahawks'],
233 ['SF', 'San Francisco', '49ers', 'San Francisco 49ers', 'S.F.'],
234 ['STL', 'St. Louis', 'Rams', 'St. Louis Rams', 'S.T.L.'],
235 ['TB', 'Tampa Bay', 'Buccaneers', 'Tampa Bay Buccaneers', 'T.B.'],
236 ['TEN', 'Tennessee', 'Titans', 'Tennessee Titans'],
237 ['WAS', 'Washington', 'Redskins', 'Washington Redskins', 'WSH'],
238 ]
239 """
240 A list of all teams. Each item is a list of different ways to
241 describe a team. (i.e., JAC, JAX, Jacksonville, Jaguars, etc.).
242 The first item in each list is always the standard NFL.com
243 team abbreviation (two or three letters).
244 """
245
246
247 -def find(name, team=None):
248 """
249 Finds a player (or players) with a name matching (case insensitive)
250 name and returns them as a list.
251
252 If team is not None, it is used as an additional search constraint.
253 """
254 hits = []
255 for player in players.itervalues():
256 if player.name.lower() == name.lower():
257 if team is None or team.lower() == player.team.lower():
258 hits.append(player)
259 return hits
260
261
263 """
264 Returns a standard abbreviation when team corresponds to a team in
265 nflgame.teams (case insensitive). All known variants of a team name are
266 searched. If no team is found, None is returned.
267 """
268 team = team.lower()
269 for variants in teams:
270 for variant in variants:
271 if team == variant.lower():
272 return variants[0]
273 return None
274
275
276 -def games(year, week=None, home=None, away=None, kind='REG', started=False):
277 """
278 games returns a list of all games matching the given criteria. Each
279 game can then be queried for player statistics and information about
280 the game itself (score, winner, scoring plays, etc.).
281
282 As a special case, if the home and away teams are set to the same team,
283 then all games where that team played are returned.
284
285 The kind parameter specifies whether to fetch preseason, regular season
286 or postseason games. Valid values are PRE, REG and POST.
287
288 The week parameter is relative to the value of the kind parameter, and
289 may be set to a list of week numbers.
290 In the regular season, the week parameter corresponds to the normal
291 week numbers 1 through 17. Similarly in the preseason, valid week numbers
292 are 1 through 4. In the post season, the week number corresponds to the
293 numerical round of the playoffs. So the wild card round is week 1,
294 the divisional round is week 2, the conference round is week 3
295 and the Super Bowl is week 4.
296
297 The year parameter specifies the season, and not necessarily the actual
298 year that a game was played in. For example, a Super Bowl taking place
299 in the year 2011 actually belongs to the 2010 season. Also, the year
300 parameter may be set to a list of seasons just like the week parameter.
301
302 Note that if a game's JSON data is not cached to disk, it is retrieved
303 from the NFL web site. A game's JSON data is *only* cached to disk once
304 the game is over, so be careful with the number of times you call this
305 while a game is going on. (i.e., don't piss off NFL.com.)
306
307 If started is True, then only games that have already started (or are
308 about to start in less than 5 minutes) will be returned. Note that the
309 started parameter requires pytz to be installed. This is useful when
310 you only want to collect stats from games that have JSON data available
311 (as opposed to waiting for a 404 error from NFL.com).
312 """
313 return list(games_gen(year, week, home, away, kind, started))
314
315
316 -def games_gen(year, week=None, home=None, away=None,
317 kind='REG', started=False):
318 """
319 games returns a generator of all games matching the given criteria. Each
320 game can then be queried for player statistics and information about
321 the game itself (score, winner, scoring plays, etc.).
322
323 As a special case, if the home and away teams are set to the same team,
324 then all games where that team played are returned.
325
326 The kind parameter specifies whether to fetch preseason, regular season
327 or postseason games. Valid values are PRE, REG and POST.
328
329 The week parameter is relative to the value of the kind parameter, and
330 may be set to a list of week numbers.
331 In the regular season, the week parameter corresponds to the normal
332 week numbers 1 through 17. Similarly in the preseason, valid week numbers
333 are 1 through 4. In the post season, the week number corresponds to the
334 numerical round of the playoffs. So the wild card round is week 1,
335 the divisional round is week 2, the conference round is week 3
336 and the Super Bowl is week 4.
337
338 The year parameter specifies the season, and not necessarily the actual
339 year that a game was played in. For example, a Super Bowl taking place
340 in the year 2011 actually belongs to the 2010 season. Also, the year
341 parameter may be set to a list of seasons just like the week parameter.
342
343 Note that if a game's JSON data is not cached to disk, it is retrieved
344 from the NFL web site. A game's JSON data is *only* cached to disk once
345 the game is over, so be careful with the number of times you call this
346 while a game is going on. (i.e., don't piss off NFL.com.)
347
348 If started is True, then only games that have already started (or are
349 about to start in less than 5 minutes) will be returned. Note that the
350 started parameter requires pytz to be installed. This is useful when
351 you only want to collect stats from games that have JSON data available
352 (as opposed to waiting for a 404 error from NFL.com).
353 """
354 infos = _search_schedule(year, week, home, away, kind, started)
355 if not infos:
356 return None
357
358 def gen():
359 for info in infos:
360 g = nflgame.game.Game(info['eid'])
361 if g is None:
362 continue
363 yield g
364 return gen()
365
366
367 -def one(year, week, home, away, kind='REG', started=False):
368 """
369 one returns a single game matching the given criteria. The
370 game can then be queried for player statistics and information about
371 the game itself (score, winner, scoring plays, etc.).
372
373 one returns either a single game or no games. If there are multiple games
374 matching the given criteria, an assertion is raised.
375
376 The kind parameter specifies whether to fetch preseason, regular season
377 or postseason games. Valid values are PRE, REG and POST.
378
379 The week parameter is relative to the value of the kind parameter, and
380 may be set to a list of week numbers.
381 In the regular season, the week parameter corresponds to the normal
382 week numbers 1 through 17. Similarly in the preseason, valid week numbers
383 are 1 through 4. In the post season, the week number corresponds to the
384 numerical round of the playoffs. So the wild card round is week 1,
385 the divisional round is week 2, the conference round is week 3
386 and the Super Bowl is week 4.
387
388 The year parameter specifies the season, and not necessarily the actual
389 year that a game was played in. For example, a Super Bowl taking place
390 in the year 2011 actually belongs to the 2010 season. Also, the year
391 parameter may be set to a list of seasons just like the week parameter.
392
393 Note that if a game's JSON data is not cached to disk, it is retrieved
394 from the NFL web site. A game's JSON data is *only* cached to disk once
395 the game is over, so be careful with the number of times you call this
396 while a game is going on. (i.e., don't piss off NFL.com.)
397
398 If started is True, then only games that have already started (or are
399 about to start in less than 5 minutes) will be returned. Note that the
400 started parameter requires pytz to be installed. This is useful when
401 you only want to collect stats from games that have JSON data available
402 (as opposed to waiting for a 404 error from NFL.com).
403 """
404 infos = _search_schedule(year, week, home, away, kind, started)
405 if not infos:
406 return None
407 assert len(infos) == 1, 'More than one game matches the given criteria.'
408 return nflgame.game.Game(infos[0]['eid'])
409
410
412 """
413 DEPRECATED. Please use one of nflgame.combine_{game,play,max}_stats
414 instead.
415
416 Combines a list of games into one big player sequence containing game
417 level statistics.
418
419 This can be used, for example, to get PlayerStat objects corresponding to
420 statistics across an entire week, some number of weeks or an entire season.
421
422 If the plays parameter is True, then statistics will be dervied from
423 play by play data. This mechanism is slower but will contain more detailed
424 statistics like receiver targets, yards after the catch, punt and field
425 goal blocks, etc.
426 """
427 if plays:
428 return combine_play_stats(games)
429 else:
430 return combine_game_stats(games)
431
432
434 """
435 Combines a list of games into one big player sequence containing game
436 level statistics.
437
438 This can be used, for example, to get GamePlayerStats objects corresponding
439 to statistics across an entire week, some number of weeks or an entire
440 season.
441 """
442 return reduce(lambda ps1, ps2: ps1 + ps2,
443 [g.players for g in games if g is not None])
444
445
447 """
448 Combines a list of games into one big player sequence containing play
449 level statistics.
450
451 This can be used, for example, to get PlayPlayerStats objects corresponding
452 to statistics across an entire week, some number of weeks or an entire
453 season.
454
455 This function should be used in lieu of combine_game_stats when more
456 detailed statistics such as receiver targets, yards after the catch and
457 punt/FG blocks are needed.
458
459 N.B. Since this combines *all* play data, this function may take a while
460 to complete depending on the number of games passed in.
461 """
462 return reduce(lambda p1, p2: p1 + p2,
463 [g.drives.players() for g in games if g is not None])
464
465
467 """
468 Combines a list of games into one big player sequence containing maximum
469 statistics based on game and play level statistics.
470
471 This can be used, for example, to get GamePlayerStats objects corresponding
472 to statistics across an entire week, some number of weeks or an entire
473 season.
474
475 This function should be used in lieu of combine_game_stats or
476 combine_play_stats when the best possible accuracy is desired.
477 """
478 return reduce(lambda a, b: a + b,
479 [g.max_player_stats() for g in games if g is not None])
480
481
483 """
484 Combines a list of games into one big play generator that can be searched
485 as if it were a single game.
486 """
487 chain = itertools.chain(*[g.drives.plays() for g in games])
488 return nflgame.seq.GenPlays(chain)
489
490
491 -def _search_schedule(year, week=None, home=None, away=None, kind='REG',
492 started=False):
493 """
494 Searches the schedule to find the game identifiers matching the criteria
495 given.
496
497 The kind parameter specifies whether to fetch preseason, regular season
498 or postseason games. Valid values are PRE, REG and POST.
499
500 The week parameter is relative to the value of the kind parameter, and
501 may be set to a list of week numbers.
502 In the regular season, the week parameter corresponds to the normal
503 week numbers 1 through 17. Similarly in the preseason, valid week numbers
504 are 1 through 4. In the post season, the week number corresponds to the
505 numerical round of the playoffs. So the wild card round is week 1,
506 the divisional round is week 2, the conference round is week 3
507 and the Super Bowl is week 4.
508
509 The year parameter specifies the season, and not necessarily the actual
510 year that a game was played in. For example, a Super Bowl taking place
511 in the year 2011 actually belongs to the 2010 season. Also, the year
512 parameter may be set to a list of seasons just like the week parameter.
513
514 If started is True, then only games that have already started (or are
515 about to start in less than 5 minutes) will be returned. Note that the
516 started parameter requires pytz to be installed. This is useful when
517 you only want to collect stats from games that have JSON data available
518 (as opposed to waiting for a 404 error from NFL.com).
519 """
520 infos = []
521 for (y, t, w, h, a), info in nflgame.schedule.games:
522 if year is not None:
523 if isinstance(year, list) and y not in year:
524 continue
525 if not isinstance(year, list) and y != year:
526 continue
527 if week is not None:
528 if isinstance(week, list) and w not in week:
529 continue
530 if not isinstance(week, list) and w != week:
531 continue
532 if home is not None and away is not None and home == away:
533 if h != home and a != home:
534 continue
535 else:
536 if home is not None and h != home:
537 continue
538 if away is not None and a != away:
539 continue
540 if t != kind:
541 continue
542 if started:
543 gametime = nflgame.live._game_datetime(info)
544 now = nflgame.live._now()
545 if gametime > now and (gametime - now).total_seconds() > 300:
546 continue
547 infos.append(info)
548 return infos
549