wsba-hockey 1.1.8__py3-none-any.whl → 1.2.0__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/__init__.py +22 -1
- wsba_hockey/tools/scraping.py +166 -190
- wsba_hockey/tools/utils/__init__.py +0 -1
- wsba_hockey/tools/utils/shared.py +14 -389
- wsba_hockey/tools/xg_model.py +6 -1
- wsba_hockey/wsba_main.py +330 -20
- {wsba_hockey-1.1.8.dist-info → wsba_hockey-1.2.0.dist-info}/METADATA +16 -15
- wsba_hockey-1.2.0.dist-info/RECORD +15 -0
- wsba_hockey/api/api/index.py +0 -162
- wsba_hockey/data_pipelines.py +0 -247
- wsba_hockey/evidence/weakside-breakout/node_modules/duckdb/vendor.py +0 -146
- wsba_hockey/evidence/weakside-breakout/node_modules/flatted/python/flatted.py +0 -149
- wsba_hockey/evidence/weakside-breakout/node_modules/flatted/python/test.py +0 -63
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/gyp_main.py +0 -45
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSNew.py +0 -367
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSProject.py +0 -206
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSSettings.py +0 -1270
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSSettings_test.py +0 -1547
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSToolFile.py +0 -59
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSUserFile.py +0 -153
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSUtil.py +0 -271
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSVersion.py +0 -574
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/__init__.py +0 -690
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/common.py +0 -661
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/common_test.py +0 -78
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/easy_xml.py +0 -165
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/easy_xml_test.py +0 -109
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/flock_tool.py +0 -55
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/__init__.py +0 -0
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/analyzer.py +0 -808
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/android.py +0 -1173
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/cmake.py +0 -1321
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/compile_commands_json.py +0 -120
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/dump_dependency_json.py +0 -103
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/eclipse.py +0 -464
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/gypd.py +0 -89
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/gypsh.py +0 -58
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/make.py +0 -2714
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/msvs.py +0 -3981
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/msvs_test.py +0 -44
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/ninja.py +0 -2936
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/ninja_test.py +0 -55
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/xcode.py +0 -1394
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/xcode_test.py +0 -25
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/input.py +0 -3130
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/input_test.py +0 -98
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/mac_tool.py +0 -771
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/msvs_emulation.py +0 -1271
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/ninja_syntax.py +0 -174
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/simple_copy.py +0 -61
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/win_tool.py +0 -374
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py +0 -1939
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/xcode_ninja.py +0 -302
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/xcodeproj_file.py +0 -3197
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/xml_fix.py +0 -65
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/test_gyp.py +0 -261
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/tools/graphviz.py +0 -102
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/tools/pretty_gyp.py +0 -156
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/tools/pretty_sln.py +0 -181
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/tools/pretty_vcproj.py +0 -339
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/test/fixtures/test-charmap.py +0 -31
- wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/update-gyp.py +0 -64
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/gyp_main.py +0 -45
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSNew.py +0 -367
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSProject.py +0 -206
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSSettings.py +0 -1270
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSSettings_test.py +0 -1547
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSToolFile.py +0 -59
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSUserFile.py +0 -153
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSUtil.py +0 -271
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSVersion.py +0 -574
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/__init__.py +0 -666
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/common.py +0 -654
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/common_test.py +0 -78
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/easy_xml.py +0 -165
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/easy_xml_test.py +0 -109
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/flock_tool.py +0 -55
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/__init__.py +0 -0
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/analyzer.py +0 -808
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/android.py +0 -1173
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/cmake.py +0 -1321
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/compile_commands_json.py +0 -120
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/dump_dependency_json.py +0 -103
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/eclipse.py +0 -464
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/gypd.py +0 -89
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/gypsh.py +0 -58
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/make.py +0 -2518
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/msvs.py +0 -3978
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/msvs_test.py +0 -44
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/ninja.py +0 -2936
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/ninja_test.py +0 -55
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/xcode.py +0 -1394
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/xcode_test.py +0 -25
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/input.py +0 -3137
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/input_test.py +0 -98
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/mac_tool.py +0 -771
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/msvs_emulation.py +0 -1271
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/ninja_syntax.py +0 -174
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/simple_copy.py +0 -61
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/win_tool.py +0 -374
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py +0 -1939
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/xcode_ninja.py +0 -302
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/xcodeproj_file.py +0 -3197
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/xml_fix.py +0 -65
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/setup.py +0 -42
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/test_gyp.py +0 -260
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/tools/graphviz.py +0 -102
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/tools/pretty_gyp.py +0 -156
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/tools/pretty_sln.py +0 -181
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/tools/pretty_vcproj.py +0 -339
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/test/fixtures/test-charmap.py +0 -31
- wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/update-gyp.py +0 -46
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/duos/app.py +0 -210
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/duos/calc.py +0 -163
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/game_stats/app.py +0 -401
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/game_stats/name_fix.py +0 -47
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/app.py +0 -101
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/plot.py +0 -71
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/rink_plot.py +0 -245
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/app.py +0 -108
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/plot.py +0 -95
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/rink_plot.py +0 -245
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/line-combos/app.py +0 -245
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/line-combos/plot.py +0 -275
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/line-combos/rink_plot.py +0 -245
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/app.py +0 -145
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/plot.py +0 -79
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/rink_plot.py +0 -245
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/app.py +0 -406
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/plot.py +0 -79
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/rink_plot.py +0 -245
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/app.py +0 -110
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/plot.py +0 -59
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/rink_plot.py +0 -245
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/app.py +0 -103
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/plot.py +0 -95
- wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/rink_plot.py +0 -245
- wsba_hockey/flask/app.py +0 -77
- wsba_hockey/tools/utils/config.py +0 -14
- wsba_hockey/tools/utils/save_pages.py +0 -133
- wsba_hockey/workspace.py +0 -31
- wsba_hockey-1.1.8.dist-info/RECORD +0 -148
- {wsba_hockey-1.1.8.dist-info → wsba_hockey-1.2.0.dist-info}/WHEEL +0 -0
- {wsba_hockey-1.1.8.dist-info → wsba_hockey-1.2.0.dist-info}/licenses/LICENSE +0 -0
- {wsba_hockey-1.1.8.dist-info → wsba_hockey-1.2.0.dist-info}/top_level.txt +0 -0
@@ -1,245 +0,0 @@
|
|
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://f005.backblazeb2.com/file/weakside-breakout/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
|
@@ -1,108 +0,0 @@
|
|
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
|
-
'skater':['8473419'],
|
28
|
-
'season':['20182019'],
|
29
|
-
'team':['BOS'],
|
30
|
-
'strength_state':['5v5'],
|
31
|
-
'season_type':['2']
|
32
|
-
}
|
33
|
-
|
34
|
-
for key in defaults.keys():
|
35
|
-
if key not in query.keys():
|
36
|
-
query.update({key:defaults[key]})
|
37
|
-
|
38
|
-
#Iterate through query and parse params with multiple selections
|
39
|
-
for param in query.keys():
|
40
|
-
q_string = query[param][0]
|
41
|
-
query[param] = q_string.split(',')
|
42
|
-
|
43
|
-
print(query)
|
44
|
-
#Determine which season to load based on the input
|
45
|
-
season = query['season'][0]
|
46
|
-
#Load appropriate dataframe
|
47
|
-
df = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/pbp/{season}.parquet')
|
48
|
-
|
49
|
-
#Prepare dataframe for plotting based on URL parameters
|
50
|
-
df = df.loc[(df['season'].astype(str).isin(query['season']))&(df['season_type'].astype(str).isin(query['season_type']))].replace({np.nan: None})
|
51
|
-
#Return empty rink if no data exists else continue
|
52
|
-
if df.empty:
|
53
|
-
return wsba_plt.wsba_rink()
|
54
|
-
else:
|
55
|
-
rink = wsba_plt.wsba_rink()
|
56
|
-
|
57
|
-
try:
|
58
|
-
for_plot = wsba_plt.heatmap(df,skater=query['skater'][0],team=query['team'][0],events=['missed-shot','shot-on-goal','goal'],strengths=query['strength_state'],onice='for')
|
59
|
-
against_plot = wsba_plt.heatmap(df,skater=query['skater'][0],team=query['team'][0],events=['missed-shot','shot-on-goal','goal'],strengths=query['strength_state'],onice='against')
|
60
|
-
|
61
|
-
for trace in for_plot.data:
|
62
|
-
rink.add_trace(trace)
|
63
|
-
|
64
|
-
for trace in against_plot.data:
|
65
|
-
rink.add_trace(trace)
|
66
|
-
|
67
|
-
try:
|
68
|
-
player = df.loc[df['event_player_1_id'].astype(str).str.replace('.0','')==query['skater'][0],'event_player_1_name'].to_list()[0]
|
69
|
-
except:
|
70
|
-
player = query['skater'][0]
|
71
|
-
season = int(season[0:4])
|
72
|
-
team = query['team'][0]
|
73
|
-
strengths = 'All Situations' if len(query['strength_state']) == 4 else query['strength_state']
|
74
|
-
span = 'Regular Season' if query['season_type'][0]=='2' else 'Playoffs'
|
75
|
-
|
76
|
-
return rink.update_layout(
|
77
|
-
title=dict(
|
78
|
-
text=f'{player} On-Ice xG at {strengths}; {season}-{season+1}, {span}, {team}',
|
79
|
-
x=0.5, y=0.96,
|
80
|
-
xanchor='center',
|
81
|
-
yanchor='top',
|
82
|
-
font=dict(color='white')
|
83
|
-
),
|
84
|
-
).add_annotation(
|
85
|
-
text='Lower xG',
|
86
|
-
xref="paper",
|
87
|
-
yref="paper",
|
88
|
-
xanchor='right',
|
89
|
-
yanchor='top',
|
90
|
-
font=dict(color='white'),
|
91
|
-
x=0.3,
|
92
|
-
y=0.04,
|
93
|
-
showarrow=False
|
94
|
-
).add_annotation(
|
95
|
-
text='Higher xG',
|
96
|
-
xref="paper",
|
97
|
-
yref="paper",
|
98
|
-
xanchor='right',
|
99
|
-
yanchor='top',
|
100
|
-
font=dict(color='white'),
|
101
|
-
x=0.76,
|
102
|
-
y=0.04,
|
103
|
-
showarrow=False
|
104
|
-
)
|
105
|
-
except:
|
106
|
-
return wsba_plt.wsba_rink()
|
107
|
-
|
108
|
-
app = App(app_ui, server)
|
@@ -1,95 +0,0 @@
|
|
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,skater,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['onice_for'].str.contains(skater))&(df['event_team_abbr']==team)]
|
57
|
-
else:
|
58
|
-
player_shots = df.loc[(df['onice_against'].str.contains(skater))&(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
|