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
@@ -0,0 +1,245 @@
|
|
1
|
+
|
2
|
+
import numpy as np
|
3
|
+
import plotly.graph_objects as go
|
4
|
+
import io
|
5
|
+
import base64
|
6
|
+
import requests as rs
|
7
|
+
from PIL import Image
|
8
|
+
|
9
|
+
def rink(setting = "full", vertical = False):
|
10
|
+
'''
|
11
|
+
Function to plot rink in Plotly. Takes 2 arguments :
|
12
|
+
|
13
|
+
setting : full (default) for full ice, offense positive half of the ice, ozone positive quarter of ice, defense for negative half of the ice, dzone for negative quarter of the ice, and neutral for the neutral zone
|
14
|
+
vertical : True if you want a vertical rink, False (default) is for an horizontal rink
|
15
|
+
|
16
|
+
'''
|
17
|
+
|
18
|
+
def faceoff_circle(x, y, outer=True):
|
19
|
+
segments = []
|
20
|
+
theta = np.linspace(0, 2*np.pi, 300)
|
21
|
+
if outer:
|
22
|
+
# Outer circle
|
23
|
+
x_outer = x + 15*np.cos(theta)
|
24
|
+
y_outer = y + 15*np.sin(theta)
|
25
|
+
outer_circle = go.Scatter(x=x_outer, y=y_outer, mode='lines', line=dict(width=2, color='red'), showlegend=False, hoverinfo='skip')
|
26
|
+
|
27
|
+
segments.append(outer_circle)
|
28
|
+
|
29
|
+
# Inner circle
|
30
|
+
x_inner = x + np.cos(theta)
|
31
|
+
y_inner = y + np.sin(theta)
|
32
|
+
inner_circle = go.Scatter(x=x_inner, y=y_inner, mode='lines', fill='toself', fillcolor='rgba(255, 0, 0, 0.43)', line=dict(color='rgba(255, 0, 0, 1)', width=2), showlegend=False, hoverinfo='skip')
|
33
|
+
|
34
|
+
segments.append(inner_circle)
|
35
|
+
|
36
|
+
return segments #segments
|
37
|
+
|
38
|
+
fig = go.Figure()
|
39
|
+
|
40
|
+
if vertical :
|
41
|
+
setting_dict = {
|
42
|
+
"full" : [-101, 101],
|
43
|
+
"offense" : [0, 101],
|
44
|
+
"ozone" : [25, 101],
|
45
|
+
"defense" : [-101, 0],
|
46
|
+
"dzone" : [-101, -25],
|
47
|
+
"neutral" : [-25,25]
|
48
|
+
}
|
49
|
+
fig.update_layout(xaxis=dict(range=[-42.6, 42.6], showgrid=False, zeroline=False, showticklabels=False, constrain="domain"), yaxis=dict(range=setting_dict[setting], showgrid=False, zeroline=False, showticklabels=False, constrain="domain"),
|
50
|
+
showlegend=False, autosize=True, template="plotly_white")
|
51
|
+
fig.update_yaxes(
|
52
|
+
scaleanchor="x",
|
53
|
+
scaleratio=1,
|
54
|
+
)
|
55
|
+
def goal_crease(flip=1):
|
56
|
+
x_seq = np.linspace(-4, 4, 100)
|
57
|
+
x_goal = np.concatenate(([-4], x_seq, [4]))
|
58
|
+
y_goal = flip * np.concatenate(([89], 83 + x_seq**2/4**2*1.5, [89]))
|
59
|
+
goal_crease = go.Scatter(x=x_goal, y=y_goal, fill='toself', fillcolor='rgba(173, 216, 230, 0.3)', line=dict(color='red'))
|
60
|
+
return goal_crease
|
61
|
+
|
62
|
+
# Outer circle
|
63
|
+
theta = np.linspace(0, 2*np.pi, 300)
|
64
|
+
x_outer = 15 * np.cos(theta)
|
65
|
+
y_outer = 15 * np.sin(theta)
|
66
|
+
fig.add_trace(go.Scatter(x=x_outer, y=y_outer, mode='lines', line=dict(color='royalblue', width=2), showlegend=False, hoverinfo='skip'))
|
67
|
+
# Inner circle
|
68
|
+
theta2 = np.linspace(np.pi/2, 3*np.pi/2, 300)
|
69
|
+
x_inner = 42.5 + 10 * np.cos(theta2)
|
70
|
+
y_inner = 10 * np.sin(theta2)
|
71
|
+
fig.add_trace(go.Scatter(x=x_inner, y=y_inner, mode='lines', line=dict(color='red', width=2), showlegend=False, hoverinfo='skip'))
|
72
|
+
# Rink boundaries
|
73
|
+
fig.add_shape(type='rect', xref='x', yref='y', x0=-42.5, y0=25, x1=42.5, y1=26, line=dict(color='royalblue', width=1), fillcolor='royalblue', opacity=1)
|
74
|
+
fig.add_shape(type='rect', xref='x', yref='y', x0=-42.5, y0=-25, x1=42.5, y1=-26, line=dict(color='royalblue', width=1), fillcolor='royalblue', opacity=1)
|
75
|
+
fig.add_shape(type='rect', xref='x', yref='y', x0=-42.5, y0=-0.5, x1=42.5, y1=0.5, line=dict(color='red', width=2), fillcolor='red')
|
76
|
+
|
77
|
+
# Goal crease
|
78
|
+
fig.add_trace(goal_crease())
|
79
|
+
fig.add_trace(goal_crease(-1))
|
80
|
+
# Goal lines
|
81
|
+
goal_line_extreme = 42.5 - 28 + np.sqrt(28**2 - (28-11)**2)
|
82
|
+
fig.add_shape(type='line', xref='x', yref='y', x0=-goal_line_extreme, y0=89, x1=goal_line_extreme, y1=89, line=dict(color='red', width=2))
|
83
|
+
fig.add_shape(type='line', xref='x', yref='y', x0=-goal_line_extreme, y0=-89, x1=goal_line_extreme, y1=-89, line=dict(color='red', width=2))
|
84
|
+
|
85
|
+
# Faceoff circles
|
86
|
+
fig.add_traces(faceoff_circle(-22, 69))
|
87
|
+
fig.add_traces(faceoff_circle(22, 69))
|
88
|
+
fig.add_traces(faceoff_circle(-22, -69))
|
89
|
+
fig.add_traces(faceoff_circle(22, -69))
|
90
|
+
fig.add_traces(faceoff_circle(-22, -20, False))
|
91
|
+
fig.add_traces(faceoff_circle(22, -20, False))
|
92
|
+
fig.add_traces(faceoff_circle(-22, 20, False))
|
93
|
+
fig.add_traces(faceoff_circle(22, 20, False))
|
94
|
+
|
95
|
+
# Sidelines
|
96
|
+
theta_lines = np.linspace(0, np.pi/2, 20)
|
97
|
+
x_lines1 = np.concatenate(([-42.5], -42.5 + 28 - 28*np.cos(theta_lines), 42.5 - 28 + 28*np.cos(np.flip(theta_lines))))
|
98
|
+
y_lines1 = np.concatenate(([15], 72 + 28*np.sin(theta_lines), 72 + 28*np.sin(np.flip(theta_lines))))
|
99
|
+
x_lines2 = np.concatenate(([-42.5], -42.5 + 28 - 28*np.cos(theta_lines), 42.5 - 28 + 28*np.cos(np.flip(theta_lines))))
|
100
|
+
y_lines2 = np.concatenate(([15], -72 - 28*np.sin(theta_lines), -72 - 28*np.sin(np.flip(theta_lines))))
|
101
|
+
fig.add_trace(go.Scatter(x=x_lines1, y=y_lines1, mode='lines', line=dict(color='white', width=2), showlegend=False, hoverinfo='skip'))
|
102
|
+
fig.add_trace(go.Scatter(x=x_lines2, y=y_lines2, mode='lines', line=dict(color='white', width=2), showlegend=False, hoverinfo='skip'))
|
103
|
+
fig.add_shape(type='line', xref='x', yref='y', x0=42.5, y0=-72.5, x1=42.5, y1=72.5, line=dict(color='white', width=2))
|
104
|
+
fig.add_shape(type='line', xref='x', yref='y', x0=-42.5, y0=-72.5, x1=-42.5, y1=72.5, line=dict(color='white', width=2))
|
105
|
+
|
106
|
+
# Add goals
|
107
|
+
goal_width = 6 # feet
|
108
|
+
goal_depth = 4 # feet
|
109
|
+
|
110
|
+
# Top goal
|
111
|
+
fig.add_shape(
|
112
|
+
type="rect",
|
113
|
+
xref="x",
|
114
|
+
yref="y",
|
115
|
+
x0=-goal_width / 2,
|
116
|
+
y0=89,
|
117
|
+
x1=goal_width / 2,
|
118
|
+
y1=89 + goal_depth,
|
119
|
+
line=dict(color="red", width=2),
|
120
|
+
)
|
121
|
+
# Bottom goal
|
122
|
+
fig.add_shape(
|
123
|
+
type="rect",
|
124
|
+
xref="x",
|
125
|
+
yref="y",
|
126
|
+
x0=-goal_width / 2,
|
127
|
+
y0=-89 - goal_depth,
|
128
|
+
x1=goal_width / 2,
|
129
|
+
y1=-89,
|
130
|
+
line=dict(color="red", width=2),
|
131
|
+
)
|
132
|
+
|
133
|
+
else :
|
134
|
+
setting_dict = {
|
135
|
+
"full" : [-101, 101],
|
136
|
+
"offense" : [0, 101],
|
137
|
+
"ozone" : [25, 101],
|
138
|
+
"defense" : [-101, 0],
|
139
|
+
"dzone" : [-101, -25]
|
140
|
+
}
|
141
|
+
fig.update_layout(xaxis=dict(range=setting_dict[setting], showgrid=False, zeroline=False, showticklabels=False), yaxis=dict(range=[-42.6, 42.6], showgrid=False, zeroline=False, showticklabels=False, constrain="domain"),
|
142
|
+
showlegend=True, autosize =True, template="plotly_white")
|
143
|
+
fig.update_yaxes(
|
144
|
+
scaleanchor="x",
|
145
|
+
scaleratio=1,
|
146
|
+
)
|
147
|
+
def goal_crease(flip=1):
|
148
|
+
y_seq = np.linspace(-4, 4, 100)
|
149
|
+
y_goal = np.concatenate(([-4], y_seq, [4]))
|
150
|
+
x_goal = flip * np.concatenate(([89], 83 + y_seq**2/4**2*1.5, [89]))
|
151
|
+
goal_crease = go.Scatter(x=x_goal, y=y_goal, fill='toself', fillcolor='rgba(173, 216, 230, 0.3)', line=dict(color='red'), showlegend=False, hoverinfo='skip')
|
152
|
+
return goal_crease
|
153
|
+
|
154
|
+
# Outer circle
|
155
|
+
theta = np.linspace(0, 2 * np.pi, 300)
|
156
|
+
x_outer = 15 * np.sin(theta)
|
157
|
+
y_outer = 15 * np.cos(theta)
|
158
|
+
fig.add_trace(go.Scatter(x=x_outer, y=y_outer, mode='lines', line=dict(color='royalblue', width=2), showlegend=False, hoverinfo='skip'))
|
159
|
+
# Inner circle
|
160
|
+
theta2 = np.linspace(3 * np.pi / 2, np.pi / 2, 300) # Update theta2 to rotate the plot by 180 degrees
|
161
|
+
x_inner = 10 * np.sin(theta2) # Update x_inner to rotate the plot by 180 degrees
|
162
|
+
y_inner = -42.5 - 10 * np.cos(theta2) # Update y_inner to rotate the plot by 180 degrees
|
163
|
+
fig.add_trace(go.Scatter(x=x_inner, y=y_inner, mode='lines', line=dict(color='red', width=2), showlegend=False, hoverinfo='skip'))
|
164
|
+
|
165
|
+
# Rink boundaries
|
166
|
+
fig.add_shape(type='rect', xref='x', yref='y', x0=25, y0=-42.5, x1=26, y1=42.5, line=dict(color='royalblue', width=1), fillcolor='royalblue', opacity=1)
|
167
|
+
fig.add_shape(type='rect', xref='x', yref='y', x0=-25, y0=-42.5, x1=-26, y1=42.5, line=dict(color='royalblue', width=1), fillcolor='royalblue', opacity=1)
|
168
|
+
fig.add_shape(type='rect', xref='x', yref='y', x0=-0.5, y0=-42.5, x1=0.5, y1=42.5, line=dict(color='red', width=2), fillcolor='red')
|
169
|
+
# Goal crease
|
170
|
+
fig.add_trace(goal_crease())
|
171
|
+
fig.add_trace(goal_crease(-1))
|
172
|
+
# Goal lines
|
173
|
+
goal_line_extreme = 42.5 - 28 + np.sqrt(28 ** 2 - (28 - 11) ** 2)
|
174
|
+
fig.add_shape(type='line', xref='x', yref='y', x0=89, y0=-goal_line_extreme, x1=89, y1=goal_line_extreme, line=dict(color='red', width=2))
|
175
|
+
fig.add_shape(type='line', xref='x', yref='y', x0=-89, y0=-goal_line_extreme, x1=-89, y1=goal_line_extreme, line=dict(color='red', width=2))
|
176
|
+
# Faceoff circles
|
177
|
+
fig.add_traces(faceoff_circle(-69, -22))
|
178
|
+
fig.add_traces(faceoff_circle(-69, 22))
|
179
|
+
fig.add_traces(faceoff_circle(69, -22))
|
180
|
+
fig.add_traces(faceoff_circle(69, 22))
|
181
|
+
fig.add_traces(faceoff_circle(-20, -22, False))
|
182
|
+
fig.add_traces(faceoff_circle(-20, 22, False))
|
183
|
+
fig.add_traces(faceoff_circle(20, -22, False))
|
184
|
+
fig.add_traces(faceoff_circle(20, 22, False))
|
185
|
+
|
186
|
+
# Sidelines
|
187
|
+
theta_lines = np.linspace(0, np.pi / 2, 20)
|
188
|
+
x_lines1 = np.concatenate(([15], 72 + 28 * np.sin(theta_lines), 72 + 28 * np.sin(np.flip(theta_lines))))
|
189
|
+
y_lines1 = np.concatenate(([-42.5], -42.5 + 28 - 28 * np.cos(theta_lines), 42.5 - 28 + 28 * np.cos(np.flip(theta_lines))))
|
190
|
+
x_lines2 = np.concatenate(([15], -72 - 28 * np.sin(theta_lines), -72 - 28 * np.sin(np.flip(theta_lines))))
|
191
|
+
y_lines2 = np.concatenate(([-42.5], -42.5 + 28 - 28 * np.cos(theta_lines), 42.5 - 28 + 28 * np.cos(np.flip(theta_lines))))
|
192
|
+
fig.add_trace(go.Scatter(x=x_lines1, y=y_lines1, mode='lines', line=dict(color='white', width=2), showlegend=False, hoverinfo='skip'))
|
193
|
+
fig.add_trace(go.Scatter(x=x_lines2, y=y_lines2, mode='lines', line=dict(color='white', width=2), showlegend=False, hoverinfo='skip'))
|
194
|
+
fig.add_shape(type='line', xref='x', yref='y', x0=-72.5, y0=-42.5, x1=72.5, y1=-42.5, line=dict(color='white', width=2))
|
195
|
+
fig.add_shape(type='line', xref='x', yref='y', x0=-72.5, y0=42.5, x1=72.5, y1=42.5, line=dict(color='white', width=2))
|
196
|
+
|
197
|
+
# Add goals
|
198
|
+
goal_width = 6 # feet
|
199
|
+
goal_depth = 4 # feet
|
200
|
+
|
201
|
+
# Right goal
|
202
|
+
fig.add_shape(
|
203
|
+
type="rect",
|
204
|
+
xref="x",
|
205
|
+
yref="y",
|
206
|
+
x0=89,
|
207
|
+
y0=-goal_width / 2,
|
208
|
+
x1=89 + goal_depth,
|
209
|
+
y1=goal_width / 2,
|
210
|
+
line=dict(color="red", width=2),
|
211
|
+
)
|
212
|
+
# Left goal
|
213
|
+
fig.add_shape(
|
214
|
+
type="rect",
|
215
|
+
xref="x",
|
216
|
+
yref="y",
|
217
|
+
x0=-89 - goal_depth,
|
218
|
+
y0=-goal_width / 2,
|
219
|
+
x1=-89,
|
220
|
+
y1=goal_width / 2,
|
221
|
+
line=dict(color="red", width=2),
|
222
|
+
)
|
223
|
+
|
224
|
+
# Add logo
|
225
|
+
logo = Image.open(rs.get('https://weakside-breakout.s3.us-east-2.amazonaws.com/utils/wsba.png',stream=True).raw)
|
226
|
+
|
227
|
+
fig.add_layout_image(
|
228
|
+
dict(
|
229
|
+
source=logo,
|
230
|
+
xref="x",
|
231
|
+
yref="y",
|
232
|
+
x=-12,
|
233
|
+
y=12,
|
234
|
+
sizex=24,
|
235
|
+
sizey=24,
|
236
|
+
sizing="stretch",
|
237
|
+
opacity=1)
|
238
|
+
)
|
239
|
+
|
240
|
+
#Set background to transparent
|
241
|
+
fig.update_layout(
|
242
|
+
paper_bgcolor="rgba(0,0,0,0)",
|
243
|
+
plot_bgcolor="rgba(0,0,0,0)"
|
244
|
+
)
|
245
|
+
return fig
|
wsba_hockey/flask/app.py
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
from flask import Flask, render_template, request, redirect
|
2
|
+
from flask_sqlalchemy import SQLAlchemy
|
3
|
+
import pandas as pd
|
4
|
+
|
5
|
+
app = Flask(__name__)
|
6
|
+
|
7
|
+
#Globals
|
8
|
+
seasons = [
|
9
|
+
'20102011',
|
10
|
+
'20112012',
|
11
|
+
'20122013',
|
12
|
+
'20132014',
|
13
|
+
'20142015',
|
14
|
+
'20152016',
|
15
|
+
'20162017',
|
16
|
+
'20172018',
|
17
|
+
'20182019',
|
18
|
+
'20192020',
|
19
|
+
'20202021',
|
20
|
+
'20212022',
|
21
|
+
'20222023',
|
22
|
+
'20232024',
|
23
|
+
'20242025'
|
24
|
+
]
|
25
|
+
|
26
|
+
#Generate pages
|
27
|
+
@app.route("/")
|
28
|
+
def index():
|
29
|
+
return render_template("index.html")
|
30
|
+
|
31
|
+
@app.route("/about/about")
|
32
|
+
def about():
|
33
|
+
return render_template("about/about.html")
|
34
|
+
|
35
|
+
@app.route("/about/glossary")
|
36
|
+
def glossary():
|
37
|
+
return render_template("about/glossary.html")
|
38
|
+
|
39
|
+
@app.route("/about/goal_impact")
|
40
|
+
def goal_impact():
|
41
|
+
return render_template("about/goal_impact.html")
|
42
|
+
|
43
|
+
@app.route("/about/resources")
|
44
|
+
def resources():
|
45
|
+
return render_template("about/resources.html")
|
46
|
+
|
47
|
+
@app.route("/about/xg_model")
|
48
|
+
def xg_model():
|
49
|
+
return render_template("about/xg_model.html")
|
50
|
+
|
51
|
+
@app.route("/games/schedule")
|
52
|
+
def schedule():
|
53
|
+
return render_template("games/schedule.html")
|
54
|
+
|
55
|
+
@app.route("/games/game_metrics")
|
56
|
+
def pbp_viewer():
|
57
|
+
return render_template("games/game_metrics.html")
|
58
|
+
|
59
|
+
@app.route("/players/skater_stats", methods=["GET", "POST"])
|
60
|
+
def skater_stats():
|
61
|
+
filters = {}
|
62
|
+
for filter in ['season','span','strength','position','display','type','min_age','min_toi']:
|
63
|
+
print(request.args.get(filter))
|
64
|
+
filters.update({filter:request.args.get(filter)})
|
65
|
+
|
66
|
+
return render_template("players/skater_stats.html")
|
67
|
+
|
68
|
+
@app.route("/players/goalie_stats")
|
69
|
+
def goalie_stats():
|
70
|
+
return render_template("players/goalie_stats.html")
|
71
|
+
|
72
|
+
@app.route("/players/team_stats")
|
73
|
+
def team_stats():
|
74
|
+
return render_template("players/team_stats.html")
|
75
|
+
|
76
|
+
if __name__ == "__main__":
|
77
|
+
app.run()
|
wsba_hockey/tools/plotting.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import os
|
1
2
|
import matplotlib.pyplot as plt
|
2
3
|
import numpy as np
|
3
4
|
import pandas as pd
|
@@ -5,7 +6,7 @@ from hockey_rink import NHLRink
|
|
5
6
|
from hockey_rink import CircularImage
|
6
7
|
from scipy.interpolate import griddata
|
7
8
|
from scipy.ndimage import gaussian_filter
|
8
|
-
from
|
9
|
+
from tools.xg_model import *
|
9
10
|
|
10
11
|
### PLOTTING FUNCTIONS ###
|
11
12
|
# Provided in this file are basic plotting functions for the WSBA Hockey Python package. #
|
wsba_hockey/tools/scraping.py
CHANGED
@@ -6,7 +6,7 @@ import pandas as pd
|
|
6
6
|
import requests as rs
|
7
7
|
import json as json_lib
|
8
8
|
from bs4 import BeautifulSoup
|
9
|
-
from
|
9
|
+
from tools.utils.shared import *
|
10
10
|
warnings.filterwarnings('ignore')
|
11
11
|
|
12
12
|
### SCRAPING FUNCTIONS ###
|
@@ -28,7 +28,7 @@ def get_col():
|
|
28
28
|
return [
|
29
29
|
'season','season_type','game_id','game_date',"start_time","venue","venue_location",
|
30
30
|
'away_team_abbr','home_team_abbr','event_num','period','period_type',
|
31
|
-
'seconds_elapsed',"strength_state","strength_state_venue","home_team_defending_side",
|
31
|
+
'seconds_elapsed','period_time','game_time',"strength_state","strength_state_venue","home_team_defending_side",
|
32
32
|
"event_type_code","event_type","description","event_reason",
|
33
33
|
"penalty_type","penalty_duration","penalty_attribution",
|
34
34
|
"event_team_abbr","event_team_venue",
|
@@ -984,7 +984,11 @@ def combine_data(info,sources):
|
|
984
984
|
df[f'{venue}_corsi'] = ((df['event_team_venue']==venue)&(df['event_type'].isin(['blocked-shot','missed-shot','shot-on-goal','goal']))).cumsum()
|
985
985
|
df[f'{venue}_fenwick'] = ((df['event_team_venue']==venue)&(df['event_type'].isin(['missed-shot','shot-on-goal','goal']))).cumsum()
|
986
986
|
df[f'{venue}_penalties'] = ((df['event_team_venue']==venue)&(df['event_type']=='penalty')).cumsum()
|
987
|
-
|
987
|
+
|
988
|
+
#Add time adjustments
|
989
|
+
df['period_time'] = np.trunc((df['seconds_elapsed']-((df['period']-1)*1200))/60).astype(str).str.replace('.0','')+":"+(df['seconds_elapsed'] % 60).astype(str).str.pad(2,'left','0')
|
990
|
+
df['game_time'] = np.trunc(df['seconds_elapsed']/60).astype(str).str.replace('.0','')+":"+(df['seconds_elapsed'] % 60).astype(str).str.pad(2,'left','0')
|
991
|
+
|
988
992
|
#Forward fill as necessary
|
989
993
|
cols = ['period_type','home_team_defending_side','away_coach','home_coach']
|
990
994
|
for col in cols:
|
wsba_hockey/tools/xg_model.py
CHANGED
@@ -4,8 +4,8 @@ import pandas as pd
|
|
4
4
|
import numpy as np
|
5
5
|
import xgboost as xgb
|
6
6
|
import scipy.sparse as sp
|
7
|
-
import
|
8
|
-
import
|
7
|
+
import wsba_main as wsba
|
8
|
+
import tools.scraping as scraping
|
9
9
|
import matplotlib.pyplot as plt
|
10
10
|
from sklearn.calibration import calibration_curve
|
11
11
|
from sklearn.metrics import roc_curve, auc
|
@@ -118,7 +118,7 @@ def fix_players(pbp):
|
|
118
118
|
|
119
119
|
def prep_xG_data(data):
|
120
120
|
#Prep data for xG training and calculation
|
121
|
-
data = fix_players(data)
|
121
|
+
#data = fix_players(data)
|
122
122
|
|
123
123
|
#Informal groupby
|
124
124
|
data = data.sort_values(by=['season','game_id','period','seconds_elapsed','event_num'])
|
wsba_hockey/workspace.py
CHANGED
@@ -6,30 +6,46 @@ import numpy as np
|
|
6
6
|
|
7
7
|
season_load = wsba.repo_load_seasons()
|
8
8
|
|
9
|
-
select = season_load[
|
10
|
-
|
11
|
-
#data.pbp(select)
|
12
|
-
#data.pbp_db(select)
|
9
|
+
select = season_load[9:17]
|
13
10
|
|
14
11
|
#pbp = data.load_pbp_db(select)
|
15
12
|
|
16
13
|
#wsba.wsba_xG(pbp,hypertune=True,train=True,train_runs=30,cv_runs=30)
|
14
|
+
#select = season_load[3:18]
|
17
15
|
#for season in select:
|
18
16
|
# wsba.nhl_apply_xG(data.load_pbp([season])).to_parquet(f'pbp/parquet/nhl_pbp_{season}.parquet',index=False)
|
19
17
|
#data.pbp_db(select)
|
20
|
-
test = pd.read_parquet('backblaze_pbp/20242025.parquet')
|
21
|
-
test.loc[(test['event_goalie_id']==8476945)].to_csv('Hellebuyck.csv',index=False)
|
22
18
|
|
23
|
-
|
24
|
-
mp.loc[(mp['goalieIdForShot']==8476945)].to_csv('mfreally.csv',index=False)
|
19
|
+
#test = pd.read_parquet('aws_pbp/20242025.parquet')
|
25
20
|
#wsba.roc_auc_curve(test,'tools/xg_model/wsba_xg.joblib')
|
26
21
|
#wsba.feature_importance('tools/xg_model/wsba_xg.joblib')
|
27
22
|
#wsba.reliability(test,'tools/xg_model/wsba_xg.joblib')
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
#data.
|
32
|
-
#data.game_log(['goalie'],select)
|
24
|
+
#data.build_stats(['skater','team','goalie'],select)
|
25
|
+
#data.game_log(['skater','goalie'],select)
|
26
|
+
#data.fix_names(['skater','goalie'],select)
|
33
27
|
|
28
|
+
## DATA EXPORT ##
|
34
29
|
#data.push_to_sheet(select,['skaters','team','info'])
|
35
30
|
|
31
|
+
wsba.nhl_scrape_game(['2024020008'],remove=[]).to_csv('wtfwhy.csv',index=False)
|
32
|
+
|
33
|
+
pbp = pd.read_parquet('pbp/parquet/nhl_pbp_20242025.parquet')
|
34
|
+
helle = pbp.loc[pbp['event_goalie_id']==8476945,
|
35
|
+
['game_id','period','seconds_elapsed',
|
36
|
+
'strength_state','event_type','description',
|
37
|
+
'event_goalie_id','x','y','xG']]
|
38
|
+
mp = pd.read_csv('shots_2024.csv')
|
39
|
+
goalie = mp.loc[mp['goalieIdForShot']==8476945,
|
40
|
+
['game_id','period','time','event','goalieIdForShot',
|
41
|
+
'xCord','yCord','xGoal']].replace({
|
42
|
+
'SHOT':'shot-on-goal',
|
43
|
+
'MISS':'missed-shot',
|
44
|
+
'GOAL':'goal'
|
45
|
+
})
|
46
|
+
|
47
|
+
helle.to_csv('hellebuyck.csv',index=False)
|
48
|
+
helle['game_id'] = helle['game_id'].astype(str)
|
49
|
+
goalie['game_id'] = ('20240'+goalie['game_id'].astype(str))
|
50
|
+
pd.merge(helle,goalie,how='left',left_on=['game_id','period','seconds_elapsed','event_type','x','y'],right_on=['game_id','period','time','event','xCord','yCord']).to_csv('test.csv',index=False)
|
51
|
+
|
wsba_hockey/wsba_main.py
CHANGED
@@ -475,16 +475,19 @@ def nhl_scrape_player_data(player_ids):
|
|
475
475
|
api = f'https://api-web.nhle.com/v1/player/{player_id}/landing'
|
476
476
|
|
477
477
|
data = pd.json_normalize(rs.get(api).json())
|
478
|
-
|
479
478
|
#Add name column
|
480
479
|
data['fullName'] = (data['firstName.default'] + " " + data['lastName.default']).str.upper()
|
481
480
|
|
482
481
|
#Append
|
483
482
|
infos.append(data)
|
484
483
|
|
485
|
-
|
486
|
-
|
487
|
-
|
484
|
+
if infos:
|
485
|
+
df = pd.concat(infos)
|
486
|
+
|
487
|
+
#Return: player data
|
488
|
+
return df
|
489
|
+
else:
|
490
|
+
return pd.DataFrame()
|
488
491
|
|
489
492
|
def nhl_scrape_draft_rankings(arg = 'now', category = ''):
|
490
493
|
#Given url argument for timeframe and prospect category, return draft rankings
|
@@ -885,18 +888,8 @@ def nhl_calculate_stats(pbp,type,season_types,game_strength,split_game=False,ros
|
|
885
888
|
except KeyError:
|
886
889
|
pbp = wsba_xG(pbp)
|
887
890
|
|
888
|
-
#
|
889
|
-
|
890
|
-
|
891
|
-
#Include everything when strengths is set to 'all'
|
892
|
-
if game_strength == 'all':
|
893
|
-
mask = ((pbp['event_type'].isin(fenwick_events)) & (pbp['empty_net']<1))
|
894
|
-
else:
|
895
|
-
mask = ((pbp['event_type'].isin(fenwick_events)) & (pbp['empty_net']<1) & (pbp['x'].notna()) & (pbp['y'].notna()))
|
896
|
-
|
897
|
-
pbp_shot = pbp.loc[(pbp['season_type'].isin(season_types)) & mask]
|
898
|
-
|
899
|
-
pbp = pd.concat([pbp_shot,pbp_noshot])
|
891
|
+
#Apply season_type filter
|
892
|
+
pbp = pbp.loc[(pbp['season_type'].isin(season_types))]
|
900
893
|
|
901
894
|
#Convert all columns with player ids to float in order to avoid merging errors
|
902
895
|
for col in get_col():
|
@@ -1210,7 +1203,7 @@ def repo_load_pbp(seasons = []):
|
|
1210
1203
|
|
1211
1204
|
#Add parquet to total
|
1212
1205
|
print(f'Loading play-by-play from the following seasons: {seasons}...')
|
1213
|
-
dfs = [pd.read_parquet(f"https://
|
1206
|
+
dfs = [pd.read_parquet(f"https://weakside-breakout.s3.us-east-2.amazonaws.com/pbp/{season}.parquet") for season in seasons]
|
1214
1207
|
|
1215
1208
|
return pd.concat(dfs)
|
1216
1209
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: wsba_hockey
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.1
|
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/
|
@@ -1,7 +1,20 @@
|
|
1
1
|
wsba_hockey/__init__.py,sha256=yfr8z5PA503iaIQv30ngancwT_WnsuK-tZETKlHcI0M,377
|
2
|
-
wsba_hockey/data_pipelines.py,sha256=
|
3
|
-
wsba_hockey/workspace.py,sha256=
|
4
|
-
wsba_hockey/wsba_main.py,sha256=
|
2
|
+
wsba_hockey/data_pipelines.py,sha256=wjyxw1ikv4N3kmfTuHxdHj7_W5bz0wAM-DIgxvJVg2s,10852
|
3
|
+
wsba_hockey/workspace.py,sha256=ECScWNqkmx8SDoxTtZYZtM1K1_oX-wQSXXsb_1Bjca4,2014
|
4
|
+
wsba_hockey/wsba_main.py,sha256=c8KEXBpjHHEadMMStMRXsNYqbvtoYdZbmOl8_FBmHQg,53761
|
5
|
+
wsba_hockey/api/api/index.py,sha256=EgGd5B1382b5OMFkDvKdiodByIaDQY6-mYm58774Y0Y,5924
|
6
|
+
wsba_hockey/api/api/main.py,sha256=QaObP7kSFr-zjJL549sSWv7LtqHq5mBqvpyjjs2nVn8,87
|
7
|
+
wsba_hockey/api/api/wsba_main.py,sha256=zrQFsy-AqW1GENm-gOm9VCZNrK4TAINHRadbPi156k8,53757
|
8
|
+
wsba_hockey/api/api/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
wsba_hockey/api/api/tools/agg.py,sha256=SYZDykUQFygDfRaazlBMKcfs_1eYP7GTJNpUnNKHH-8,21409
|
10
|
+
wsba_hockey/api/api/tools/plotting.py,sha256=3x59nyqMV6pIoL548m17dfDbc39ZkMTj4EjEdJVG4uo,6017
|
11
|
+
wsba_hockey/api/api/tools/scraping.py,sha256=i6Br0XCwq4EL1Nq9z9sTzISGQ6kPZ5EYnASVJMD9lyk,45645
|
12
|
+
wsba_hockey/api/api/tools/xg_model.py,sha256=nOr_2RBijLgPmJ0TTs4wbSsORYmRqWCKRjLKDm7sAhI,18342
|
13
|
+
wsba_hockey/api/api/tools/archive/old_scraping.py,sha256=hEjMI1RtfeZnf0RBiJFI38oXkLZ3WofeH5xqcF4pzgM,49585
|
14
|
+
wsba_hockey/api/api/tools/utils/__init__.py,sha256=vccXhOtzARoR99fmEWU1OEI3qCIdQ9Z42AlRA_BUhrs,114
|
15
|
+
wsba_hockey/api/api/tools/utils/config.py,sha256=D3Uk05-YTyrhfReMTTLfNI3HN_rON2uo_CDE9oER3Lg,351
|
16
|
+
wsba_hockey/api/api/tools/utils/save_pages.py,sha256=CsyL_0n-b-4pJoUauwU3HpnCO6n69-RlBMJQBd_qGDc,4979
|
17
|
+
wsba_hockey/api/api/tools/utils/shared.py,sha256=dH_JwZfia5fib8rksy5sW-mBp0pluBPvw37Vdr8Kap0,14211
|
5
18
|
wsba_hockey/evidence/weakside-breakout/node_modules/duckdb/vendor.py,sha256=lmu0TB0rIYkAuV9-csFJgW-1hJojso_-EZpEoorUUKM,4949
|
6
19
|
wsba_hockey/evidence/weakside-breakout/node_modules/flatted/python/flatted.py,sha256=ke8FuEflns-WlphCcQ9CC0qJqWqX3zEEuak74o6rgE8,3879
|
7
20
|
wsba_hockey/evidence/weakside-breakout/node_modules/flatted/python/test.py,sha256=uTOn6HJd7KeY_PTRvvufv60dmvON3KWp3nnqACj8IlA,2129
|
@@ -104,32 +117,39 @@ wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gy
|
|
104
117
|
wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/tools/pretty_sln.py,sha256=b_Fxm-SXUCPL3Tix4EyNwZNmQ-zkeRIFFmuL0R5wFhw,5482
|
105
118
|
wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/tools/pretty_vcproj.py,sha256=AwQrxK1F-jhjsbbT35XQjrvWNbc3IBFaKXoJogqMh_o,10633
|
106
119
|
wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/test/fixtures/test-charmap.py,sha256=5raXzaQnO2eJnrlFtlDtWftryhZX7Fj0amFW3hdSnhE,547
|
107
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/game_stats/app.py,sha256=
|
120
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/game_stats/app.py,sha256=P3vDaWyuij-DXlwk6XJ0aiAjrfs-NHi5hmngk-c9r8U,12704
|
108
121
|
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/game_stats/name_fix.py,sha256=v7IN4JWrudeFuIsBdjLLlHsr9wU65jYi9-34pI_ZpoM,1488
|
109
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
110
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
111
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
112
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
113
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
114
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
115
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
116
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
117
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
118
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
119
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
120
|
-
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/
|
122
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/app.py,sha256=f5uwSvNKbtud91e7B17zC0HbPnYIvUgnShhdJZCOtkE,3820
|
123
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/plot.py,sha256=GFp2FalFg2P3kGR88mZdJY_6tJblvEl5ZLtyuKJU-Oo,3149
|
124
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/rink_plot.py,sha256=bvU7enxqxGwo2QThNabSo1qB2vltS_0HjF95ZOYZ98I,11993
|
125
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/app.py,sha256=XDoZ6-uTgT1vCAOjJ8KjW3r7T0eNDfShGScDxY95HyU,4255
|
126
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/plot.py,sha256=QERvb9I_OJPhrz84Omsf9Mq6JjaECark_ql1KfWha-I,4648
|
127
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/rink_plot.py,sha256=RB_csrnTxlFR4OyFEhZXbHDSR3dP-KgME0xGBR2JE-4,11994
|
128
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/app.py,sha256=JFWhfsyMhCnvLVyIfYzgZE2xT8_mnsOVWVXNi2EF9rM,6136
|
129
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/plot.py,sha256=t3XRT88L0lh5jE-PSSboLZZ-Yg_u8L4gzJh-egWiRcY,3935
|
130
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/rink_plot.py,sha256=RB_csrnTxlFR4OyFEhZXbHDSR3dP-KgME0xGBR2JE-4,11994
|
131
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/app.py,sha256=oH_Su2Z9iCfwsgW2aINzzxlo1fCq6dnEkTMbngjw9vg,13811
|
132
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/plot.py,sha256=zfUTSic2M1AfXufvLFDTxxvpqQXw0RzwwQTGxALjjSw,2779
|
133
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/rink_plot.py,sha256=RB_csrnTxlFR4OyFEhZXbHDSR3dP-KgME0xGBR2JE-4,11994
|
134
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/app.py,sha256=fNGWRHgqZr2G_QgACzh1l93ob-ugik1F9Wnq-sowWKU,4308
|
135
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/plot.py,sha256=qLxANHYsdPCevTGDbvDDzx4R3B8Mqm1XAs4XuuEWbfk,1852
|
136
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/rink_plot.py,sha256=RB_csrnTxlFR4OyFEhZXbHDSR3dP-KgME0xGBR2JE-4,11994
|
137
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/app.py,sha256=qqTs9uFnTS5JD5ibCKFQZOI2lFBKIlcyuf17BUV1USQ,3912
|
138
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/plot.py,sha256=rTIqkSIPrh818xDxm3iOTkRat0SAgdi_vKuIFFPEJkI,4559
|
139
|
+
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/rink_plot.py,sha256=RB_csrnTxlFR4OyFEhZXbHDSR3dP-KgME0xGBR2JE-4,11994
|
140
|
+
wsba_hockey/flask/app.py,sha256=J51iA65h9xyJfLgdH0h2sVSbfIR7xgGd2Oy8bJsmpAk,1873
|
121
141
|
wsba_hockey/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
122
142
|
wsba_hockey/tools/agg.py,sha256=SYZDykUQFygDfRaazlBMKcfs_1eYP7GTJNpUnNKHH-8,21409
|
123
|
-
wsba_hockey/tools/plotting.py,sha256=
|
124
|
-
wsba_hockey/tools/scraping.py,sha256=
|
125
|
-
wsba_hockey/tools/xg_model.py,sha256=
|
143
|
+
wsba_hockey/tools/plotting.py,sha256=3x59nyqMV6pIoL548m17dfDbc39ZkMTj4EjEdJVG4uo,6017
|
144
|
+
wsba_hockey/tools/scraping.py,sha256=i6Br0XCwq4EL1Nq9z9sTzISGQ6kPZ5EYnASVJMD9lyk,45645
|
145
|
+
wsba_hockey/tools/xg_model.py,sha256=t9ETZ8H8VlOiniVscuPTs8b0iXGJS_Ds63FJ1nehlYM,18319
|
126
146
|
wsba_hockey/tools/archive/old_scraping.py,sha256=hEjMI1RtfeZnf0RBiJFI38oXkLZ3WofeH5xqcF4pzgM,49585
|
127
147
|
wsba_hockey/tools/utils/__init__.py,sha256=vccXhOtzARoR99fmEWU1OEI3qCIdQ9Z42AlRA_BUhrs,114
|
128
148
|
wsba_hockey/tools/utils/config.py,sha256=D3Uk05-YTyrhfReMTTLfNI3HN_rON2uo_CDE9oER3Lg,351
|
129
149
|
wsba_hockey/tools/utils/save_pages.py,sha256=CsyL_0n-b-4pJoUauwU3HpnCO6n69-RlBMJQBd_qGDc,4979
|
130
150
|
wsba_hockey/tools/utils/shared.py,sha256=dH_JwZfia5fib8rksy5sW-mBp0pluBPvw37Vdr8Kap0,14211
|
131
|
-
wsba_hockey-1.1.
|
132
|
-
wsba_hockey-1.1.
|
133
|
-
wsba_hockey-1.1.
|
134
|
-
wsba_hockey-1.1.
|
135
|
-
wsba_hockey-1.1.
|
151
|
+
wsba_hockey-1.1.1.dist-info/licenses/LICENSE,sha256=Nr_Um1Pd5FQJTWWgm7maZArdtYMbDhzXYSwyJIZDGik,1114
|
152
|
+
wsba_hockey-1.1.1.dist-info/METADATA,sha256=Xb5o3LMbRGCzB1soAZWpFQNIhk_0GnG9e9EQXqqFB-Y,3542
|
153
|
+
wsba_hockey-1.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
154
|
+
wsba_hockey-1.1.1.dist-info/top_level.txt,sha256=acU7s3x-RZC1zGiqCOmO0g267iqCg34lzIfdmYxxGmQ,12
|
155
|
+
wsba_hockey-1.1.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|