wsba-hockey 1.1.0__py3-none-any.whl → 1.1.1__py3-none-any.whl
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.
- wsba_hockey/api/api/index.py +129 -0
- wsba_hockey/api/api/main.py +4 -0
- wsba_hockey/api/api/tools/__init__.py +0 -0
- wsba_hockey/api/api/tools/agg.py +374 -0
- wsba_hockey/api/api/tools/archive/old_scraping.py +1104 -0
- wsba_hockey/api/api/tools/plotting.py +144 -0
- wsba_hockey/api/api/tools/scraping.py +1000 -0
- wsba_hockey/api/api/tools/utils/__init__.py +1 -0
- wsba_hockey/api/api/tools/utils/config.py +14 -0
- wsba_hockey/api/api/tools/utils/save_pages.py +133 -0
- wsba_hockey/api/api/tools/utils/shared.py +450 -0
- wsba_hockey/api/api/tools/xg_model.py +455 -0
- wsba_hockey/api/api/wsba_main.py +1213 -0
- wsba_hockey/data_pipelines.py +71 -8
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/game_stats/app.py +6 -5
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/app.py +101 -0
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/plot.py +71 -0
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/rink_plot.py +245 -0
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/app.py +1 -1
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/plot.py +2 -0
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/rink_plot.py +1 -1
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/app.py +3 -3
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/plot.py +2 -0
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/rink_plot.py +1 -1
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/app.py +44 -28
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/plot.py +12 -3
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/rink_plot.py +1 -1
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/app.py +1 -1
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/plot.py +5 -4
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/rink_plot.py +1 -1
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/app.py +103 -0
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/plot.py +95 -0
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/rink_plot.py +245 -0
- wsba_hockey/flask/app.py +77 -0
- wsba_hockey/tools/plotting.py +2 -1
- wsba_hockey/tools/scraping.py +7 -3
- wsba_hockey/tools/xg_model.py +3 -3
- wsba_hockey/workspace.py +28 -12
- wsba_hockey/wsba_main.py +10 -17
- {wsba_hockey-1.1.0.dist-info → wsba_hockey-1.1.1.dist-info}/METADATA +1 -1
- {wsba_hockey-1.1.0.dist-info → wsba_hockey-1.1.1.dist-info}/RECORD +44 -24
- {wsba_hockey-1.1.0.dist-info → wsba_hockey-1.1.1.dist-info}/WHEEL +0 -0
- {wsba_hockey-1.1.0.dist-info → wsba_hockey-1.1.1.dist-info}/licenses/LICENSE +0 -0
- {wsba_hockey-1.1.0.dist-info → wsba_hockey-1.1.1.dist-info}/top_level.txt +0 -0
@@ -109,7 +109,7 @@ def server(input, output, session):
|
|
109
109
|
query = reactive.Value(None)
|
110
110
|
|
111
111
|
def schedule():
|
112
|
-
schedule = pd.read_csv('https://
|
112
|
+
schedule = pd.read_csv('https://weakside-breakout.s3.us-east-2.amazonaws.com/info/schedule.csv')
|
113
113
|
|
114
114
|
return schedule.loc[schedule['gameState'].isin(['OFF','FINAL'])]
|
115
115
|
|
@@ -126,7 +126,8 @@ def server(input, output, session):
|
|
126
126
|
'event_type':['missed-shot,shot-on-goal,goal'],
|
127
127
|
'strength_state':['all'],
|
128
128
|
'filters':['false'],
|
129
|
-
'table':['false']
|
129
|
+
'table':['false'],
|
130
|
+
'title':['true']
|
130
131
|
}
|
131
132
|
|
132
133
|
for key in defaults.keys():
|
@@ -223,7 +224,7 @@ def server(input, output, session):
|
|
223
224
|
front_year = int(query['game_id'][0][0:4])
|
224
225
|
season = f'{front_year}{front_year+1}'
|
225
226
|
#Load appropriate dataframe
|
226
|
-
df = pd.read_parquet(f'https://
|
227
|
+
df = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/pbp/{season}.parquet')
|
227
228
|
|
228
229
|
#Prepare dataframe for plotting based on URL parameters
|
229
230
|
game_data = df.loc[df['game_id'].astype(str).isin(query['game_id'])].replace({np.nan: None})
|
@@ -255,7 +256,7 @@ def server(input, output, session):
|
|
255
256
|
color='Team',
|
256
257
|
color_discrete_map=colors,
|
257
258
|
hover_name='Description',
|
258
|
-
hover_data=['Event Num.', 'Period', 'Time (in
|
259
|
+
hover_data=['Event Num.', 'Period', 'Time (in Period)',
|
259
260
|
'Strength',
|
260
261
|
'Away Score', 'Home Score', 'x', 'y',
|
261
262
|
'Event Distance from Attacking Net',
|
@@ -265,28 +266,44 @@ def server(input, output, session):
|
|
265
266
|
for trace in plot.data:
|
266
267
|
rink.add_trace(trace)
|
267
268
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
orientation='h',
|
279
|
-
x=0.49,
|
280
|
-
y=-0.04,
|
281
|
-
xanchor='center',
|
282
|
-
yanchor='bottom',
|
283
|
-
font=dict(color='white')
|
284
|
-
),
|
269
|
+
if active_params()['title'][0]=='false':
|
270
|
+
return rink.update_layout(
|
271
|
+
legend=dict(
|
272
|
+
orientation='h',
|
273
|
+
x=0.49,
|
274
|
+
y=-0.04,
|
275
|
+
xanchor='center',
|
276
|
+
yanchor='bottom',
|
277
|
+
font=dict(color='white')
|
278
|
+
),
|
285
279
|
|
286
|
-
|
287
|
-
|
280
|
+
hoverlabel=dict(
|
281
|
+
font_size=10
|
282
|
+
)
|
283
|
+
)
|
284
|
+
else:
|
285
|
+
return rink.update_layout(
|
286
|
+
title=dict(
|
287
|
+
text=game_title,
|
288
|
+
x=0.5, y=0.94,
|
289
|
+
xanchor='center',
|
290
|
+
yanchor='top',
|
291
|
+
font=dict(color='white')
|
292
|
+
),
|
293
|
+
|
294
|
+
legend=dict(
|
295
|
+
orientation='h',
|
296
|
+
x=0.49,
|
297
|
+
y=-0.04,
|
298
|
+
xanchor='center',
|
299
|
+
yanchor='bottom',
|
300
|
+
font=dict(color='white')
|
301
|
+
),
|
302
|
+
|
303
|
+
hoverlabel=dict(
|
304
|
+
font_size=10
|
305
|
+
)
|
288
306
|
)
|
289
|
-
)
|
290
307
|
|
291
308
|
@output
|
292
309
|
@render.ui
|
@@ -322,10 +339,9 @@ def server(input, output, session):
|
|
322
339
|
if input.metric_select()=='Timelines':
|
323
340
|
return None
|
324
341
|
else:
|
325
|
-
df = game_df.get().copy()[['event_num','period','
|
342
|
+
df = game_df.get().copy()[['event_num','period','Time (in Period)','strength_state','event_type','Description','event_team_abbr','event_player_1_name','shot_type','zone_code','x','y','away_score','home_score','xG']].rename(columns={
|
326
343
|
'event_num':'#',
|
327
344
|
'period':'Period',
|
328
|
-
'seconds_elapsed':'Seconds',
|
329
345
|
'strength_state':'Strength State',
|
330
346
|
'event_type':'Event',
|
331
347
|
'event_team_abbr':'Team',
|
@@ -352,7 +368,7 @@ def server(input, output, session):
|
|
352
368
|
data = wsba_plt.timelines(game_df.get().copy())
|
353
369
|
colors = wsba_plt.colors(data)
|
354
370
|
timelines = px.line(data,
|
355
|
-
x='Time (in
|
371
|
+
x='Time (in Period)',
|
356
372
|
y=input.timeline_select(),
|
357
373
|
color='Team',
|
358
374
|
color_discrete_map=colors,
|
@@ -368,7 +384,7 @@ def server(input, output, session):
|
|
368
384
|
paper_bgcolor="rgba(0,0,0,0)",
|
369
385
|
plot_bgcolor="rgba(0,0,0,0)",
|
370
386
|
font_color='white',
|
371
|
-
xaxis=dict(title=dict(text='Time (in
|
387
|
+
xaxis=dict(title=dict(text='Time (in Period)'),showgrid=False),
|
372
388
|
yaxis=dict(title=dict(text=input.timeline_select()),showgrid=False),
|
373
389
|
|
374
390
|
legend=dict(
|
@@ -23,7 +23,7 @@ def colors(df):
|
|
23
23
|
away_abbr = list(df['away_team_abbr'])[0]
|
24
24
|
home_abbr = list(df['home_team_abbr'])[0]
|
25
25
|
season = list(df['season'])[0]
|
26
|
-
team_data = pd.read_csv('https://
|
26
|
+
team_data = pd.read_csv('https://weakside-breakout.s3.us-east-2.amazonaws.com/info/nhl_teaminfo.csv')
|
27
27
|
|
28
28
|
team_info ={
|
29
29
|
away_abbr: list(team_data.loc[team_data['WSBA']==f'{away_abbr}{season}','Primary Color'])[0],
|
@@ -32,13 +32,21 @@ def colors(df):
|
|
32
32
|
|
33
33
|
return team_info
|
34
34
|
|
35
|
+
def convert_time(seconds,period):
|
36
|
+
period_seconds = seconds - ((period-1)*1200)
|
37
|
+
minutes = int(period_seconds/60)
|
38
|
+
seconds = int(((period_seconds/60)-minutes)*60)
|
39
|
+
|
40
|
+
return f'{minutes}:{seconds:02}'
|
41
|
+
|
35
42
|
def prep(df,events,strengths):
|
36
43
|
df = df.loc[(df['event_type'].isin(events))]
|
37
|
-
|
44
|
+
|
45
|
+
df['strength_state'] = np.where(df['strength_state'].isin(['5v5','5v4','4v5']),df['strength_state'],'Other')
|
38
46
|
if 'all' not in strengths:
|
39
47
|
df = df.loc[((df['strength_state'].isin(strengths)))]
|
40
48
|
|
41
|
-
df
|
49
|
+
df = df.fillna(0)
|
42
50
|
df['size'] = np.where(df['xG']<=0,40,df['xG']*400)
|
43
51
|
|
44
52
|
df['marker'] = df['event_type'].replace(event_markers)
|
@@ -48,6 +56,7 @@ def prep(df,events,strengths):
|
|
48
56
|
df['Event Num.'] = df['event_num']
|
49
57
|
df['Period'] = df['period']
|
50
58
|
df['Time (in seconds)'] = df['seconds_elapsed']
|
59
|
+
df['Time (in Period)'] = df.apply(lambda x: convert_time(x['Time (in seconds)'],x['Period']), axis=1)
|
51
60
|
df['Strength'] = df['strength_state']
|
52
61
|
df['Away Score'] = df['away_score']
|
53
62
|
df['Home Score'] = df['home_score']
|
@@ -222,7 +222,7 @@ def rink(setting = "full", vertical = False):
|
|
222
222
|
)
|
223
223
|
|
224
224
|
# Add logo
|
225
|
-
logo = Image.open(rs.get('https://
|
225
|
+
logo = Image.open(rs.get('https://weakside-breakout.s3.us-east-2.amazonaws.com/utils/wsba.png',stream=True).raw)
|
226
226
|
|
227
227
|
fig.add_layout_image(
|
228
228
|
dict(
|
@@ -46,7 +46,7 @@ def server(input, output, session):
|
|
46
46
|
#Determine which season to load based on the input
|
47
47
|
season = query['season'][0]
|
48
48
|
#Load appropriate dataframe
|
49
|
-
df = pd.read_parquet(f'https://
|
49
|
+
df = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/pbp/{season}.parquet')
|
50
50
|
|
51
51
|
#Prepare dataframe for plotting based on URL parameters
|
52
52
|
df = df.loc[(df['event_player_1_id'].astype(str).str.replace('.0','').isin(query['skater']))&(df['season'].astype(str).isin(query['season']))&(df['event_team_abbr'].astype(str).isin(query['team']))&(df['season_type'].astype(str).isin(query['season_type']))].replace({np.nan: None})
|
@@ -20,9 +20,9 @@ def wsba_rink(setting='full', vertical=False):
|
|
20
20
|
return rink_plot.rink(setting=setting, vertical=vertical)
|
21
21
|
|
22
22
|
def colors(df):
|
23
|
-
team = list(df['
|
23
|
+
team = list(df['event_team_abbr'])[0]
|
24
24
|
season = list(df['season'])[0]
|
25
|
-
team_data = pd.read_csv('https://
|
25
|
+
team_data = pd.read_csv('https://weakside-breakout.s3.us-east-2.amazonaws.com/info/nhl_teaminfo.csv')
|
26
26
|
|
27
27
|
team_info ={
|
28
28
|
team: list(team_data.loc[team_data['WSBA']==f'{team}{season}','Primary Color'])[0],
|
@@ -37,7 +37,7 @@ def prep(df,events,strengths):
|
|
37
37
|
if strengths != 'all':
|
38
38
|
df = df.loc[((df['strength_state'].isin(strengths)))]
|
39
39
|
|
40
|
-
df
|
40
|
+
df = df.fillna(0)
|
41
41
|
df['size'] = np.where(df['xG']<=0,40,df['xG']*400)
|
42
42
|
|
43
43
|
df['marker'] = df['event_type'].replace(event_markers)
|
@@ -50,9 +50,10 @@ def prep(df,events,strengths):
|
|
50
50
|
df['Strength'] = df['strength_state']
|
51
51
|
df['Away Score'] = df['away_score']
|
52
52
|
df['Home Score'] = df['home_score']
|
53
|
-
df['x'] = np.where(df['x_adj']<0
|
53
|
+
df['x'] = np.where(df['x_adj']<0,df['y_adj'],-df['y_adj'])
|
54
54
|
df['y'] = abs(df['x_adj'])
|
55
55
|
df['Event Distance from Attacking Net'] = df['event_distance']
|
56
56
|
df['Event Angle to Attacking Net'] = df['event_angle']
|
57
57
|
df['xG'] = df['xG']*100
|
58
|
+
|
58
59
|
return df
|
@@ -222,7 +222,7 @@ def rink(setting = "full", vertical = False):
|
|
222
222
|
)
|
223
223
|
|
224
224
|
# Add logo
|
225
|
-
logo = Image.open(rs.get('https://
|
225
|
+
logo = Image.open(rs.get('https://weakside-breakout.s3.us-east-2.amazonaws.com/utils/wsba.png',stream=True).raw)
|
226
226
|
|
227
227
|
fig.add_layout_image(
|
228
228
|
dict(
|
@@ -0,0 +1,103 @@
|
|
1
|
+
import pandas as pd
|
2
|
+
import plot as wsba_plt
|
3
|
+
import numpy as np
|
4
|
+
from urllib.parse import *
|
5
|
+
from shiny import *
|
6
|
+
from shinywidgets import output_widget, render_widget
|
7
|
+
|
8
|
+
app_ui = ui.page_fluid(
|
9
|
+
ui.tags.style(
|
10
|
+
"body {background:#09090b"
|
11
|
+
"}"
|
12
|
+
),
|
13
|
+
output_widget("plot_skater"),
|
14
|
+
)
|
15
|
+
|
16
|
+
def server(input, output, session):
|
17
|
+
@output()
|
18
|
+
@render_widget
|
19
|
+
def plot_skater():
|
20
|
+
#Retreive query parameters
|
21
|
+
search = session.input[".clientdata_url_search"]()
|
22
|
+
query = parse_qs(urlparse(search).query)
|
23
|
+
|
24
|
+
print(query)
|
25
|
+
#If no input data is provided automatically provide a select skater and plot all 5v5 fenwick shots
|
26
|
+
defaults = {
|
27
|
+
'team':['BOS'],
|
28
|
+
'season':['20222023'],
|
29
|
+
'strength_state':['5v5'],
|
30
|
+
'season_type':['2']
|
31
|
+
}
|
32
|
+
|
33
|
+
for key in defaults.keys():
|
34
|
+
if key not in query.keys():
|
35
|
+
query.update({key:defaults[key]})
|
36
|
+
|
37
|
+
#Iterate through query and parse params with multiple selections
|
38
|
+
for param in query.keys():
|
39
|
+
q_string = query[param][0]
|
40
|
+
query[param] = q_string.split(',')
|
41
|
+
|
42
|
+
print(query)
|
43
|
+
#Determine which season to load based on the input
|
44
|
+
season = query['season'][0]
|
45
|
+
#Load appropriate dataframe
|
46
|
+
df = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/pbp/{season}.parquet')
|
47
|
+
|
48
|
+
#Prepare dataframe for plotting based on URL parameters
|
49
|
+
df = df.loc[(df['season'].astype(str).isin(query['season']))&(df['season_type'].astype(str).isin(query['season_type']))].replace({np.nan: None})
|
50
|
+
#Return empty rink if no data exists else continue
|
51
|
+
if df.empty:
|
52
|
+
return wsba_plt.wsba_rink()
|
53
|
+
else:
|
54
|
+
rink = wsba_plt.wsba_rink()
|
55
|
+
|
56
|
+
try:
|
57
|
+
for_plot = wsba_plt.heatmap(df,team=query['team'][0],events=['missed-shot','shot-on-goal','goal'],strengths=query['strength_state'],onice='for')
|
58
|
+
against_plot = wsba_plt.heatmap(df,team=query['team'][0],events=['missed-shot','shot-on-goal','goal'],strengths=query['strength_state'],onice='against')
|
59
|
+
|
60
|
+
for trace in for_plot.data:
|
61
|
+
rink.add_trace(trace)
|
62
|
+
|
63
|
+
for trace in against_plot.data:
|
64
|
+
rink.add_trace(trace)
|
65
|
+
|
66
|
+
season = int(season[0:4])
|
67
|
+
team = query['team'][0]
|
68
|
+
strengths = 'All Situations' if len(query['strength_state']) == 4 else query['strength_state']
|
69
|
+
span = 'Regular Season' if query['season_type'][0]=='2' else 'Playoffs'
|
70
|
+
|
71
|
+
return rink.update_layout(
|
72
|
+
title=dict(
|
73
|
+
text=f'{team} On-Ice xG at {strengths}; {season}-{season+1}, {span}',
|
74
|
+
x=0.5, y=0.96,
|
75
|
+
xanchor='center',
|
76
|
+
yanchor='top',
|
77
|
+
font=dict(color='white')
|
78
|
+
),
|
79
|
+
).add_annotation(
|
80
|
+
text='Lower xG',
|
81
|
+
xref="paper",
|
82
|
+
yref="paper",
|
83
|
+
xanchor='right',
|
84
|
+
yanchor='top',
|
85
|
+
font=dict(color='white'),
|
86
|
+
x=0.3,
|
87
|
+
y=0.04,
|
88
|
+
showarrow=False
|
89
|
+
).add_annotation(
|
90
|
+
text='Higher xG',
|
91
|
+
xref="paper",
|
92
|
+
yref="paper",
|
93
|
+
xanchor='right',
|
94
|
+
yanchor='top',
|
95
|
+
font=dict(color='white'),
|
96
|
+
x=0.76,
|
97
|
+
y=0.04,
|
98
|
+
showarrow=False
|
99
|
+
)
|
100
|
+
except:
|
101
|
+
return wsba_plt.wsba_rink()
|
102
|
+
|
103
|
+
app = App(app_ui, server)
|
@@ -0,0 +1,95 @@
|
|
1
|
+
import pandas as pd
|
2
|
+
import numpy as np
|
3
|
+
import plotly.graph_objects as go
|
4
|
+
import matplotlib.pyplot as plt
|
5
|
+
import rink_plot
|
6
|
+
from scipy.interpolate import griddata
|
7
|
+
from scipy.ndimage import gaussian_filter
|
8
|
+
|
9
|
+
def wsba_rink(setting='full', vertical=False):
|
10
|
+
return rink_plot.rink(setting=setting, vertical=vertical)
|
11
|
+
|
12
|
+
def heatmap(df,team,events,strengths,onice):
|
13
|
+
df['event_team_abbr_2'] = np.where(df['home_team_abbr']==df['event_team_abbr'],df['away_team_abbr'],df['home_team_abbr'])
|
14
|
+
df['strength_state_2'] = df['strength_state'].str[::-1]
|
15
|
+
|
16
|
+
df = df.fillna(0)
|
17
|
+
df = df.loc[(df['event_type'].isin(events))&(df['x_adj'].notna())&(df['y_adj'].notna())]
|
18
|
+
if onice == 'for':
|
19
|
+
df['x'] = abs(df['x_adj'])
|
20
|
+
df['y'] = np.where(df['x_adj']<0,-df['y_adj'],df['y_adj'])
|
21
|
+
df['event_distance'] = abs(df['event_distance'].fillna(0))
|
22
|
+
df = df.loc[(df['event_distance']<=89)&(df['x']<=89)&(df['empty_net']==0)]
|
23
|
+
|
24
|
+
x_min = 0
|
25
|
+
x_max = 100
|
26
|
+
else:
|
27
|
+
df['x'] = -abs(df['x_adj'])
|
28
|
+
df['y'] = np.where(df['x_adj']>0,-df['y_adj'],df['y_adj'])
|
29
|
+
df['event_distance'] = -abs(df['event_distance'])
|
30
|
+
df = df.loc[(df['event_distance']>-89)&(df['x']>-89)&(df['empty_net']==0)]
|
31
|
+
|
32
|
+
x_min = -100
|
33
|
+
x_max = 0
|
34
|
+
|
35
|
+
df['home_on_ice'] = df['home_on_1_id'].astype(str) + ";" + df['home_on_2_id'].astype(str) + ";" + df['home_on_3_id'].astype(str) + ";" + df['home_on_4_id'].astype(str) + ";" + df['home_on_5_id'].astype(str) + ";" + df['home_on_6_id'].astype(str)
|
36
|
+
df['away_on_ice'] = df['away_on_1_id'].astype(str) + ";" + df['away_on_2_id'].astype(str) + ";" + df['away_on_3_id'].astype(str) + ";" + df['away_on_4_id'].astype(str) + ";" + df['away_on_5_id'].astype(str) + ";" + df['away_on_6_id'].astype(str)
|
37
|
+
|
38
|
+
df['onice_for'] = np.where(df['home_team_abbr']==df['event_team_abbr'],df['home_on_ice'],df['away_on_ice'])
|
39
|
+
df['onice_against'] = np.where(df['away_team_abbr']==df['event_team_abbr'],df['home_on_ice'],df['away_on_ice'])
|
40
|
+
|
41
|
+
df['strength_state'] = np.where(df['strength_state'].isin(['5v5','5v4','4v5']),df['strength_state'],'Other')
|
42
|
+
df['strength_state_2'] = np.where(df['strength_state_2'].isin(['5v5','5v4','4v5']),df['strength_state_2'],'Other')
|
43
|
+
|
44
|
+
if strengths != 'all':
|
45
|
+
if onice == 'against':
|
46
|
+
df = df.loc[((df['strength_state_2'].isin(strengths)))]
|
47
|
+
else:
|
48
|
+
df = df.loc[((df['strength_state'].isin(strengths)))]
|
49
|
+
|
50
|
+
[x,y] = np.round(np.meshgrid(np.linspace(x_min,x_max,(x_max-x_min)),np.linspace(-42.5,42.5,85)))
|
51
|
+
xgoals = griddata((df['x'],df['y']),df['xG'],(x,y),method='cubic',fill_value=0)
|
52
|
+
xgoals = np.where(xgoals < 0,0,xgoals)
|
53
|
+
xgoals_smooth = gaussian_filter(xgoals,sigma=3)
|
54
|
+
|
55
|
+
if onice == 'for':
|
56
|
+
player_shots = df.loc[(df['event_team_abbr']==team)]
|
57
|
+
else:
|
58
|
+
player_shots = df.loc[(df['event_team_abbr_2']==team)]
|
59
|
+
[x,y] = np.round(np.meshgrid(np.linspace(x_min,x_max,(x_max-x_min)),np.linspace(-42.5,42.5,85)))
|
60
|
+
xgoals_player = griddata((player_shots['x'],player_shots['y']),player_shots['xG'],(x,y),method='cubic',fill_value=0)
|
61
|
+
xgoals_player = np.where(xgoals_player < 0,0,xgoals_player)
|
62
|
+
|
63
|
+
difference = (gaussian_filter(xgoals_player,sigma = 3)) - xgoals_smooth
|
64
|
+
data_min= difference.min()
|
65
|
+
data_max= difference.max()
|
66
|
+
|
67
|
+
if abs(data_min) > data_max:
|
68
|
+
data_max = data_min * -1
|
69
|
+
elif data_max > abs(data_min):
|
70
|
+
data_min = data_max * -1
|
71
|
+
|
72
|
+
fig = go.Figure(
|
73
|
+
data = go.Contour( x=np.linspace(x_min,x_max,(x_max-x_min)),
|
74
|
+
y=np.linspace(-42.5,42.5,85),
|
75
|
+
z=difference,
|
76
|
+
colorscale=[[0.0,'red'],[0.5,'#09090b'],[1.0,'blue']],
|
77
|
+
connectgaps=True,
|
78
|
+
contours=dict(
|
79
|
+
type='levels',
|
80
|
+
start = data_min,
|
81
|
+
end = data_max,
|
82
|
+
size=(data_max-data_min)/11
|
83
|
+
),
|
84
|
+
colorbar=dict(
|
85
|
+
len = 0.7,
|
86
|
+
orientation='h',
|
87
|
+
showticklabels=False,
|
88
|
+
thickness=15,
|
89
|
+
yref='paper',
|
90
|
+
yanchor='top',
|
91
|
+
y=0
|
92
|
+
))
|
93
|
+
)
|
94
|
+
|
95
|
+
return fig
|