Skip to content

Instantly share code, notes, and snippets.

@OTStats
Created February 26, 2025 03:49
Show Gist options
  • Save OTStats/2a94ee1a10efa05b26c0f292530a04d6 to your computer and use it in GitHub Desktop.
Save OTStats/2a94ee1a10efa05b26c0f292530a04d6 to your computer and use it in GitHub Desktop.
# -- Load libraries
library(tidyverse)
library(glue)
library(ggpath)
# -- Read data
df <- read_csv("Downloads/20250222_shots_2024.csv") %>%
janitor::clean_names()
df %>% tail()
# # -- Look at goalies goals allowed over expected
# df %>%
# filter(
# # shot_was_on_goal == 1,
# event %in% c("SHOT", "GOAL"),
# shot_on_empty_net == 0
# ) %>%
# group_by(goalie_name_for_shot) %>%
# summarise(goals_allowed = sum(goal),
# xg = sum(x_goal),
# diff = xg - goals_allowed) %>%
# arrange(diff)
prepped_for_viz <-
df %>%
filter(
# shot_was_on_goal == 1,
# event %in% c("SHOT", "GOAL"),
shot_on_empty_net == 0
) %>%
transmute(
id,
team = if_else(is_home_team == 1, away_team_code, home_team_code),
goalie_name_for_shot,
xg = x_goal,
goal
) %>%
group_by(team, goalie_name_for_shot) %>%
mutate(
goalie_shot_id = row_number(),
cum_xg = cumsum(xg),
cum_ga = cumsum(goal),
goal_xg_diff = cum_ga - cum_xg
)
# -- Pull in NHL logos
# Courtesy of Ivo Villanueva CSV
# Need to manually adjust some team abbrevation in order to join tables
data_git_nhl <- read.csv("https://raw.githubusercontent.com/IvoVillanueva/NHL/main/dataNHL.csv")
logos_df <-
data_git_nhl %>%
transmute(
team = str_to_upper(url_abr),
logo = espn_logo,
primary
) %>%
distinct() %>%
add_row(team = "SEA") %>%
add_row(team = "UTA") %>%
mutate(
team =
case_when(
team == "TB" ~ "TBL",
team == "VGS" ~ "VGK",
team == "LA" ~ "LAK",
team == "NJ" ~ "NJD",
team == "SJ" ~ "SJS",
team == "SEA" ~ "SEA",
team == "UTA" ~ "UTA",
TRUE ~ team
)
) %>%
mutate(logo = case_when(
team == "VGK" ~ "https://a.espncdn.com/i/teamlogos/nhl/500/vgs.png",
team == "SEA" ~ "https://a.espncdn.com/i/teamlogos/nhl/500/sea.png",
team == "UTA" ~ "https://a.espncdn.com/i/teamlogos/nhl/500/utah.png",
TRUE ~ logo),
primary = case_when(
team == "SEA" ~ "#001628",
team == "UTA" ~ "#71AFE5",
TRUE ~ primary
)
)
prepped_for_viz %>%
left_join(
logos_df, by = "team"
) %>%
mutate(x = if_else(goalie_shot_id == 100, 100, NA),
y = if_else(goalie_shot_id == 100, 25, NA)) %>%
mutate(logo = if_else(!is.na(x), logo, NA)) %>%
# filter(any(goalie_shot_id > 750)) %>%
ggplot(
aes(
x = goalie_shot_id,
goal_xg_diff,
color = primary)
) +
geom_from_path(
# data = logos_df %>% filter(team != "ARI"),
aes(x = x, y = y, path = logo),
width = 0.15, inherit.aes = FALSE) +
geom_line(
aes(group = goalie_name_for_shot),
size = .4
) +
geom_hline(yintercept = 0) +
scale_x_continuous(minor_breaks = NULL,
labels = scales::comma_format(),
# labels = c(0, "", 500, "", "1,000", "")
) +
scale_y_continuous(
minor_breaks = NULL,
limits = c(-35, 35),
breaks = seq(-30, 30, by = 10), expand = c(0,0)) +
scale_color_identity() +
facet_wrap(
~team,
ncol = 4
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0, size = 16, face = "bold"),
plot.subtitle = element_text(hjust = 0, size = 12),
axis.title = element_text(size = 8),
axis.text = element_text(size = 6),
panel.grid.major = element_line(linewidth = .4),
strip.background = element_blank(),
strip.text = element_blank(),
plot.margin = margin(12, 12, 12, 12)
) +
labs(
title = "NHL 2025: Goals Prevented by Goaltender",
subtitle = "Cumulative goals prevented from all shots faced in NHL | Each line is a different goaltender",
y = "",
x = "Cumulative Shot Faced",
caption = "Created by @OTStats\nData as of 2/24/2025\nData Source: @MoneyPuck.com"
)
ggsave(
filename = "20250225 NHL goaltender goals prevented.png",
height = 12, width = 8, dpi = "print", bg = "white"
)
install.packages("gghighlight")
library(gghighlight)
prepped_for_viz %>%
left_join(
logos_df, by = "team"
) %>%
ggplot(
aes(
x = goalie_shot_id,
y = goal_xg_diff,
group = str_c(goalie_name_for_shot, "-", team)
)
) +
geom_line(aes(color = primary)) +
gghighlight(any(goal_xg_diff < -22) || any(goal_xg_diff > 10), use_group_by = T) +
scale_color_identity()
# event %in% c("SHOT", "GOAL")
#
# goalieNameForShot
# team
# teamcode # team that shot
# shotWasOnGoal
# shotOnEmptyNet
@OTStats
Copy link
Author

OTStats commented Feb 26, 2025

20250225 NHL goaltender goals prevented

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment