Created
February 27, 2024 17:00
-
-
Save gallochris/d3e8e65809b4e87bc7a05b97e05d27d2 to your computer and use it in GitHub Desktop.
Possession plot for basketball
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# use bigballR to fetch schedule | |
schedule <- | |
bigballR::get_team_schedule(season = "2023-24", team.name = "North Carolina") | |
# grab miami home game pbp | |
unc_miami_pbp <- bigballR::get_play_by_play(schedule$Game_ID[28]) | |
# add index to determine first half and second half | |
um_index <- which(unc_miami_pbp$Half_Status == 2)[1] | |
# denote when the half changes | |
# could also maybe do this smarter? | |
# divide up by every 10/20 possessions? | |
first_half_poss <- unc_miami_pbp$Poss_Num[um_index] / 2 | |
# manipulate the data for a viz | |
canes_heels <- unc_miami_pbp |> | |
dplyr::mutate( | |
scoring = dplyr::case_match(Event_Result, | |
"made" ~ TRUE, | |
"missed" ~ FALSE, | |
NA ~ FALSE), | |
pts_value = dplyr::case_when( | |
Event_Type == "Turnover" ~ -1, | |
Event_Result == "missed" & Shot_Value %in% c(1, 2, 3) ~ 0, | |
Event_Result == "made" & Shot_Value == 1 ~ 1, | |
Event_Result == "made" & Shot_Value == 2 ~ 2, | |
Event_Result == "made" & Shot_Value == 3 ~ 3, | |
.default = 0 | |
), | |
pts_shape = dplyr::case_match(pts_value, | |
-1 ~ 4, | |
0 ~ 48, | |
1 ~ 49, | |
2 ~ 50, | |
3 ~ 51) | |
) | |
# make the plot using geom_point with different shapes | |
# could productionize this into a function for _any_ game | |
# in order to do that, would need to determine points per trip | |
# and any annotations separately | |
canes_heels_plot <- canes_heels |> | |
ggplot2::ggplot(ggplot2::aes( | |
x = Poss_Num / 2, | |
y = Poss_Team, | |
color = scoring, | |
size = pts_value / 2 | |
)) + | |
ggplot2::geom_point(ggplot2::aes(shape = factor(pts_shape)), | |
position = ggplot2::position_dodge(width = 0.5)) + | |
ggplot2::scale_color_manual(values = c("red", "darkgreen")) + | |
ggplot2::scale_shape_manual(values = c(4, 45, 49, 50, 51)) + | |
ggplot2::scale_x_continuous(breaks = seq(0, 75, 5), limits = c(0, 75)) + | |
ggplot2::geom_vline(xintercept = first_half_poss, | |
linetype = "dashed", | |
color = "#333333") + | |
ggplot2::annotate( | |
"rect", | |
fill = "yellow", | |
alpha = 0.1, | |
xmin = 126.5 / 2, | |
xmax = 144.5 / 2, | |
ymin = -Inf, | |
ymax = Inf | |
) + | |
ggthemes::theme_fivethirtyeight() + | |
ggplot2::theme( | |
legend.position = "none", | |
axis.text.y = cbbplotR::element_cbb_teams(size = 0.9), | |
panel.grid.major = ggplot2::element_blank(), | |
panel.grid.minor = ggplot2::element_blank(), | |
panel.background = ggplot2::element_blank() | |
) + | |
ggplot2::labs( | |
x = "Possessions", | |
y = "", | |
title = "North Carolina 75, Miami 71", | |
subtitle = "Green represents a scoring possession: three-pointers, two-pointers, free throws \nRed represents empty possessions: missed shots (-) or turnovers (x)", | |
caption = "Bless your chart | February 26, 2024 | data via bigballR + cbbplotR" | |
) + | |
ggplot2::annotate( | |
"label", | |
x = 10 / 2, | |
y = 1.5, | |
label = "Points per trip \nNorth Carolina 1.01 \nMiami 0.96", | |
size = 3, | |
color = "#333333", | |
fill = "floralwhite", | |
fontface = "bold" | |
) + | |
ggplot2::annotate( | |
"label", | |
x = 135 / 2, | |
y = 1.5, | |
label = "UNC: 0 made field goals \nlast 4:17 of game", | |
size = 2.5, | |
color = "#333333", | |
fill = "floralwhite", | |
fontface = "bold" | |
) + | |
ggplot2::annotate( | |
"label", | |
x = first_poss_num, | |
y = 2.55, | |
label = "Halftime", | |
size = 2.5, | |
color = "#333333", | |
fill = "floralwhite", | |
fontface = "bold" | |
) | |
# save the plot | |
ggplot2::ggsave( | |
"unc_miami_poss_plot.png", | |
canes_heels_plot, | |
w = 10, | |
h = 6, | |
dpi = 600, | |
type = 'cairo' | |
) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment