wsba-hockey 1.1.0__tar.gz → 1.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wsba_hockey-1.1.0/src/wsba_hockey.egg-info → wsba_hockey-1.1.2}/PKG-INFO +1 -1
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/pyproject.toml +1 -1
- wsba_hockey-1.1.2/src/wsba_hockey/api/api/index.py +129 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/data_pipelines.py +71 -8
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/game_stats/app.py +6 -5
- wsba_hockey-1.1.2/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/app.py +101 -0
- wsba_hockey-1.1.2/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie/plot.py +71 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/app.py +1 -1
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps/plot.py +2 -0
- {wsba_hockey-1.1.0/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater → wsba_hockey-1.1.2/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps}/rink_plot.py +1 -1
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/app.py +3 -3
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/plot.py +2 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/matchups/rink_plot.py +1 -1
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/app.py +44 -28
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/plot.py +12 -3
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/pbp/rink_plot.py +1 -1
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/app.py +1 -1
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/plot.py +5 -4
- wsba_hockey-1.1.2/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/skater/rink_plot.py +245 -0
- wsba_hockey-1.1.2/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/app.py +103 -0
- wsba_hockey-1.1.2/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/plot.py +95 -0
- wsba_hockey-1.1.2/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/team_heatmaps/rink_plot.py +245 -0
- wsba_hockey-1.1.2/src/wsba_hockey/flask/app.py +77 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/tools/plotting.py +1 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/tools/scraping.py +6 -2
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/tools/xg_model.py +1 -1
- wsba_hockey-1.1.2/src/wsba_hockey/workspace.py +51 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/wsba_main.py +10 -17
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2/src/wsba_hockey.egg-info}/PKG-INFO +1 -1
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey.egg-info/SOURCES.txt +8 -0
- wsba_hockey-1.1.0/src/wsba_hockey/workspace.py +0 -35
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/LICENSE +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/README.md +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/setup.cfg +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/__init__.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/duckdb/vendor.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/flatted/python/flatted.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/flatted/python/test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/gyp_main.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSNew.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSProject.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSSettings.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSSettings_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSToolFile.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSUserFile.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSUtil.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/MSVSVersion.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/__init__.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/common.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/common_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/easy_xml.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/easy_xml_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/flock_tool.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/__init__.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/analyzer.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/android.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/cmake.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/compile_commands_json.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/dump_dependency_json.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/eclipse.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/gypd.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/gypsh.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/make.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/msvs.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/msvs_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/ninja.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/ninja_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/xcode.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/generator/xcode_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/input.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/input_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/mac_tool.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/msvs_emulation.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/ninja_syntax.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/simple_copy.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/win_tool.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/xcode_ninja.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/xcodeproj_file.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/pylib/gyp/xml_fix.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/test_gyp.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/tools/graphviz.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/tools/pretty_gyp.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/tools/pretty_sln.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/gyp/tools/pretty_vcproj.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/test/fixtures/test-charmap.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/node-gyp/update-gyp.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/gyp_main.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSNew.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSProject.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSSettings.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSSettings_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSToolFile.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSUserFile.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSUtil.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/MSVSVersion.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/__init__.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/common.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/common_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/easy_xml.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/easy_xml_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/flock_tool.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/__init__.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/analyzer.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/android.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/cmake.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/compile_commands_json.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/dump_dependency_json.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/eclipse.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/gypd.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/gypsh.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/make.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/msvs.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/msvs_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/ninja.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/ninja_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/xcode.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/generator/xcode_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/input.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/input_test.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/mac_tool.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/msvs_emulation.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/ninja_syntax.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/simple_copy.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/win_tool.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/xcode_ninja.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/xcodeproj_file.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/pylib/gyp/xml_fix.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/setup.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/test_gyp.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/tools/graphviz.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/tools/pretty_gyp.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/tools/pretty_sln.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/gyp/tools/pretty_vcproj.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/test/fixtures/test-charmap.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/node_modules/sqlite3/node_modules/node-gyp/update-gyp.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/game_stats/name_fix.py +0 -0
- {wsba_hockey-1.1.0/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/heatmaps → wsba_hockey-1.1.2/src/wsba_hockey/evidence/weakside-breakout/wsba_nhl_apps/wsba_nhl_apps/goalie}/rink_plot.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/tools/__init__.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/tools/agg.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/tools/archive/old_scraping.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/tools/utils/__init__.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/tools/utils/config.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/tools/utils/save_pages.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey/tools/utils/shared.py +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey.egg-info/dependency_links.txt +0 -0
- {wsba_hockey-1.1.0 → wsba_hockey-1.1.2}/src/wsba_hockey.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: wsba_hockey
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.2
|
4
4
|
Summary: WeakSide Breakout's complete Python package of access to hockey data, primairly including the scraping of National Hockey League schedule, play-by-play, and shifts information.
|
5
5
|
Author-email: Owen Singh <owenbksingh@gmail.com>
|
6
6
|
Project-URL: Homepage, https://github.com/owensingh38/wsba_hockey/
|
@@ -0,0 +1,129 @@
|
|
1
|
+
import pandas as pd
|
2
|
+
import numpy as np
|
3
|
+
import wsba_hockey as wsba
|
4
|
+
import requests as rs
|
5
|
+
from fastapi import FastAPI
|
6
|
+
from datetime import datetime
|
7
|
+
import pytz
|
8
|
+
|
9
|
+
app = FastAPI()
|
10
|
+
|
11
|
+
@app.get("/")
|
12
|
+
def read_root():
|
13
|
+
return {"WeakSide Breakout Analysis": "Welcome to the API!"}
|
14
|
+
|
15
|
+
@app.get("/nhl/players/{player_id}")
|
16
|
+
def player(player_id: int):
|
17
|
+
player = rs.get(f'https://api-web.nhle.com/v1/player/{player_id}/landing').json()
|
18
|
+
|
19
|
+
return player
|
20
|
+
|
21
|
+
@app.get("/nhl/schedule/{date}")
|
22
|
+
def schedule_info(date: str):
|
23
|
+
data = rs.get(f'https://api-web.nhle.com/v1/schedule/{date}').json()
|
24
|
+
|
25
|
+
eastern = pytz.timezone('US/Eastern')
|
26
|
+
for game in data['gameWeek'][0]['games']:
|
27
|
+
game['startTimeEST'] = datetime.strptime(game['startTimeUTC'],'%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=pytz.UTC).astimezone(eastern).strftime('%I:%M %p')
|
28
|
+
|
29
|
+
return data
|
30
|
+
|
31
|
+
@app.get("/nhl/games/{game_id}")
|
32
|
+
def pbp(game_id: int):
|
33
|
+
df = wsba.nhl_apply_xG(wsba.nhl_scrape_game([game_id],remove=[]))
|
34
|
+
|
35
|
+
skater = {}
|
36
|
+
goalie = {}
|
37
|
+
team_stats = {}
|
38
|
+
other = df.loc[~df['strength_state'].isin(['5v5','5v4','4v5']),'strength_state'].drop_duplicates().to_list()
|
39
|
+
for strength in [['5v5'],['5v4'],['4v5'],
|
40
|
+
other,
|
41
|
+
'all']:
|
42
|
+
|
43
|
+
s = wsba.nhl_calculate_stats(df,'skater',[2,3],strength,True).replace([np.inf, -np.inf], np.nan).fillna('').to_dict(orient='records')
|
44
|
+
g = wsba.nhl_calculate_stats(df,'goalie',[2,3],strength,True).replace([np.inf, -np.inf], np.nan).fillna('').to_dict(orient='records')
|
45
|
+
t = wsba.nhl_calculate_stats(df,'team',[2,3],strength,True).replace([np.inf, -np.inf], np.nan).fillna('').to_dict(orient='records')
|
46
|
+
|
47
|
+
if strength != 'all':
|
48
|
+
if len(strength)>1:
|
49
|
+
add = 'Other'
|
50
|
+
else:
|
51
|
+
add = strength[0]
|
52
|
+
else:
|
53
|
+
add = 'All'
|
54
|
+
|
55
|
+
skater.update({add:s})
|
56
|
+
goalie.update({add:g})
|
57
|
+
team_stats.update({add:t})
|
58
|
+
|
59
|
+
df = df.fillna('')
|
60
|
+
|
61
|
+
team_data = pd.read_csv('https://weakside-breakout.s3.us-east-2.amazonaws.com/info/nhl_teaminfo.csv')[['triCode','seasonId','teamName.default','teamLogo','Primary Color','Secondary Color','WSBA']]
|
62
|
+
|
63
|
+
info = df[['season','season_type','game_id','game_date',
|
64
|
+
'venue','venue_location']].drop_duplicates().to_dict(orient='records')[0]
|
65
|
+
|
66
|
+
info.update({'notice':'All data and materials are from the National Hockey League.'})
|
67
|
+
|
68
|
+
teams = {}
|
69
|
+
for team in ['away','home']:
|
70
|
+
df = pd.merge(df,team_data,how='left',left_on=[f'{team}_team_abbr','season'],right_on=['triCode','seasonId']).fillna('')
|
71
|
+
mod = '' if team == 'away' else '_y'
|
72
|
+
teams.update({team: df[[f'{team}_team_abbr'
|
73
|
+
,f'{team}_coach',
|
74
|
+
f'teamName.default{mod}',
|
75
|
+
f'teamLogo{mod}',
|
76
|
+
f'Primary Color{mod}',
|
77
|
+
f'Secondary Color{mod}',
|
78
|
+
f'WSBA{mod}']].rename(columns={f'{team}_team_abbr':'team_abbr',f'{team}_coach':'coach',
|
79
|
+
f'teamName.default{mod}':'team_name',
|
80
|
+
f'teamLogo{mod}':'team_logo',
|
81
|
+
f'Primary Color{mod}':'primary_color',
|
82
|
+
f'Secondary Color{mod}':'secondary_color',
|
83
|
+
f'WSBA{mod}':'WSBA'
|
84
|
+
}).drop_duplicates().to_dict(orient='records')[0]})
|
85
|
+
|
86
|
+
play_col = [
|
87
|
+
'event_num','period','period_type',
|
88
|
+
'seconds_elapsed','period_time','game_time',"strength_state","strength_state_venue","home_team_defending_side",
|
89
|
+
"event_type_code","event_type","description","event_reason",
|
90
|
+
"penalty_type","penalty_duration","penalty_attribution",
|
91
|
+
"event_team_abbr","event_team_venue",
|
92
|
+
'num_on', 'players_on','ids_on','num_off','players_off','ids_off','shift_type',
|
93
|
+
"event_player_1_name","event_player_2_name","event_player_3_name",
|
94
|
+
"event_player_1_id","event_player_2_id","event_player_3_id",
|
95
|
+
"event_player_1_pos","event_player_2_pos","event_player_3_pos",
|
96
|
+
"event_goalie_name","event_goalie_id",
|
97
|
+
"shot_type","zone_code","x","y","x_fixed","y_fixed","x_adj","y_adj",
|
98
|
+
"event_skaters","away_skaters","home_skaters",
|
99
|
+
"event_distance","event_angle","event_length","seconds_since_last",
|
100
|
+
"away_score","home_score", "away_fenwick", "home_fenwick",
|
101
|
+
"away_on_1","away_on_2","away_on_3","away_on_4","away_on_5","away_on_6","away_goalie",
|
102
|
+
"home_on_1","home_on_2","home_on_3","home_on_4","home_on_5","home_on_6","home_goalie",
|
103
|
+
"away_on_1_id","away_on_2_id","away_on_3_id","away_on_4_id","away_on_5_id","away_on_6_id","away_goalie_id",
|
104
|
+
"home_on_1_id","home_on_2_id","home_on_3_id","home_on_4_id","home_on_5_id","home_on_6_id","home_goalie_id",
|
105
|
+
"event_coach",'xG'
|
106
|
+
]
|
107
|
+
|
108
|
+
def sanitize(value):
|
109
|
+
if isinstance(value, (np.generic, np.ndarray)):
|
110
|
+
return value.item()
|
111
|
+
return value
|
112
|
+
|
113
|
+
plays = [
|
114
|
+
{k: sanitize(v) for k, v in row.items() if v != ''}
|
115
|
+
for row in df[[col for col in play_col if col in df.columns]].to_dict(orient='records')
|
116
|
+
]
|
117
|
+
|
118
|
+
plays = [
|
119
|
+
{k: sanitize(v) for k, v in row.items() if v != ''}
|
120
|
+
for row in df[[col for col in play_col if col in df.columns]].to_dict(orient='records')
|
121
|
+
]
|
122
|
+
|
123
|
+
return {'info': info,
|
124
|
+
'teams': teams,
|
125
|
+
'skater_stats':skater,
|
126
|
+
'goalie_stats':goalie,
|
127
|
+
'team_stats':team_stats,
|
128
|
+
'plays': plays
|
129
|
+
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import os
|
1
2
|
import numpy as np
|
2
3
|
import pandas as pd
|
3
4
|
import wsba_main as wsba
|
@@ -23,15 +24,16 @@ def pbp_db(seasons):
|
|
23
24
|
for season in seasons:
|
24
25
|
pbp = pd.read_parquet(f'pbp/parquet/nhl_pbp_{season}.parquet')
|
25
26
|
pbp.loc[pbp['event_type'].isin(wsba.events+['penalty'])].to_csv('temp.csv',index=False)
|
26
|
-
pd.read_csv('temp.csv').to_parquet(f'
|
27
|
+
pd.read_csv('temp.csv').to_parquet(f'aws_pbp/{season}.parquet',index=False)
|
28
|
+
os.remove('temp.csv')
|
27
29
|
|
28
30
|
def load_pbp(seasons):
|
29
31
|
return pd.concat([pd.read_parquet(f'pbp/parquet/nhl_pbp_{season}.parquet') for season in seasons])
|
30
32
|
|
31
33
|
def load_pbp_db(seasons):
|
32
|
-
return pd.concat([pd.read_parquet(f'
|
34
|
+
return pd.concat([pd.read_parquet(f'aws_pbp/{season}.parquet') for season in seasons])
|
33
35
|
|
34
|
-
def
|
36
|
+
def build_stats(arg,seasons):
|
35
37
|
#Stats building
|
36
38
|
for group in arg:
|
37
39
|
for season in seasons:
|
@@ -73,9 +75,70 @@ def game_log(arg,seasons):
|
|
73
75
|
data['Span'] = season_type[0]
|
74
76
|
dfs.append(data)
|
75
77
|
stat = pd.concat(dfs)
|
76
|
-
|
77
|
-
|
78
|
-
stats.
|
78
|
+
path = 'stats/game_log' if group == 'skater' else 'stats/game_log/goalie'
|
79
|
+
stat.to_csv(f'{path}/temp.csv',index=False)
|
80
|
+
stats = pd.read_csv(f'{path}/temp.csv')
|
81
|
+
os.remove('temp.csv')
|
82
|
+
stats.to_parquet(f'{path}/wsba_nhl_{season}_game_log{'_goalie' if group == 'goalie' else ''}.parquet',index=False)
|
83
|
+
|
84
|
+
def fix_names(arg,seasons):
|
85
|
+
#Stats building
|
86
|
+
for group in arg:
|
87
|
+
for season in seasons:
|
88
|
+
print(f'Fixing names for {group} stats in {season}...')
|
89
|
+
|
90
|
+
group_name = 'Player' if 'skater' in group else 'Goalie'
|
91
|
+
if 'game_log' in group:
|
92
|
+
if 'skater' in group:
|
93
|
+
path = f'stats/{group[-8:]}/wsba_nhl_{season}_game_log.parquet'
|
94
|
+
else:
|
95
|
+
path = f'stats/{group[-8:]}/goalie/wsba_nhl_{season}_game_log_goalie.parquet'
|
96
|
+
else:
|
97
|
+
path = f'stats/{group}/wsba_nhl_{season}_{group}.csv'
|
98
|
+
|
99
|
+
if 'game_log' in group:
|
100
|
+
stats = pd.read_parquet(path)
|
101
|
+
else:
|
102
|
+
stats = pd.read_csv(path)
|
103
|
+
|
104
|
+
missing = stats.loc[stats[group_name].astype(str)=='0','ID'].drop_duplicates()
|
105
|
+
|
106
|
+
if not missing.to_list():
|
107
|
+
''
|
108
|
+
else:
|
109
|
+
info = wsba.nhl_scrape_player_data(missing)
|
110
|
+
columns={'playerId':'ID',
|
111
|
+
'fullName':group_name,
|
112
|
+
'position':'Position',
|
113
|
+
'headshot':'Headshot',
|
114
|
+
'shootsCatches':'Handedness',
|
115
|
+
'heightInInches':'Height (in)',
|
116
|
+
'weightInPounds':'Weight (lbs)',
|
117
|
+
'birthDate':'Birthday' }
|
118
|
+
|
119
|
+
info = info[list(columns.keys())]
|
120
|
+
complete = pd.merge(stats,info,how='left',left_on=['ID'],right_on=['playerId']).replace({'0':np.nan})
|
121
|
+
|
122
|
+
for key, value in zip(columns.keys(), columns.values()):
|
123
|
+
complete[value] = complete[value].combine_first(complete[key])
|
124
|
+
complete = complete.drop(columns=[key])
|
125
|
+
|
126
|
+
complete.to_csv('wtf.csv')
|
127
|
+
#Add player age
|
128
|
+
complete['Birthday'] = pd.to_datetime(complete['Birthday'],format='mixed')
|
129
|
+
complete['season_year'] = complete['Season'].astype(str).str[4:8].astype(int)
|
130
|
+
complete['Age'] = complete['season_year'] - complete['Birthday'].dt.year
|
131
|
+
|
132
|
+
complete['WSBA'] = complete[group_name]+complete['Team']+complete['Season'].astype(str)
|
133
|
+
complete = complete.sort_values(by=['Player','Season','Team','ID'])
|
134
|
+
|
135
|
+
if 'game_log' in group:
|
136
|
+
complete.to_csv('temp.csv',index=False)
|
137
|
+
pd.read_csv('temp.csv').to_parquet(path,index=False)
|
138
|
+
os.remove('temp.csv')
|
139
|
+
|
140
|
+
else:
|
141
|
+
complete.to_csv(path)
|
79
142
|
|
80
143
|
def push_to_sheet(seasons, types = ['skaters','team','goalie','info'], msg = 'Data Update'):
|
81
144
|
spread = Spread('WSBA - NHL 5v5 Shooting Metrics Public v1.0')
|
@@ -100,8 +163,8 @@ def push_to_sheet(seasons, types = ['skaters','team','goalie','info'], msg = 'Da
|
|
100
163
|
spread.df_to_sheet(goalie,index=False,sheet='Goalie DB')
|
101
164
|
|
102
165
|
if 'info' in types:
|
103
|
-
team_info = pd.read_csv('teaminfo/nhl_teaminfo.csv')
|
104
|
-
country = pd.read_csv('teaminfo/nhl_countryinfo.csv')
|
166
|
+
team_info = pd.read_csv('tools/teaminfo/nhl_teaminfo.csv')
|
167
|
+
country = pd.read_csv('tools/teaminfo/nhl_countryinfo.csv')
|
105
168
|
|
106
169
|
spread.df_to_sheet(team_info,index=False,sheet='Team Info')
|
107
170
|
spread.df_to_sheet(country,index=False,sheet='Country Info')
|
@@ -125,7 +125,7 @@ def server(input, output, session):
|
|
125
125
|
game_info = reactive.Value(None)
|
126
126
|
|
127
127
|
def get_schedule():
|
128
|
-
games = pd.read_csv('https://
|
128
|
+
games = pd.read_csv('https://weakside-breakout.s3.us-east-2.amazonaws.com/info/schedule.csv')
|
129
129
|
|
130
130
|
return games.loc[games['gameState'].isin(['OFF','FINAL'])]
|
131
131
|
|
@@ -139,6 +139,7 @@ def server(input, output, session):
|
|
139
139
|
|
140
140
|
defaults = {
|
141
141
|
'game_id':['2024020001'],
|
142
|
+
'title':['true']
|
142
143
|
}
|
143
144
|
|
144
145
|
for key in defaults.keys():
|
@@ -180,9 +181,9 @@ def server(input, output, session):
|
|
180
181
|
info = game_info.get()
|
181
182
|
season = info['season']
|
182
183
|
#Load appropriate dataframe
|
183
|
-
df = pd.read_parquet(f'https://
|
184
|
-
goalie_df = pd.read_parquet(f'https://
|
185
|
-
pbp = pd.read_parquet(f'https://
|
184
|
+
df = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/game_log/wsba_nhl_{season}_game_log.parquet')
|
185
|
+
goalie_df = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/game_log/goalie/wsba_nhl_{season}_game_log_goalie.parquet')
|
186
|
+
pbp = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/pbp/{season}.parquet')
|
186
187
|
|
187
188
|
game_df.set([df.loc[(df['Game']==info['game_id'])], pbp.loc[(pbp['game_id']==info['game_id'])&(pbp['event_type']=='goal')], goalie_df.loc[(goalie_df['Game']==info['game_id'])]])
|
188
189
|
|
@@ -247,7 +248,7 @@ def server(input, output, session):
|
|
247
248
|
@output
|
248
249
|
@render.text
|
249
250
|
def game_header():
|
250
|
-
return game_info.get()['title']
|
251
|
+
return game_info.get()['title'] if active_params()['title'][0] == 'true' else None
|
251
252
|
|
252
253
|
@output
|
253
254
|
@render.text
|
@@ -0,0 +1,101 @@
|
|
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_goalie"),
|
14
|
+
)
|
15
|
+
|
16
|
+
def server(input, output, session):
|
17
|
+
@output()
|
18
|
+
@render_widget
|
19
|
+
def plot_goalie():
|
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 goalie and plot all 5v5 fenwick shots
|
26
|
+
defaults = {
|
27
|
+
'goalie':['8471679'],
|
28
|
+
'season':['20142015'],
|
29
|
+
'team':['MTL'],
|
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(setting='offense',vertical=True)
|
54
|
+
else:
|
55
|
+
rink = wsba_plt.wsba_rink(setting='offense',vertical=True)
|
56
|
+
|
57
|
+
try:
|
58
|
+
plot = wsba_plt.heatmap(df,goalie=query['goalie'][0],team=query['team'][0],events=['missed-shot','shot-on-goal','goal'],strengths=query['strength_state'])
|
59
|
+
|
60
|
+
for trace in plot.data:
|
61
|
+
rink.add_trace(trace)
|
62
|
+
|
63
|
+
player = query['goalie'][0]
|
64
|
+
season = int(season[0:4])
|
65
|
+
team = query['team'][0]
|
66
|
+
strengths = 'All Situations' if len(query['strength_state']) == 4 else query['strength_state']
|
67
|
+
span = 'Regular Season' if query['season_type'][0]=='2' else 'Playoffs'
|
68
|
+
|
69
|
+
return rink.update_layout(
|
70
|
+
title=dict(
|
71
|
+
text=f'{player} GSAx at {strengths}; {season}-{season+1}, {span}, {team}',
|
72
|
+
x=0.5, y=0.96,
|
73
|
+
xanchor='center',
|
74
|
+
yanchor='top',
|
75
|
+
font=dict(color='white')
|
76
|
+
),
|
77
|
+
).add_annotation(
|
78
|
+
text='Lower GSAx',
|
79
|
+
xref="paper",
|
80
|
+
yref="paper",
|
81
|
+
xanchor='right',
|
82
|
+
yanchor='top',
|
83
|
+
font=dict(color='white'),
|
84
|
+
x=0.3,
|
85
|
+
y=0.04,
|
86
|
+
showarrow=False
|
87
|
+
).add_annotation(
|
88
|
+
text='Higher GSAx',
|
89
|
+
xref="paper",
|
90
|
+
yref="paper",
|
91
|
+
xanchor='right',
|
92
|
+
yanchor='top',
|
93
|
+
font=dict(color='white'),
|
94
|
+
x=0.76,
|
95
|
+
y=0.04,
|
96
|
+
showarrow=False
|
97
|
+
)
|
98
|
+
except:
|
99
|
+
return wsba_plt.wsba_rink(setting='offense',vertical=True)
|
100
|
+
|
101
|
+
app = App(app_ui, server)
|
@@ -0,0 +1,71 @@
|
|
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,goalie,team,events,strengths):
|
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.loc[(df['event_type'].isin(events))&(df['x_adj'].notna())&(df['y_adj'].notna())]
|
17
|
+
df['x'] = np.where(df['x_adj']<0,-df['y_adj'],df['y_adj'])
|
18
|
+
df['y'] = abs(df['x_adj'])
|
19
|
+
df['event_distance'] = abs(df['event_distance'].fillna(0))
|
20
|
+
df = df.loc[(df['event_distance']<=89)&(df['y']<=89)&(df['empty_net']==0)]
|
21
|
+
|
22
|
+
y_min = 0
|
23
|
+
y_max = 100
|
24
|
+
|
25
|
+
df['G'] = (df['event_type']=='goal').astype(int)
|
26
|
+
df['strength_state_2'] = np.where(df['strength_state_2'].isin(['5v5','5v4','4v5']),df['strength_state_2'],'Other')
|
27
|
+
|
28
|
+
if strengths != 'all':
|
29
|
+
df = df.loc[((df['strength_state_2'].isin(strengths)))]
|
30
|
+
|
31
|
+
[x,y] = np.round(np.meshgrid(np.linspace(-42.5,42.5,85),np.linspace(y_min,y_max,(y_max-y_min))))
|
32
|
+
xgoals = griddata((df['x'],df['y']),df['xG']-df['G'],(x,y),method='cubic',fill_value=0)
|
33
|
+
xgoals_smooth = gaussian_filter(xgoals,sigma=3)
|
34
|
+
|
35
|
+
player_shots = df.loc[(df['event_goalie_id'].astype(str).str.contains(goalie))&(df['event_team_abbr_2']==team)]
|
36
|
+
[x,y] = np.round(np.meshgrid(np.linspace(-42.5,42.5,85),np.linspace(y_min,y_max,(y_max-y_min))))
|
37
|
+
xgoals_player = griddata((player_shots['x'],player_shots['y']),player_shots['xG']-player_shots['G'],(x,y),method='cubic',fill_value=0)
|
38
|
+
|
39
|
+
difference = (gaussian_filter(xgoals_player,sigma = 3)) - xgoals_smooth
|
40
|
+
data_min= difference.min()
|
41
|
+
data_max= difference.max()
|
42
|
+
|
43
|
+
if abs(data_min) > data_max:
|
44
|
+
data_max = data_min * -1
|
45
|
+
elif data_max > abs(data_min):
|
46
|
+
data_min = data_max * -1
|
47
|
+
|
48
|
+
fig = go.Figure(
|
49
|
+
data = go.Contour( x=np.linspace(-42.5,42,5,85),
|
50
|
+
y=np.linspace(y_min,y_max,(y_max-y_min)),
|
51
|
+
z=xgoals_smooth,
|
52
|
+
colorscale=[[0.0,'red'],[0.5,'#09090b'],[1.0,'blue']],
|
53
|
+
connectgaps=True,
|
54
|
+
contours=dict(
|
55
|
+
type='levels',
|
56
|
+
start = data_min,
|
57
|
+
end = data_max,
|
58
|
+
size=(data_max-data_min)/11
|
59
|
+
),
|
60
|
+
colorbar=dict(
|
61
|
+
len = 0.7,
|
62
|
+
orientation='h',
|
63
|
+
showticklabels=False,
|
64
|
+
thickness=15,
|
65
|
+
yref='paper',
|
66
|
+
yanchor='top',
|
67
|
+
y=0
|
68
|
+
))
|
69
|
+
)
|
70
|
+
|
71
|
+
return fig
|
@@ -44,7 +44,7 @@ def server(input, output, session):
|
|
44
44
|
#Determine which season to load based on the input
|
45
45
|
season = query['season'][0]
|
46
46
|
#Load appropriate dataframe
|
47
|
-
df = pd.read_parquet(f'https://
|
47
|
+
df = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/pbp/{season}.parquet')
|
48
48
|
|
49
49
|
#Prepare dataframe for plotting based on URL parameters
|
50
50
|
df = df.loc[(df['season'].astype(str).isin(query['season']))&(df['season_type'].astype(str).isin(query['season_type']))].replace({np.nan: None})
|
@@ -13,6 +13,7 @@ def heatmap(df,skater,team,events,strengths,onice):
|
|
13
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
14
|
df['strength_state_2'] = df['strength_state'].str[::-1]
|
15
15
|
|
16
|
+
df = df.fillna(0)
|
16
17
|
df = df.loc[(df['event_type'].isin(events))&(df['x_adj'].notna())&(df['y_adj'].notna())]
|
17
18
|
if onice == 'for':
|
18
19
|
df['x'] = abs(df['x_adj'])
|
@@ -38,6 +39,7 @@ def heatmap(df,skater,team,events,strengths,onice):
|
|
38
39
|
df['onice_against'] = np.where(df['away_team_abbr']==df['event_team_abbr'],df['home_on_ice'],df['away_on_ice'])
|
39
40
|
|
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')
|
41
43
|
|
42
44
|
if strengths != 'all':
|
43
45
|
if onice == 'against':
|
@@ -222,7 +222,7 @@ def rink(setting = "full", vertical = False):
|
|
222
222
|
)
|
223
223
|
|
224
224
|
# Add logo
|
225
|
-
logo = Image.open(rs.get('https://
|
225
|
+
logo = Image.open(rs.get('https://weakside-breakout.s3.us-east-2.amazonaws.com/utils/wsba.png',stream=True).raw)
|
226
226
|
|
227
227
|
fig.add_layout_image(
|
228
228
|
dict(
|
@@ -50,12 +50,12 @@ def server(input, output, session):
|
|
50
50
|
season_2 = query['season_2'][0]
|
51
51
|
#Load appropriate dataframes
|
52
52
|
if season_1 == season_2:
|
53
|
-
df_1 = pd.read_parquet(f'https://
|
53
|
+
df_1 = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/pbp/{season_1}.parquet')
|
54
54
|
df_2 = df_1
|
55
55
|
|
56
56
|
else:
|
57
|
-
df_1 = pd.read_parquet(f'https://
|
58
|
-
df_2 = pd.read_parquet(f'https://
|
57
|
+
df_1 = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/pbp/{season_1}.parquet')
|
58
|
+
df_2 = pd.read_parquet(f'https://weakside-breakout.s3.us-east-2.amazonaws.com/pbp/{season_2}.parquet')
|
59
59
|
|
60
60
|
events = ['missed-shot','shot-on-goal','goal']
|
61
61
|
team_xg = {}
|
@@ -12,6 +12,7 @@ def wsba_rink(setting='full', vertical=False):
|
|
12
12
|
def heatmap_prep(df,team,events,strengths,onice,flip=False):
|
13
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
14
|
|
15
|
+
df = df.fillna(0)
|
15
16
|
df = df.loc[(df['event_type'].isin(events))&(df['x_adj'].notna())&(df['y_adj'].notna())]
|
16
17
|
if flip:
|
17
18
|
if onice == 'for':
|
@@ -55,6 +56,7 @@ def heatmap_prep(df,team,events,strengths,onice,flip=False):
|
|
55
56
|
df['onice_against'] = np.where(df['away_team_abbr']==df['event_team_abbr'],df['home_on_ice'],df['away_on_ice'])
|
56
57
|
|
57
58
|
df['strength_state'] = np.where(df['strength_state'].isin(['5v5','5v4','4v5']),df['strength_state'],'Other')
|
59
|
+
df['strength_state_2'] = np.where(df['strength_state_2'].isin(['5v5','5v4','4v5']),df['strength_state_2'],'Other')
|
58
60
|
|
59
61
|
if strengths != 'all':
|
60
62
|
df = df.loc[((df['strength_state'].isin(strengths)))]
|
@@ -222,7 +222,7 @@ def rink(setting = "full", vertical = False):
|
|
222
222
|
)
|
223
223
|
|
224
224
|
# Add logo
|
225
|
-
logo = Image.open(rs.get('https://
|
225
|
+
logo = Image.open(rs.get('https://weakside-breakout.s3.us-east-2.amazonaws.com/utils/wsba.png',stream=True).raw)
|
226
226
|
|
227
227
|
fig.add_layout_image(
|
228
228
|
dict(
|