wsba-hockey 1.0.0__tar.gz → 1.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {wsba_hockey-1.0.0/src/wsba_hockey.egg-info → wsba_hockey-1.0.2}/PKG-INFO +2 -2
  2. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/README.md +1 -1
  3. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/pyproject.toml +1 -1
  4. wsba_hockey-1.0.2/src/wsba_hockey/tools/plotting.py +143 -0
  5. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/tools/scraping.py +2 -3
  6. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/tools/xg_model.py +1 -0
  7. wsba_hockey-1.0.2/src/wsba_hockey/workspace.py +114 -0
  8. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/wsba_main.py +16 -31
  9. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2/src/wsba_hockey.egg-info}/PKG-INFO +2 -2
  10. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey.egg-info/SOURCES.txt +1 -0
  11. wsba_hockey-1.0.0/src/wsba_hockey/tools/plotting.py +0 -113
  12. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/LICENSE +0 -0
  13. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/setup.cfg +0 -0
  14. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/__init__.py +0 -0
  15. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/stats/calculate_viz/shot_impact.py +0 -0
  16. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/tools/__init__.py +0 -0
  17. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/tools/agg.py +0 -0
  18. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/tools/archive/old_scraping.py +0 -0
  19. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/tools/utils/__init__.py +0 -0
  20. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/tools/utils/config.py +0 -0
  21. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/tools/utils/save_pages.py +0 -0
  22. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey/tools/utils/shared.py +0 -0
  23. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey.egg-info/dependency_links.txt +0 -0
  24. {wsba_hockey-1.0.0 → wsba_hockey-1.0.2}/src/wsba_hockey.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wsba_hockey
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: WeakSide Breakout's complete Python package of access to hockey data, primairly including the scraping of National Hockey League schedule, play-by-play, and shifts information.
5
5
  Author-email: Owen Singh <owenbksingh@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/owensingh38/wsba_hockey/
@@ -78,7 +78,7 @@ skater_dict = {
78
78
  }
79
79
  pbp = wsba.nhl_scrape_season('20212022',remove=[], local = True)
80
80
 
81
- wsba.nhl_plot_skater_shots(pbp,skater_dict,['5v5'],legend=True)
81
+ wsba.nhl_plot_skaters_shots(pbp,skater_dict,['5v5'],onice='for',legend=True)
82
82
  wsba.nhl_plot_games(pbp,legend=True)
83
83
  ```
84
84
 
@@ -63,7 +63,7 @@ skater_dict = {
63
63
  }
64
64
  pbp = wsba.nhl_scrape_season('20212022',remove=[], local = True)
65
65
 
66
- wsba.nhl_plot_skater_shots(pbp,skater_dict,['5v5'],legend=True)
66
+ wsba.nhl_plot_skaters_shots(pbp,skater_dict,['5v5'],onice='for',legend=True)
67
67
  wsba.nhl_plot_games(pbp,legend=True)
68
68
  ```
69
69
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "wsba_hockey"
3
- version = "1.0.0"
3
+ version = "1.0.2"
4
4
  authors = [
5
5
  { name="Owen Singh", email="owenbksingh@gmail.com" },
6
6
  ]
@@ -0,0 +1,143 @@
1
+ import matplotlib.pyplot as plt
2
+ import matplotlib.image as mpimg
3
+ import numpy as np
4
+ import pandas as pd
5
+ from scipy.interpolate import griddata
6
+ from scipy.ndimage import gaussian_filter
7
+ import urllib.request
8
+ import PIL
9
+ from .xg_model import *
10
+ from hockey_rink import NHLRink
11
+ from hockey_rink import CircularImage
12
+
13
+ event_markers = {
14
+ 'faceoff':'X',
15
+ 'hit':'P',
16
+ 'blocked-shot':'v',
17
+ 'missed-shot':'H',
18
+ 'shot-on-goal':'D',
19
+ 'goal':'o',
20
+ 'giveaway':'1',
21
+ 'takeaway':'2',
22
+ }
23
+
24
+ def wsba_rink(display_range='offense',rotation = 0):
25
+ img = 'tools/utils/wsba.png'
26
+ rink = NHLRink(center_logo={
27
+ "feature_class": CircularImage,
28
+ "image_path": img,
29
+ "length": 25, "width": 25,
30
+ "x": 0, "y": 0,
31
+ "radius": 14,
32
+ "zorder": 11,
33
+ }
34
+ )
35
+ rink.draw(
36
+ display_range=display_range,
37
+ rotation=rotation,
38
+ despine=True
39
+ )
40
+
41
+ def prep_plot_data(pbp,events,strengths,marker_dict=event_markers,xg='moneypuck'):
42
+ try: pbp['xG']
43
+ except:
44
+ if xg == 'wsba':
45
+ pbp = wsba_xG(pbp)
46
+ else:
47
+ pbp = moneypuck_xG(pbp)
48
+ pbp['xG'] = np.where(pbp['xG'].isna(),0,pbp['xG'])
49
+
50
+ pbp['WSBA'] = pbp['event_player_1_name']+pbp['season'].astype(str)+pbp['event_team_abbr']
51
+
52
+ pbp['x_plot'] = pbp['y_fixed']*-1
53
+ pbp['y_plot'] = pbp['x_fixed']
54
+
55
+ pbp['home_on_ice'] = pbp['home_on_1'].astype(str) + ";" + pbp['home_on_2'].astype(str) + ";" + pbp['home_on_3'].astype(str) + ";" + pbp['home_on_4'].astype(str) + ";" + pbp['home_on_5'].astype(str) + ";" + pbp['home_on_6'].astype(str)
56
+ pbp['away_on_ice'] = pbp['away_on_1'].astype(str) + ";" + pbp['away_on_2'].astype(str) + ";" + pbp['away_on_3'].astype(str) + ";" + pbp['away_on_4'].astype(str) + ";" + pbp['away_on_5'].astype(str) + ";" + pbp['away_on_6'].astype(str)
57
+
58
+ pbp['onice_for'] = np.where(pbp['home_team_abbr']==pbp['event_team_abbr'],pbp['home_on_ice'],pbp['away_on_ice'])
59
+ pbp['onice_against'] = np.where(pbp['away_team_abbr']==pbp['event_team_abbr'],pbp['home_on_ice'],pbp['away_on_ice'])
60
+
61
+ pbp['size'] = np.where(pbp['xG']<=0,40,pbp['xG']*400)
62
+ pbp['marker'] = pbp['event_type'].replace(marker_dict)
63
+
64
+ pbp = pbp.loc[(pbp['event_type'].isin(events))&
65
+ (pbp['event_distance']<=89)&
66
+ (pbp['x_fixed']<=89)]
67
+
68
+ if strengths != 'all':
69
+ pbp = pbp.loc[(pbp['strength_state'].isin(strengths))]
70
+
71
+ return pbp
72
+
73
+ def league_shots(pbp,events,strengths):
74
+ pbp = prep_plot_data(pbp,events,strengths)
75
+
76
+ print(pbp[['event_player_1_name','xG','x_plot','y_plot']].head(10))
77
+
78
+ [x,y] = np.round(np.meshgrid(np.linspace(-42.5,42.5,85),np.linspace(0,100,100)))
79
+ xgoals = griddata((pbp[f'x_plot'],pbp[f'y_plot']),pbp['xG'],(x,y),method='cubic',fill_value=0)
80
+ xgoals_smooth = gaussian_filter(xgoals,sigma = 3)
81
+
82
+ return xgoals_smooth
83
+
84
+ def plot_skater_shots(pbp, player, season, team, strengths, title = None, marker_dict=event_markers, onice='for', legend=False,xg='moneypuck'):
85
+ shots = ['missed-shot','shot-on-goal','goal']
86
+ pbp = prep_plot_data(pbp,shots,strengths,marker_dict,xg)
87
+ pbp = pbp.loc[(pbp['season'].astype(str)==season)&((pbp['away_team_abbr']==team)|(pbp['home_team_abbr']==team))]
88
+
89
+ team_data = pd.read_csv('teaminfo/nhl_teaminfo.csv')
90
+ team_color = list(team_data.loc[team_data['WSBA']==f'{team}{season}','Primary Color'])[0]
91
+ team_color_2nd = list(team_data.loc[team_data['WSBA']==f'{team}{season}','Secondary Color'])[0]
92
+
93
+ if onice in ['for','against']:
94
+ skater = pbp.loc[(pbp[f'onice_{onice}'].str.contains(player.upper()))]
95
+ skater['color'] = np.where(skater['event_player_1_name']==player.upper(),team_color,team_color_2nd)
96
+
97
+ else:
98
+ skater = pbp.loc[pbp['event_player_1_name']==player.upper()]
99
+ skater['color'] = team_color
100
+
101
+ fig, ax = plt.subplots()
102
+ wsba_rink(rotation=90)
103
+
104
+ for event in shots:
105
+ plays = skater.loc[skater['event_type']==event]
106
+ ax.scatter(plays['x_plot'],plays['y_plot'],plays['size'],plays['color'],marker=event_markers[event],label=event,zorder=5)
107
+
108
+ ax.set_title(title) if title else ''
109
+ ax.legend().set_visible(legend)
110
+ ax.legend().set_zorder(1000)
111
+
112
+ return fig
113
+
114
+ def plot_game_events(pbp,game_id,events,strengths,marker_dict=event_markers,team_colors={'away':'secondary','home':'primary'},legend=False,xg='moneypuck'):
115
+ pbp = prep_plot_data(pbp,events,strengths,marker_dict,xg)
116
+ pbp = pbp.loc[pbp['game_id'].astype(str)==game_id]
117
+
118
+ away_abbr = list(pbp['away_team_abbr'])[0]
119
+ home_abbr = list(pbp['home_team_abbr'])[0]
120
+ date = list(pbp['game_date'])[0]
121
+ season = f'{game_id[0:4]}{int(game_id[0:4])+1}'
122
+
123
+ team_data = pd.read_csv('teaminfo/nhl_teaminfo.csv')
124
+ team_info ={
125
+ 'away_color':'#000000' if list(team_data.loc[team_data['WSBA']==f'{away_abbr}{season}','Secondary Color'])[0]=='#FFFFFF' else list(team_data.loc[team_data['WSBA']==f'{away_abbr}{season}',f'{team_colors['away'].capitalize()} Color'])[0],
126
+ 'home_color': list(team_data.loc[team_data['WSBA']==f'{home_abbr}{season}',f'{team_colors['home'].capitalize()} Color'])[0],
127
+ 'away_logo': f'tools/logos/png/{away_abbr}{season}.png',
128
+ 'home_logo': f'tools/logos/png/{home_abbr}{season}.png',
129
+ }
130
+
131
+ pbp['color'] = np.where(pbp['event_team_abbr']==away_abbr,team_info['away_color'],team_info['home_color'])
132
+
133
+ fig, ax = plt.subplots()
134
+ wsba_rink(display_range='full')
135
+
136
+ for event in events:
137
+ plays = pbp.loc[pbp['event_type']==event]
138
+ ax.scatter(plays['x_adj'],plays['y_adj'],plays['size'],plays['color'],marker=event_markers[event],label=event,zorder=5)
139
+
140
+ ax.set_title(f'{away_abbr} @ {home_abbr} - {date}')
141
+ ax.legend(bbox_to_anchor =(0.5,-0.35), loc='lower center',ncol=1).set_visible(legend)
142
+
143
+ return fig
@@ -337,7 +337,6 @@ def parse_espn(date,away,home):
337
337
  coords_df = coords_df.assign(
338
338
  coords_x = coords_df[~pd.isna(coords_df.coordinate)].coordinate.apply(lambda x: x['x']).astype(int),
339
339
  coords_y = coords_df[~pd.isna(coords_df.coordinate)].coordinate.apply(lambda y: y['y']).astype(int),
340
- event_player_1_name = coords_df[~pd.isna(coords_df.athlete)]['athlete'].apply(lambda x: x['name'])
341
340
  )
342
341
 
343
342
  #Combine
@@ -356,7 +355,7 @@ def parse_espn(date,away,home):
356
355
  coords_y = np.where((pd.isna(espn_events.coords_x)) & (pd.isna(espn_events.coords_y)) &
357
356
  (espn_events.event_type=='Face Off'), 0, espn_events.coords_y))
358
357
 
359
- espn_events = espn_events[(~pd.isna(espn_events.coords_x)) & (~pd.isna(espn_events.coords_y)) & (~pd.isna(espn_events.event_player_1_name))]
358
+ espn_events = espn_events[(~pd.isna(espn_events.coords_x)) & (~pd.isna(espn_events.coords_y))]
360
359
 
361
360
  espn_events = espn_events.assign(
362
361
  coords_x = espn_events.coords_x.astype(int),
@@ -711,7 +710,7 @@ def combine_pbp(info):
711
710
  #Route data combining - json if season is after 2009-2010:
712
711
  if str(info['season']) in ['20052006','20062007','20072008','20082009','20092010']:
713
712
  #ESPN x HTML
714
- espn_pbp = parse_espn(str(info['game_date']),info['away_team_abbr'],info['home_team_abbr']).rename(columns={'coords_x':'x',"coords_y":'y'}).drop(columns=['event_player_1_name'])
713
+ espn_pbp = parse_espn(str(info['game_date']),info['away_team_abbr'],info['home_team_abbr']).rename(columns={'coords_x':'x',"coords_y":'y'})
715
714
  merge_col = ['period','seconds_elapsed','event_type','event_team_abbr']
716
715
 
717
716
  df = pd.merge(html_pbp,espn_pbp,how='left',on=merge_col)
@@ -38,6 +38,7 @@ def prep_xG_data(pbp):
38
38
  data.sort_values(['season','game_id','period','seconds_elapsed','event_num'],inplace=True)
39
39
  data['score_state'] = np.where(data['away_team_abbr']==data['event_team_abbr'],data['away_score']-data['home_score'],data['home_score']-data['away_score'])
40
40
  data['strength_diff'] = np.where(data['away_team_abbr']==data['event_team_abbr'],data['away_skaters']-data['home_skaters'],data['home_skaters']-data['away_skaters'])
41
+ data['strength_state_venue'] = data['away_skaters'].astype(str)+'v'+data['home_skaters'].astype(str)
41
42
  data['fenwick_state'] = np.where(data['away_team_abbr']==data['event_team_abbr'],data['away_fenwick']-data['home_fenwick'],data['home_fenwick']-data['away_fenwick'])
42
43
  data['distance_from_last'] = np.sqrt((data['x_fixed'] - data['x_fixed_last'])**2 + (data['y_fixed'] - data['y_fixed_last'])**2)
43
44
 
@@ -0,0 +1,114 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ import matplotlib
4
+ matplotlib.use('agg')
5
+ import matplotlib.pyplot as plt
6
+ import wsba_hockey as wsba
7
+ from gspread_pandas import Spread, Client
8
+ import urllib.request
9
+ from wand.color import Color
10
+ from wand.image import Image
11
+
12
+ season_load = wsba.repo_load_seasons()
13
+
14
+ def workspace(seasons,type,arg = '',start='',end=''):
15
+ if type == 'pbp':
16
+ #Scrape pbp
17
+ errors=[]
18
+ for season in seasons:
19
+ data = wsba.nhl_scrape_season(season,remove=[],local=True,errors=True)
20
+ errors.append(data['errors'])
21
+ data['pbp'].to_csv(f'pbp/nhl_pbp_{season}.csv',index=False)
22
+ print(f'Errors: {errors}')
23
+
24
+ elif type == 'convert':
25
+ for season in seasons:
26
+ data = pd.read_csv(f"pbp/nhl_pbp_{season}.csv")
27
+ data = wsba.wsba_main.moneypuck_xG(data)
28
+ data.to_parquet(f'pbp/parquet/nhl_pbp_{season}.parquet',index=False)
29
+
30
+ elif type == 'team_info':
31
+ #Scrape team info
32
+ stand = [wsba.nhl_scrape_standings(season) for season in seasons]
33
+ standings = pd.concat(stand)
34
+
35
+ colors = pd.read_csv('teaminfo/nhl_colors.csv')
36
+ data = pd.merge(colors,standings,how='right',left_on='triCode',right_on='teamAbbrev.default').sort_values(by=['seasonId','triCode'])
37
+ data['WSBA'] = data['teamAbbrev.default']+data['seasonId'].astype(str)
38
+
39
+ data.to_csv('teaminfo/nhl_teaminfo.csv',index=False)
40
+
41
+ elif type == 'stats':
42
+ #Stats building
43
+ stats = []
44
+ for season in seasons:
45
+ for group in ['skater','team']:
46
+ pbp = pd.read_parquet(f'pbp/parquet/nhl_pbp_{season}.parquet')
47
+ stat = wsba.nhl_calculate_stats(pbp,group,[2],['5v5'],shot_impact=True)
48
+ stat.to_csv(f'stats/{group}/wsba_nhl_{season}_{group}.csv',index=False)
49
+ stats.append(stat)
50
+ pd.concat(stats).to_csv(f'stats/db/wsba_nhl_{group}_db.csv',index=False)
51
+
52
+ elif type == 'plot_game':
53
+ for season in seasons:
54
+ pbp = wsba.nhl_scrape_season(season,remove=[],start=start,end=end)
55
+
56
+ plots = wsba.nhl_plot_games(pbp,wsba.wsba_main.fenwick_events,['5v5'],'all',team_colors=arg,legend=True)
57
+
58
+ games = list(pbp['game_id'].astype(str).drop_duplicates())
59
+ i = 1
60
+ for plot, game_id in zip(plots,games):
61
+ plot.savefig(f'plots/games/{game_id[0:4]}{int(game_id[0:4])+1}/{game_id[5:6]}/{game_id}_shotplot.png',bbox_inches='tight',transparent=True)
62
+ i += 1
63
+
64
+ elif type == 'plot_skater':
65
+ for season in seasons:
66
+ pbp = pd.read_parquet(f'pbp/parquet/nhl_pbp_{season}.parquet')
67
+
68
+ skaters={}
69
+
70
+ for shooter,season,team in zip(pbp['event_player_1_name'],pbp['season'].astype(str),pbp['event_team_abbr']):
71
+ if shooter is None:
72
+ continue
73
+ else:
74
+ skaters.update({
75
+ shooter:[season,team]
76
+ })
77
+
78
+ plots = wsba.nhl_plot_skaters_shots(pbp,skaters,['5v5'],onice='indv',title=False,legend=True)
79
+
80
+ items = list(skaters.items())
81
+ for plot,skater in zip(plots,items):
82
+ plot.savefig(f'plots/{skater[1][0]}/{skater[0]}{skater[1][0]}{skater[1][1]}_indv.png',bbox_inches='tight',transparent=True)
83
+
84
+ elif type == 'logos':
85
+ data = pd.read_csv('teaminfo/nhl_teaminfo.csv')
86
+ for url, id in zip(data['teamLogo'],data['WSBA']):
87
+ print(url)
88
+ urllib.request.urlretrieve(url,f'tools/logos/svg/{id}.svg')
89
+ with Image(filename=f'tools/logos/svg/{id}.svg') as img:
90
+ img.format = 'png32'
91
+ img.background_color = Color('transparent')
92
+ img.alpha_channel = 'activate'
93
+ img.save(filename=f'tools/logos/png/{id}.png')
94
+
95
+ else:
96
+ print('Nothing here.')
97
+
98
+ def push_to_sheet():
99
+ spread = Spread('WSBA - NHL 5v5 Shooting Metrics Public v2.0')
100
+
101
+ #Tables
102
+ skater = pd.read_csv('stats/db/wsba_nhl_skater_db.csv')
103
+ team = pd.read_csv('stats/db/wsba_nhl_team_db.csv')
104
+ team_info = pd.read_csv('teaminfo/nhl_teaminfo.csv')
105
+ country = pd.read_csv('teaminfo/nhl_countryinfo.csv')
106
+ schedule = pd.read_csv('schedule/schedule.csv')
107
+
108
+ spread.df_to_sheet(skater,index=False,sheet='Skaters DB')
109
+ spread.df_to_sheet(team,index=False,sheet='Teams DB')
110
+ spread.df_to_sheet(team_info,index=False,sheet='Team Info')
111
+ spread.df_to_sheet(country,index=False,sheet='Country Info')
112
+ spread.df_to_sheet(schedule,index=False,sheet='Schedule')
113
+
114
+ workspace(['20242025'],'plot_game',arg={'away':'secondary','home':'primary'}, start='04-20',end='04-20')
@@ -328,8 +328,7 @@ def nhl_scrape_season(season,split_shifts = False, season_types = [2,3], remove
328
328
  pbp_dict.update({'errors':data['errors']})
329
329
  return pbp_dict
330
330
  else:
331
- pbp = data['pbp']
332
-
331
+ pbp = data
333
332
  if errors:
334
333
  pbp_dict = {'pbp':pbp,
335
334
  'errors':data['errors']}
@@ -337,13 +336,6 @@ def nhl_scrape_season(season,split_shifts = False, season_types = [2,3], remove
337
336
  else:
338
337
  return pbp
339
338
 
340
- #errors = []
341
- #for season in seasons[10:12]:
342
- # data = nhl_scrape_season(season,remove=[],local=True,errors=True)
343
- # errors.append(data['errors'])
344
- # data['pbp'].to_csv(f'pbp/csv/nhl_pbp_{season}.csv',index=False)
345
- #print(f'Errors: {errors}')
346
-
347
339
  def nhl_scrape_seasons_info(seasons = []):
348
340
  #Returns info related to NHL seasons (by default, all seasons are included)
349
341
  # param 'season' - list of seasons to include
@@ -394,9 +386,6 @@ def nhl_scrape_standings(arg = "now", season_type = 2):
394
386
 
395
387
  return pd.json_normalize(data)
396
388
 
397
- #stand = [nhl_scrape_standings(season) for season in seasons]
398
- #pd.concat(stand).to_csv('teaminfo/nhl_standings.csv',index=False)
399
-
400
389
  def nhl_scrape_roster(season):
401
390
  #Given a nhl season, return rosters for all participating teams
402
391
  # param 'season' - NHL season to scrape
@@ -671,6 +660,12 @@ def nhl_calculate_stats(pbp,type,season_types,game_strength,roster_path="rosters
671
660
  #Filter by season types and remove shootouts
672
661
  pbp = pbp.loc[(pbp['season_type'].isin(season_types)) & (pbp['period'] < 5)]
673
662
 
663
+ #Convert all columns with player ids to float in order to avoid merging errors
664
+ for col in get_col():
665
+ if "_id" in col:
666
+ try: pbp[col] = pbp[col].astype(float)
667
+ except KeyError: continue
668
+
674
669
  # Filter by game strength if not "all"
675
670
  if game_strength != "all":
676
671
  pbp = pbp.loc[pbp['strength_state'].isin(game_strength)]
@@ -782,20 +777,14 @@ def nhl_calculate_stats(pbp,type,season_types,game_strength,roster_path="rosters
782
777
  else:
783
778
  return complete
784
779
 
785
- #stats = []
786
- #for season in seasons[6:18]:
787
- # pbp = pd.read_parquet(f'pbp/parquet/nhl_pbp_{season}.parquet')
788
- # stat = nhl_calculate_stats(pbp,'skater',[2],['5v5'],shot_impact=True)
789
- # stat.to_csv(f'stats/skater/wsba_nhl_{season}.csv',index=False)
790
- # stats.append(stat)
791
- #pd.concat(stats).to_csv('stats/db/wsba_nhl_skater_db.csv',index=False)
792
-
793
- def nhl_plot_skaters_shots(pbp,skater_dict,strengths,color_dict=event_colors,legend=False,xg='moneypuck'):
780
+ def nhl_plot_skaters_shots(pbp,skater_dict,strengths,marker_dict=event_markers,onice = 'indv',title = True,legend=False,xg='moneypuck'):
794
781
  #Returns list of plots for specified skaters
795
782
  # param 'pbp' - pbp to plot data
796
783
  # param 'skater_dict' - skaters to plot shots for (format: {'Patrice Bergeron':['20242025','BOS']})
797
784
  # param 'strengths' - strengths to include in plotting
798
- # param 'color_dict' - dict with colors to use for events
785
+ # param 'marker_dict' - dict with markers to use for events
786
+ # param 'onice' - can set which shots to include in plotting for the specified skater ('indv', 'for', 'against')
787
+ # param 'title' - bool including title when true
799
788
  # param 'legend' - bool which includes legend if true
800
789
  # param 'xg' - xG model to apply to pbp for plotting
801
790
 
@@ -805,19 +794,19 @@ def nhl_plot_skaters_shots(pbp,skater_dict,strengths,color_dict=event_colors,leg
805
794
  skater_plots = []
806
795
  for skater in skater_dict.keys():
807
796
  skater_info = skater_dict[skater]
808
- title = f'{skater} Fenwick Shots for {skater_info[1]} in {skater_info[0][2:4]}-{skater_info[0][6:8]}'
809
- skater_plots.append(plot_skater_shots(pbp,skater,skater_info[0],skater_info[1],strengths,title,color_dict,legend,xg))
797
+ title = f'{skater} Fenwick Shots for {skater_info[1]} in {skater_info[0][2:4]}-{skater_info[0][6:8]}' if title else ''
798
+ skater_plots.append(plot_skater_shots(pbp,skater,skater_info[0],skater_info[1],strengths,title,marker_dict,onice,legend,xg))
810
799
 
811
800
  #Return: list of plotted skater shot charts
812
801
  return skater_plots
813
802
 
814
- def nhl_plot_games(pbp,events,strengths,game_ids='all',color_dict=event_colors,legend=False,xg='moneypuck'):
803
+ def nhl_plot_games(pbp,events,strengths,game_ids='all',marker_dict=event_markers,team_colors={'away':'primary','home':'primary'},legend=False,xg='moneypuck'):
815
804
  #Returns list of plots for specified games
816
805
  # param 'pbp' - pbp to plot data
817
806
  # param 'events' - type of events to plot
818
807
  # param 'strengths' - strengths to include in plotting
819
808
  # param 'game_ids' - games to plot (list if not set to 'all')
820
- # param 'color_dict' - dict with colors to use for events
809
+ # param 'marker_dict' - dict with colors to use for events
821
810
  # param 'legend' - bool which includes legend if true
822
811
  # param 'xg' - xG model to apply to pbp for plotting
823
812
 
@@ -828,7 +817,7 @@ def nhl_plot_games(pbp,events,strengths,game_ids='all',color_dict=event_colors,l
828
817
  print(f'Plotting the following games: {game_ids}...')
829
818
 
830
819
  #Iterate through games, adding plot to list
831
- game_plots = [plot_game_events(pbp,game,events,strengths,color_dict,legend,xg) for game in game_ids]
820
+ game_plots = [plot_game_events(pbp,game,events,strengths,marker_dict,team_colors,legend,xg) for game in game_ids]
832
821
 
833
822
  #Return: list of plotted game events
834
823
  return game_plots
@@ -878,7 +867,3 @@ def admin_convert_to_parquet(seasons):
878
867
  load = pd.read_csv(f'pbp/csv/nhl_pbp_{season}.csv')
879
868
 
880
869
  load.to_parquet(f'pbp/parquet/nhl_pbp_{season}.parquet',index=False)
881
-
882
- #for season in seasons[6:12]:
883
- # data = pd.read_csv(f"pbp/csv/nhl_pbp_{season}.csv")
884
- # data.to_parquet(f'pbp/parquet/nhl_pbp_{season}.parquet',index=False)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wsba_hockey
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: WeakSide Breakout's complete Python package of access to hockey data, primairly including the scraping of National Hockey League schedule, play-by-play, and shifts information.
5
5
  Author-email: Owen Singh <owenbksingh@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/owensingh38/wsba_hockey/
@@ -78,7 +78,7 @@ skater_dict = {
78
78
  }
79
79
  pbp = wsba.nhl_scrape_season('20212022',remove=[], local = True)
80
80
 
81
- wsba.nhl_plot_skater_shots(pbp,skater_dict,['5v5'],legend=True)
81
+ wsba.nhl_plot_skaters_shots(pbp,skater_dict,['5v5'],onice='for',legend=True)
82
82
  wsba.nhl_plot_games(pbp,legend=True)
83
83
  ```
84
84
 
@@ -2,6 +2,7 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  src/wsba_hockey/__init__.py
5
+ src/wsba_hockey/workspace.py
5
6
  src/wsba_hockey/wsba_main.py
6
7
  src/wsba_hockey.egg-info/PKG-INFO
7
8
  src/wsba_hockey.egg-info/SOURCES.txt
@@ -1,113 +0,0 @@
1
- import matplotlib.pyplot as plt
2
- import matplotlib.image as img
3
- import numpy as np
4
- import pandas as pd
5
- pd.options.mode.chained_assignment = None
6
- from scipy.interpolate import griddata
7
- from scipy.ndimage import gaussian_filter
8
- from .xg_model import *
9
- from hockey_rink import NHLRink
10
- from hockey_rink import CircularImage
11
-
12
- event_colors = {
13
- 'faceoff':'black',
14
- 'hit':'yellow',
15
- 'blocked-shot':'pink',
16
- 'missed-shot':'red',
17
- 'shot-on-goal':'purple',
18
- 'goal':'blue',
19
- 'giveaway':'orange',
20
- 'takeaway':'green',
21
- }
22
-
23
- def wsba_rink(display_range='offense',rotation = 0):
24
- img = 'tools/utils/wsba.png'
25
- rink = NHLRink(center_logo={
26
- "feature_class": CircularImage,
27
- "image_path": img,
28
- "length": 25, "width": 25,
29
- "x": 0, "y": 0,
30
- "radius": 14,
31
- "zorder": 11,
32
- }
33
- )
34
- rink.draw(
35
- display_range=display_range,
36
- rotation=rotation,
37
- despine=True
38
- )
39
-
40
- def prep_plot_data(pbp,events,strengths,color_dict=event_colors,xg='moneypuck'):
41
- try: pbp['xG']
42
- except:
43
- if xg == 'wsba':
44
- pbp = wsba_xG(pbp)
45
- else:
46
- pbp = moneypuck_xG(pbp)
47
- pbp['xG'] = np.where(pbp['xG'].isna(),0,pbp['xG'])
48
-
49
- pbp['WSBA'] = pbp['event_player_1_name']+pbp['season'].astype(str)+pbp['event_team_abbr']
50
-
51
- pbp['x_plot'] = pbp['y_fixed']*-1
52
- pbp['y_plot'] = pbp['x_fixed']
53
-
54
- pbp['size'] = np.where(pbp['xG']<=0,100,pbp['xG']*1000)
55
- pbp['color'] = pbp['event_type'].replace(color_dict)
56
-
57
- pbp = pbp.loc[(pbp['event_type'].isin(events))&
58
- (pbp['event_distance']<=89)&
59
- (pbp['x_fixed']<=89)&
60
- (pbp['strength_state'].isin(strengths))]
61
-
62
- return pbp
63
-
64
- def league_shots(pbp,cord = 'fixed'):
65
- [x,y] = np.round(np.meshgrid(np.linspace(0,100,100),np.linspace(-42.5,42.5,85)))
66
- xgoals = griddata((pbp[f'x_{cord}'],pbp[f'y_{cord}']),pbp['xG'],(x,y),method='cubic',fill_value=0)
67
- xgoals_smooth = gaussian_filter(xgoals,sigma = 3)
68
-
69
- fig = plt.figure(figsize=(10,12), facecolor='w', edgecolor='k')
70
- plt.imshow(xgoals_smooth,origin = 'lower')
71
- plt.colorbar(orientation = 'horizontal', pad = 0.05)
72
- plt.title('xGoal Array',fontdict={'fontsize': 15})
73
- plt.show()
74
-
75
- return xgoals_smooth
76
-
77
-
78
- def plot_skater_shots(pbp, player, season, team, strengths, title = None, color_dict=event_colors, legend=False,xg='moneypuck'):
79
- shots = ['missed-shot','shot-on-goal','goal']
80
- pbp = prep_plot_data(pbp,shots,strengths,color_dict,xg)
81
- skater = pbp.loc[pbp['WSBA'] == f'{player.upper()}{season}{team}']
82
-
83
- fig, ax = plt.subplots()
84
- wsba_rink(rotation=90)
85
-
86
- for event in shots:
87
- plays = skater.loc[skater['event_type']==event]
88
- ax.scatter(plays['x_plot'],plays['y_plot'],plays['size'],plays['color'],label=event)
89
-
90
- ax.set_title(title) if title else ''
91
- ax.legend().set_visible(legend)
92
-
93
- return fig
94
-
95
- def plot_game_events(pbp,game_id,events,strengths,color_dict=event_colors,legend=False,xg='moneypuck'):
96
- pbp = prep_plot_data(pbp,events,strengths,color_dict,xg)
97
- pbp = pbp.loc[pbp['game_id'].astype(str)==game_id]
98
-
99
- away_abbr = list(pbp['away_team_abbr'])[0]
100
- home_abbr = list(pbp['home_team_abbr'])[0]
101
- date = list(pbp['game_date'])[0]
102
-
103
- fig, ax = plt.subplots()
104
- wsba_rink(display_range='full')
105
-
106
- for event in events:
107
- plays = pbp.loc[pbp['event_type']==event]
108
- ax.scatter(plays['x_adj'],plays['y_adj'],plays['size'],plays['color'],label=event)
109
-
110
- ax.set_title(f'{away_abbr} @ {home_abbr} - {date}')
111
- ax.legend(bbox_to_anchor =(0.5,-0.4), loc='lower center',ncol=1).set_visible(legend)
112
-
113
- return fig
File without changes
File without changes