Skip to main content

๐Ÿ’๐ŸŒ European and college hockey with sportsdataverse-py

This page is the executed notebook 17_european_college_hockey_intro.ipynb: download it to run it yourself.

North America's minor and junior leagues have their own notebook (11_junior_hockey_intro). This one crosses the Atlantic and drops into the NCAA:

LeagueModuleProvider
SHL (Sweden)sportsdataverse.hockey.shlshl.se
Liiga (Finland)sportsdataverse.hockey.liigaliiga.fi
DEL (Germany)sportsdataverse.hockey.del_DEL (eSports feed)
KHLsportsdataverse.hockey.khlkhl.ru
NCAA men's / women's hockeysportsdataverse.hockey.mch / .wchESPN

DEL's package is del_, because del is a Python keyword. The European runtimes take the season as its END year (2026 is 2025-26) and space requests at least a second apart, so be patient. โณ

๐Ÿงฐ The toolboxโ€‹

FunctionWhat it gives you
shl_scheduleSchedule and results of an SHL season
shl_pbpSHL play-by-play with shot locations (2023/24 on)
liiga_standingsLiiga standings
liiga_gamesEvery Liiga game of a season, with xG
liiga_shotmapOne Liiga game's shots
del_scheduleDEL schedule and results
del_standingsDEL standings
del_shotsOne DEL game's shots with rink coordinates
khl_standingsKHL regular-season standings
espn_mch_standingsNCAA men's hockey standings
espn_wch_scoreboardNCAA women's hockey scoreboard

๐Ÿ”Œ Setupโ€‹

pip install "sportsdataverse[sdvplot]"
import matplotlib.pyplot as plt
import polars as pl

from sportsdataverse.hockey import del_, khl, liiga, mch, shl, wch

pl.Config.set_tbl_rows(10)
SEASON = 2026 # END year: the completed 2025-26 season

Provider feeds are seasonal and occasionally rate-limited, so a tiny safe() helper runs each call defensively: you get the frame when the feed is up, and a one-line skip when it isn't, naming whether the answer was nothing there (NoDataError) or the fetch failed (AssetFetchError). ๐Ÿ›Ÿ

from sportsdataverse.errors import AssetFetchError, NoDataError

def safe(label, thunk):
try:
out = thunk()
print(f"โœ… {label}")
return out
except (NoDataError, AssetFetchError) as e:
print(f"\u23ed\ufe0f {label}: {type(e).__name__}: {e}")
return None

๐Ÿ‡ธ๐Ÿ‡ช SHLโ€‹

shl_schedule returns every game of a season with its game_uuid; shl_pbp takes that uuid.

shl_sched = safe(f"SHL schedule {SEASON}", lambda: shl.shl_schedule(SEASON))
cols = ["start_date_time", "home_team_code", "home_team_score", "away_team_code", "away_team_score", "state"]
shl_sched.select([c for c in cols if c in shl_sched.columns]).tail(5) if shl_sched is not None else None
โœ… SHL schedule 2026





shape: (5, 6)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ start_date_time โ”† home_team_code โ”† home_team_score โ”† away_team_code โ”† away_team_scor โ”† state โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”† e โ”† --- โ”‚
โ”‚ str โ”† str โ”† i64 โ”† str โ”† --- โ”† str โ”‚
โ”‚ โ”† โ”† โ”† โ”† i64 โ”† โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ 2026-03-14 โ”† TIK โ”† 1 โ”† VLH โ”† 3 โ”† post-game โ”‚
โ”‚ 15:15:00 โ”† โ”† โ”† โ”† โ”† โ”‚
โ”‚ 2026-03-14 โ”† LHC โ”† 3 โ”† OHK โ”† 2 โ”† post-game โ”‚
โ”‚ 15:15:00 โ”† โ”† โ”† โ”† โ”† โ”‚
โ”‚ 2026-03-14 โ”† DIF โ”† 2 โ”† SAIK โ”† 3 โ”† post-game โ”‚
โ”‚ 15:15:00 โ”† โ”† โ”† โ”† โ”† โ”‚
โ”‚ 2026-03-14 โ”† BIF โ”† 3 โ”† HV71 โ”† 4 โ”† post-game โ”‚
โ”‚ 15:15:00 โ”† โ”† โ”† โ”† โ”† โ”‚
โ”‚ 2026-03-14 โ”† FHC โ”† 4 โ”† MIF โ”† 1 โ”† post-game โ”‚
โ”‚ 15:15:00 โ”† โ”† โ”† โ”† โ”† โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
done = shl_sched.filter(pl.col("state") == "post-game") if shl_sched is not None else None
guid = done["game_uuid"][-1] if done is not None and done.height else None
shl_pbp = safe("SHL pbp", lambda: shl.shl_pbp(guid)) if guid else None
(shl_pbp["type"].value_counts(sort=True) if shl_pbp is not None and shl_pbp.height
else "no SHL play-by-play")
โœ… SHL pbp





shape: (7, 2)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ type โ”† count โ”‚
โ”‚ --- โ”† --- โ”‚
โ”‚ str โ”† u32 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ shot โ”† 84 โ”‚
โ”‚ goalkeeper โ”† 6 โ”‚
โ”‚ goal โ”† 5 โ”‚
โ”‚ insight โ”† 4 โ”‚
โ”‚ penalty โ”† 3 โ”‚
โ”‚ period โ”† 3 โ”‚
โ”‚ timeout โ”† 1 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ‡ซ๐Ÿ‡ฎ Liigaโ€‹

liiga_standings defaults to the current season. liiga_games carries both teams' goals per game, and liiga_shotmap one game's shots.

lst = safe("Liiga standings", liiga.liiga_standings)
cols = ["tournament", "ranking", "team_name", "games", "wins", "losses", "points", "goals", "goals_against"]
(lst.filter(pl.col("tournament") == lst["tournament"][0])
.select([c for c in cols if c in lst.columns]).sort("ranking").head(8)
if lst is not None and lst.height else "standings unavailable")
โœ… Liiga standings





shape: (8, 9)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ tournament โ”† ranking โ”† team_name โ”† games โ”† โ€ฆ โ”† losses โ”† points โ”† goals โ”† goals_against โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”† โ”† --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† i64 โ”† str โ”† i64 โ”† โ”† i64 โ”† i64 โ”† i64 โ”† i64 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ runkosarja โ”† 1 โ”† Lukko โ”† 17 โ”† โ€ฆ โ”† 4 โ”† 35 โ”† 46 โ”† 32 โ”‚
โ”‚ runkosarja โ”† 2 โ”† SaiPa โ”† 16 โ”† โ€ฆ โ”† 3 โ”† 34 โ”† 49 โ”† 27 โ”‚
โ”‚ runkosarja โ”† 3 โ”† Ilves โ”† 17 โ”† โ€ฆ โ”† 5 โ”† 32 โ”† 48 โ”† 36 โ”‚
โ”‚ runkosarja โ”† 4 โ”† Jukurit โ”† 18 โ”† โ€ฆ โ”† 6 โ”† 32 โ”† 44 โ”† 35 โ”‚
โ”‚ runkosarja โ”† 5 โ”† JYP โ”† 14 โ”† โ€ฆ โ”† 3 โ”† 30 โ”† 44 โ”† 35 โ”‚
โ”‚ runkosarja โ”† 6 โ”† Kรคrpรคt โ”† 18 โ”† โ€ฆ โ”† 4 โ”† 30 โ”† 51 โ”† 50 โ”‚
โ”‚ runkosarja โ”† 7 โ”† ร„ssรคt โ”† 17 โ”† โ€ฆ โ”† 6 โ”† 28 โ”† 38 โ”† 40 โ”‚
โ”‚ runkosarja โ”† 8 โ”† TPS โ”† 17 โ”† โ€ฆ โ”† 7 โ”† 27 โ”† 47 โ”† 42 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
lg = safe("Liiga games", liiga.liiga_games)
fin = lg.filter(pl.col("ended") == True) if lg is not None else None
if fin is not None and fin.height:
g = fin.row(-1, named=True)
sm = safe(f"Liiga shotmap {g['game_id']}", lambda: liiga.liiga_shotmap(g["season"], g["game_id"]))
print(g["home_name"], g["home_goals"], "-", g["away_goals"], g["away_name"])
out = sm.group_by("event_type").len() if sm is not None and sm.height else "no shotmap"
else:
out = "no finished Liiga games"
out
โœ… Liiga games


โœ… Liiga shotmap 2701415
Sport 1 - 3 SaiPa





shape: (4, 2)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”
โ”‚ event_type โ”† len โ”‚
โ”‚ --- โ”† --- โ”‚
โ”‚ str โ”† u32 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•ก
โ”‚ PLAYER_BLOCKED โ”† 25 โ”‚
โ”‚ MISSED โ”† 27 โ”‚
โ”‚ GOAL โ”† 4 โ”‚
โ”‚ GOALIE_BLOCKED โ”† 41 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ‡ฉ๐Ÿ‡ช DELโ€‹

del_standings and del_schedule take the END year; del_shots a match_id.

dst = safe(f"DEL standings {SEASON}", lambda: del_.del_standings(SEASON))
cols = ["position", "name", "games", "wins", "wins_ot", "losses_ot", "losses", "points"]
dst.select([c for c in cols if c in dst.columns]).sort("position").head(8) if dst is not None else None
โœ… DEL standings 2026





shape: (8, 8)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ position โ”† name โ”† games โ”† wins โ”† wins_ot โ”† losses_ot โ”† losses โ”† points โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”† --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ i64 โ”† str โ”† i64 โ”† i64 โ”† i64 โ”† i64 โ”† i64 โ”† i64 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ 1 โ”† Kรถlner Haie โ”† 52 โ”† 36 โ”† 3 โ”† 2 โ”† 11 โ”† 116 โ”‚
โ”‚ 2 โ”† Adler Mannheim โ”† 52 โ”† 29 โ”† 6 โ”† 4 โ”† 13 โ”† 103 โ”‚
โ”‚ 3 โ”† Straubing Tigers โ”† 52 โ”† 32 โ”† 2 โ”† 1 โ”† 17 โ”† 101 โ”‚
โ”‚ 4 โ”† EHC Red Bull Mรผnchen โ”† 52 โ”† 29 โ”† 5 โ”† 3 โ”† 15 โ”† 100 โ”‚
โ”‚ 5 โ”† ERC Ingolstadt โ”† 52 โ”† 28 โ”† 5 โ”† 0 โ”† 19 โ”† 94 โ”‚
โ”‚ 6 โ”† Eisbรคren Berlin โ”† 52 โ”† 23 โ”† 6 โ”† 4 โ”† 19 โ”† 85 โ”‚
โ”‚ 7 โ”† Pinguins Bremerhaven โ”† 52 โ”† 24 โ”† 4 โ”† 3 โ”† 21 โ”† 83 โ”‚
โ”‚ 8 โ”† Grizzlys Wolfsburg โ”† 52 โ”† 20 โ”† 3 โ”† 7 โ”† 22 โ”† 73 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

A DEL shot map ๐ŸŽฏโ€‹

del_shots ships coordinate_x / coordinate_y in the provider's own frame (both axes run about -100 to 100), plus team_side and is_goal. sdvplot has no mapping from this frame to a regulation IIHF rink yet, so the chart below plots the raw frame rather than drawing a rink under it.

dsched = safe(f"DEL schedule {SEASON}", lambda: del_.del_schedule(SEASON))
mid = int(dsched.filter(pl.col("final_score_home").is_not_null())["match_id"][-1]) if dsched is not None else None
dshots = safe(f"DEL shots {mid}", lambda: del_.del_shots(mid)) if mid else None
if dshots is not None and dshots.height:
fig, ax = plt.subplots(figsize=(8, 5))
for side, color in (("home", "#1f77b4"), ("visitor", "#ff7f0e")):
s = dshots.filter(pl.col("team_side") == side)
name = s["home_name" if side == "home" else "visitor_name"][0] if s.height else side
ax.scatter(s["coordinate_x"], s["coordinate_y"], s=25, alpha=0.6, c=color, label=name)
goals = dshots.filter(pl.col("is_goal") == True)
ax.scatter(goals["coordinate_x"], goals["coordinate_y"], s=160, facecolors="none",
edgecolors="black", linewidths=1.5, label="goal")
ax.set_xlim(-105, 105)
ax.set_ylim(-105, 105)
ax.set_aspect("equal")
ax.legend(loc="upper center", ncol=3, fontsize=8)
ax.set_title(f"DEL match {mid}: {dshots.height} shots (provider frame)")
plt.show()
else:
print("no DEL shots for this match")
โœ… DEL schedule 2026


โœ… DEL shots 4304

png

๐Ÿ‡ท๐Ÿ‡บ KHLโ€‹

khl_standings returns one row per team per table (conference and division tables are stacked, tagged by table).

kst = safe("KHL standings", khl.khl_standings)
cols = ["table", "rank", "name", "gp", "w", "l", "pts", "goals_for", "goals_against"]
(kst.filter(pl.col("table") == kst["table"][0]).select([c for c in cols if c in kst.columns]).head(8)
if kst is not None and kst.height else "standings unavailable")
โœ… KHL standings





shape: (8, 9)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ table โ”† rank โ”† name โ”† gp โ”† โ€ฆ โ”† l โ”† pts โ”† goals_for โ”† goals_against โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”† โ”† --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† i64 โ”† str โ”† i64 โ”† โ”† i64 โ”† i64 โ”† i64 โ”† i64 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ league โ”† 1 โ”† ะœะตั‚ะฐะปะปัƒั€ะณ ะœะณ โ”† 20 โ”† โ€ฆ โ”† 3 โ”† 32 โ”† 67 โ”† 39 โ”‚
โ”‚ league โ”† 2 โ”† ะ›ะพะบะพะผะพั‚ะธะฒ โ”† 19 โ”† โ€ฆ โ”† 5 โ”† 28 โ”† 49 โ”† 33 โ”‚
โ”‚ league โ”† 3 โ”† ะฆะกะšะ โ”† 19 โ”† โ€ฆ โ”† 5 โ”† 28 โ”† 58 โ”† 36 โ”‚
โ”‚ league โ”† 4 โ”† ะ”ั€ะฐะบะพะฝั‹ โ”† 18 โ”† โ€ฆ โ”† 4 โ”† 26 โ”† 56 โ”† 44 โ”‚
โ”‚ league โ”† 5 โ”† ะกะฟะฐั€ั‚ะฐะบ โ”† 19 โ”† โ€ฆ โ”† 5 โ”† 25 โ”† 51 โ”† 35 โ”‚
โ”‚ league โ”† 6 โ”† ะะตั„ั‚ะตั…ะธะผะธะบ โ”† 19 โ”† โ€ฆ โ”† 6 โ”† 24 โ”† 55 โ”† 46 โ”‚
โ”‚ league โ”† 7 โ”† ะกะตะฒะตั€ัั‚ะฐะปัŒ โ”† 20 โ”† โ€ฆ โ”† 7 โ”† 24 โ”† 46 โ”† 43 โ”‚
โ”‚ league โ”† 8 โ”† ะขะพั€ะฟะตะดะพ โ”† 18 โ”† โ€ฆ โ”† 5 โ”† 24 โ”† 49 โ”† 36 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐ŸŽ“ College hockey (ESPN)โ€‹

The NCAA men's (mch) and women's (wch) leagues ride the cross-league ESPN wrappers. Team colors come from sdvplot's team_colors, keyed by ESPN team id under the ncaa_mhockey league key.

import sdvplot

cst = safe("NCAA men's hockey standings", mch.espn_mch_standings)
if cst is not None and cst.height:
top = cst.sort("wins", "win_percent", descending=True).head(15).sort("wins", "win_percent")
colors = sdvplot.team_colors("ncaa_mhockey", [str(i) for i in top["team_id"]])
colors = [c or "#999999" for c in colors]
fig, ax = plt.subplots(figsize=(7, 6))
ax.barh(top["team_display_name"], top["wins"], color=colors)
ax.set_xlabel("wins")
ax.set_title("NCAA men's hockey: the 15 teams with the most wins so far")
plt.tight_layout()
plt.show()
else:
print("standings unavailable")
โœ… NCAA men's hockey standings

png

wsb = safe("NCAA women's hockey scoreboard", wch.espn_wch_scoreboard)
cols = ["date", "short_name", "status_type_detail", "home_score", "away_score"]
wsb.select([c for c in cols if c in wsb.columns]) if wsb is not None and wsb.height else "no games today"
โœ… NCAA women's hockey scoreboard





shape: (1, 5)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ date โ”† short_name โ”† status_type_detail โ”† home_score โ”† away_score โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† str โ”† str โ”† str โ”† str โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ 2026-10-26T15:00Z โ”† MNST @ BC โ”† Mon, October 26th at 11:00 AM โ€ฆ โ”† 0 โ”† 0 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐ŸŽ‰ Where to nextโ€‹

  • More European homes under sportsdataverse.hockey: icehl, eihl, metal, elh, ha, nl, magnus, vhl and the Swiss sihf; each has a reference page in the sidebar.
  • khl_webcaster_* is a second KHL source with player and team tables per stage.
  • North American minor and junior leagues: 11_junior_hockey_intro; the PWHL: 10_pwhl_intro; the NHL: 07_nhl_intro.
  • Rinks and team colors: sdvplot and sportypy.