wsba-hockey 1.1.9__py3-none-any.whl → 1.2.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/tools/scraping.py +146 -170
- 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 +47 -14
- {wsba_hockey-1.1.9.dist-info → wsba_hockey-1.2.1.dist-info}/METADATA +16 -15
- wsba_hockey-1.2.1.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 -28
- wsba_hockey-1.1.9.dist-info/RECORD +0 -148
- {wsba_hockey-1.1.9.dist-info → wsba_hockey-1.2.1.dist-info}/WHEEL +0 -0
- {wsba_hockey-1.1.9.dist-info → wsba_hockey-1.2.1.dist-info}/licenses/LICENSE +0 -0
- {wsba_hockey-1.1.9.dist-info → wsba_hockey-1.2.1.dist-info}/top_level.txt +0 -0
@@ -1,103 +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
|
-
'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)
|
@@ -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,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
|
wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/rink_plot.py
DELETED
@@ -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://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
DELETED
@@ -1,77 +0,0 @@
|
|
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()
|
@@ -1,14 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Basic configurations
|
3
|
-
"""
|
4
|
-
|
5
|
-
# Directory where to save pages
|
6
|
-
# When True assumes ~/hockey_scraper_data
|
7
|
-
# Otherwise can take str to `existing` directory
|
8
|
-
DOCS_DIR = False
|
9
|
-
|
10
|
-
# Boolean that tells us whether or not we should re-scrape a given page if it's already saved
|
11
|
-
RESCRAPE = False
|
12
|
-
|
13
|
-
# Whether to log verbose errors to log file
|
14
|
-
LOG = False
|
@@ -1,133 +0,0 @@
|
|
1
|
-
#
|
2
|
-
#Saves the scraped docs so you don't have to re-scrape them every time you want to parse the docs.
|
3
|
-
#
|
4
|
-
#\**** Don't mess with this unless you know what you're doing \****
|
5
|
-
#
|
6
|
-
import os
|
7
|
-
import gzip
|
8
|
-
|
9
|
-
|
10
|
-
def create_base_file_path(file_info):
|
11
|
-
"""
|
12
|
-
Creates the base file path for a given file
|
13
|
-
|
14
|
-
:param file_info: Dictionary containing the info on the file. Includes the name, season, file type, and the dir
|
15
|
-
we want to deposit any data in.
|
16
|
-
|
17
|
-
:return: path
|
18
|
-
"""
|
19
|
-
# Shitty fix for when you already have it saved but don't have nwhl folders
|
20
|
-
if 'nwhl' in file_info['type']:
|
21
|
-
if not os.path.isdir(os.path.join(file_info['dir'], 'docs', str(file_info['season']), file_info['type'])):
|
22
|
-
os.mkdir(os.path.join(file_info['dir'], 'docs', str(file_info['season']), file_info['type']))
|
23
|
-
|
24
|
-
return os.path.join(file_info['dir'], 'docs', str(file_info['season']), file_info['type'], file_info['name'] + ".txt")
|
25
|
-
|
26
|
-
|
27
|
-
def is_compressed(file_info):
|
28
|
-
"""
|
29
|
-
Check if stored file is compressed as we used to not save them as compressed.
|
30
|
-
|
31
|
-
:param file_info: Dictionary containing the info on the file. Includes the name, season, file type, and the dir
|
32
|
-
we want to deposit any data in.
|
33
|
-
|
34
|
-
return Boolean
|
35
|
-
"""
|
36
|
-
return os.path.isfile(create_base_file_path(file_info) + ".gz")
|
37
|
-
|
38
|
-
|
39
|
-
def create_dir_structure(dir_name):
|
40
|
-
"""
|
41
|
-
Create the basic directory structure for docs_dir if not done yet.
|
42
|
-
Creates the docs and csvs subdir if it doesn't exist
|
43
|
-
|
44
|
-
:param dir_name: Name of dir to create
|
45
|
-
|
46
|
-
:return None
|
47
|
-
"""
|
48
|
-
if not os.path.isdir(os.path.join(dir_name, 'docs')):
|
49
|
-
os.mkdir(os.path.join(dir_name, 'docs'))
|
50
|
-
|
51
|
-
if not os.path.isdir(os.path.join(dir_name, 'csvs')):
|
52
|
-
os.mkdir(os.path.join(dir_name, 'csvs'))
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
def create_season_dirs(file_info):
|
57
|
-
"""
|
58
|
-
Creates the infrastructure to hold all the scraped docs for a season
|
59
|
-
|
60
|
-
:param file_info: Dictionary containing the info on the file. Includes the name, season, file type, and the dir
|
61
|
-
we want to deposit any data in.
|
62
|
-
|
63
|
-
:return: None
|
64
|
-
"""
|
65
|
-
sub_folders = ["html_pbp", "json_pbp", "espn_pbp", "html_shifts_home", "html_shifts_away",
|
66
|
-
"json_shifts", "html_roster", "json_schedule", "espn_scoreboard"]
|
67
|
-
|
68
|
-
season_path = os.path.join(file_info['dir'], 'docs', str(file_info['season']))
|
69
|
-
os.mkdir(season_path)
|
70
|
-
|
71
|
-
for sub_f in sub_folders:
|
72
|
-
os.mkdir(os.path.join(season_path, sub_f))
|
73
|
-
|
74
|
-
|
75
|
-
def check_file_exists(file_info):
|
76
|
-
"""
|
77
|
-
Checks if the file exists. Also check if structure for holding scraped file exists to. If not, it creates it.
|
78
|
-
|
79
|
-
:param file_info: Dictionary containing the info on the file. Includes the name, season, file type, and the dir
|
80
|
-
we want to deposit any data in.
|
81
|
-
|
82
|
-
:return: Boolean - True if it exists
|
83
|
-
"""
|
84
|
-
create_dir_structure(file_info['dir'])
|
85
|
-
|
86
|
-
# Check if the folder for the season for the given game was created yet...if not create it
|
87
|
-
if not os.path.isdir(os.path.join(file_info['dir'], 'docs', str(file_info['season']))):
|
88
|
-
create_season_dirs(file_info)
|
89
|
-
|
90
|
-
# May or may not be compressed due to file saved under older versions
|
91
|
-
non_compressed_file = os.path.isfile(create_base_file_path(file_info))
|
92
|
-
compressed_file = is_compressed(file_info)
|
93
|
-
|
94
|
-
return compressed_file or non_compressed_file
|
95
|
-
|
96
|
-
|
97
|
-
def get_page(file_info):
|
98
|
-
"""
|
99
|
-
Get the file so we don't need to re-scrape.
|
100
|
-
|
101
|
-
Try both compressed and non-compressed for backwards compatability issues (formerly non-compressed)
|
102
|
-
|
103
|
-
:param file_info: Dictionary containing the info on the file. Includes the name, season, file type, and the dir
|
104
|
-
we want to deposit any data in.
|
105
|
-
|
106
|
-
:return: Response or None
|
107
|
-
"""
|
108
|
-
base_file = create_base_file_path(file_info)
|
109
|
-
|
110
|
-
if is_compressed(file_info):
|
111
|
-
with gzip.open(base_file + ".gz", 'rb') as my_file:
|
112
|
-
return my_file.read().decode("utf-8").replace('\n', '')
|
113
|
-
else:
|
114
|
-
with open(base_file, 'r') as my_file:
|
115
|
-
return my_file.read().replace('\n', '')
|
116
|
-
|
117
|
-
|
118
|
-
def save_page(page, file_info):
|
119
|
-
"""
|
120
|
-
Save the page we just scraped.
|
121
|
-
|
122
|
-
Note: It'll only get saved if the directory already exists!!!!!!. I'm not dealing with any fuck ups. That would
|
123
|
-
involve checking if it's even a valid path and creating it. Make sure you get it right.
|
124
|
-
|
125
|
-
:param page: File scraped
|
126
|
-
:param file_info: Dictionary containing the info on the file. Includes the name, season, file type, and the dir
|
127
|
-
we want to deposit any data in.
|
128
|
-
|
129
|
-
:return: None
|
130
|
-
"""
|
131
|
-
if file_info['dir'] and page is not None and page != '':
|
132
|
-
with gzip.open(create_base_file_path(file_info) + ".gz", 'wb') as file:
|
133
|
-
file.write(page.encode())
|