library('tidyverse')
library('gt')
library('gtExtras')
library('BasketballAnalyzeR')
bball_df <- read_csv("modern_RAPTOR_by_team.csv")NBA Metrics in the Regular Season and Playoffs - Posit Table Competition 2022
Basketball Players – Regular Season vs. Playoffs
There is a lot of discussion on how well top NBA players perform in the playoffs vs. during the regular season. I wanted to investigate and visualize the differences in performance (as measured by metrics such as points above average per 100 possessions added by player). The table shows a players stats for the regular season and the same stats for the playoffs. If the column is highlighted green in the “Regular season” section, it means that metric was higher compared to the post-season. If it’s highlighted red, it means it was lower than the post-season metric. Radial/spider plots also show how people perform on all the advanced metrics during the regular season and playoffs. This data was obtained from https://github.com/fivethirtyeight/data/blob/master/nba-raptor/README.md.
Here are the advanced metrics I used:
- RAPTOR: Points above average per 100 possessions added by player on both offense and defense, using both box and on-off components
- WAR: Wins Above Replacement
- PREDATOR: Predictive points above average per 100 possessions added by player on both offense and defense
Loading Libraries and Data
I focused on the top NBA players in the 21-22 season according to Ringer.com that made it to the playoffs:https://www.theringer.com/nba/2022/3/9/22967447/nba-top-25-players-2021-22-season
- Jimmy Butler 9 Chris Paul
- Demar DeRozan
- Ja Morant
- Luka Doncic
- Stephen Curry
- Kevin Durant
- Joel Embiid
- Giannis Antetokuompo
- Nikola Jokic
bball_tbl <- bball_df %>%
filter(season == 2022) %>%
filter(player_name %in% c("Jimmy Butler", "Chris Paul",
"DeMar DeRozan", "Ja Morant", "Luka Doncic",
"Stephen Curry", "Kevin Durant",
"Joel Embiid", "Giannis Antetokounmpo",
"Nikola Jokic"))First, I manually add all the images of the team logo to the data frame. I also format the data frame so that the regular season and playoff metrics are beside each other, instead of on different rows.
# Taking regular season stats and putting it into a data frame, while also adding images to the data frame.
bball_pre_df <- bball_tbl %>%
filter(season_type == "RS") %>% # Replace with your own file path:
mutate(logo = c("/Users/brendanlam/R Projects/Table_Contest_22/milwaukee.jpeg",
"/Users/brendanlam/R Projects/Table_Contest_22/miami.png",
"/Users/brendanlam/R Projects/Table_Contest_22/golden_state.png",
"/Users/brendanlam/R Projects/Table_Contest_22/chicago.png",
"/Users/brendanlam/R Projects/Table_Contest_22/dallas.png",
"/Users/brendanlam/R Projects/Table_Contest_22/brooklyn.png",
"/Users/brendanlam/R Projects/Table_Contest_22/philadelphia.png",
"/Users/brendanlam/R Projects/Table_Contest_22/denver.png",
"/Users/brendanlam/R Projects/Table_Contest_22/memphis.png",
"/Users/brendanlam/R Projects/Table_Contest_22/phoenix.png")) %>%
select(player_name, logo, season_type, poss, mp, war_reg_season, raptor_total, predator_total) %>%
dplyr::rename(reg_season = season_type)
# Taking playoff stats and putting it into a data frame.
bball_post_df <- bball_tbl %>%
filter(season_type == "PO") %>%
select(c(player_name, season_type, poss, mp, war_playoffs, raptor_total, predator_total)) %>%
dplyr::rename(post_season = season_type)
# Combining regular season and playoff stats so that they are side-by-side
bball_cmb_tbl <- bball_pre_df %>%
left_join(bball_post_df, by = "player_name") %>%
select(!c(reg_season, post_season)) %>%
mutate(radial_plots = rep(NA, nrow(bball_pre_df)))Next, I format the data so that it can be displayed in a radial/spider plot. I’ve displayed each of the plots up close.
- WRS = WAR metric for the regular season
- RRS = RAPTOR score for the regular season
- PRS = PREDATOR score for the regular season
- WP = WAR measure for the playoffs
- RP = RAPTOR score for the playoffs
- PP = PREDATOR score for the playoffs
# Creating radial plots for each player
# Creating data frame for data the we will use for radial plots
radar_data <- bball_cmb_tbl %>%
select(war_reg_season, raptor_total.x, predator_total.x, war_playoffs, raptor_total.y,
predator_total.y) %>%
dplyr::rename(WRS = war_reg_season,
RRS = raptor_total.x,
PRS = predator_total.x,
WP = war_playoffs,
RP = raptor_total.y,
PP = predator_total.y)
radial_plots <- list(rep(NA, 10))
for (i in 1:10) {
radial_plots[i] <- radialprofile(data=radar_data[i,], std=FALSE)
}Creating the table
# Create table
bball_cmb_tbl %>%
gt() %>%
tab_header(
title = md("**NBA Player Stats**"),
subtitle = md("Comparing performance during the regular and post=season for 2021-2022")
) %>%
# Renaming columns
cols_label(
player_name = "Name",
logo = "Team",
poss.x = "Possessions Played",
mp.x = "MP",
war_reg_season = "WAR",
raptor_total.x = "RAPTOR",
predator_total.x = "PREDATOR",
poss.y = "Possessions Played",
mp.y = "MP",
war_playoffs = "WAR",
raptor_total.y = "RAPTOR",
predator_total.y = "PREDATOR",
radial_plots = "Radial Plots"
) %>%
# Adding tab headers
tab_spanner(
label = "Regular Season",
columns = c(poss.x, mp.x, war_reg_season, raptor_total.x, predator_total.x) ) %>%
tab_spanner(
label = "Playoffs",
columns = c(poss.y, mp.y, war_playoffs, raptor_total.y, predator_total.y) ) %>%
# Centering text
cols_align(
align = "center",
columns = c(poss.x, war_reg_season, raptor_total.x, predator_total.x, war_playoffs,
poss.y, raptor_total.y, predator_total.y)) %>%
# Rounding to one decimal place
fmt_number(columns = c(war_reg_season, raptor_total.x, predator_total.x, poss.y, mp.y,
war_playoffs, raptor_total.y, predator_total.y), decimals = 1) %>%
# Regular Season WAR
tab_style(
style = list(
cell_fill(color = "#00BE67"),
cell_text(weight = "bold") ),
locations = cells_body(
columns = war_reg_season,
rows = war_reg_season > war_playoffs) ) %>%
# Regular Season RAPTOR
tab_style(
style = list(
cell_fill(color = "#00BE67"),
cell_text(weight = "bold") ),
locations = cells_body(
columns = raptor_total.x,
rows = raptor_total.x > raptor_total.y) ) %>%
tab_style(
style = list(
cell_fill(color = "#F8766D") ),
locations = cells_body(
columns = raptor_total.x,
rows = raptor_total.x < raptor_total.y) ) %>%
# Regular Season PREDATOR
tab_style(
style = list(
cell_fill(color = "#00BE67"),
cell_text(weight = "bold") ),
locations = cells_body(
columns = predator_total.x,
rows = predator_total.x > predator_total.y) ) %>%
tab_style(
style = list(
cell_fill(color = "#F8766D") ),
locations = cells_body(
columns = predator_total.x,
rows = predator_total.x < predator_total.y) ) %>%
# Playoffs WAR
tab_style(
style = list(
cell_fill(color = "#F8766D") ),
locations = cells_body(
columns = war_playoffs,
rows = war_reg_season > war_playoffs) ) %>%
# Playoffs RAPTOR
tab_style(
style = list(
cell_fill(color = "#00BE67"),
cell_text(weight = "bold") ),
locations = cells_body(
columns = raptor_total.y,
rows = raptor_total.x < raptor_total.y) ) %>%
tab_style(
style = list(
cell_fill(color = "#F8766D") ),
locations = cells_body(
columns = raptor_total.y,
rows = raptor_total.x > raptor_total.y) ) %>%
# Playoffs PREDATOR
tab_style(
style = list(
cell_fill(color = "#00BE67"),
cell_text(weight = "bold") ),
locations = cells_body(
columns = predator_total.y,
rows = predator_total.x < predator_total.y) ) %>%
tab_style(
style = list(
cell_fill(color = "#F8766D") ),
locations = cells_body(
columns = predator_total.y,
rows = predator_total.x > predator_total.y) ) %>%
# Adding images
gt_img_rows(columns = logo, img_source = "local", height = 30) %>%
tab_options(data_row.padding = px(1)) %>%
# Adding radial/spider plots
text_transform(
locations = cells_body(columns = c(radial_plots)),
fn = function(x) {
map(radial_plots, ggplot_image, height = px(300))
} ) %>%
# Adding footnotes
tab_footnote(
footnote = "Minutes Played",
locations = cells_column_labels(columns = c(mp.x, mp.y)) ) %>%
tab_footnote(
footnote = "Wins Above Replacement",
locations = cells_column_labels(columns = c(war_reg_season, war_playoffs) ) ) %>%
tab_footnote(
footnote = "Points above average per 100 possessions added by player on both offense and defense, using both box and on-off components",
locations = cells_column_labels(columns = c(raptor_total.x, raptor_total.y)) ) %>%
tab_footnote(
footnote = "Predictive points above average per 100 possessions added by player on both offense and defense",
locations = cells_column_labels(columns = c(predator_total.x, predator_total.y)) ) %>%
tab_footnote(
footnote = "Radial plots where regular season and playoff metrics are on the opposite side of each other. Points closer to the edge of the circle indicate higher scores.",
locations = cells_column_labels(columns = radial_plots) ) %>%
# Adding divider between Regular season and playoffs
gt_add_divider(
predator_total.x,
sides = "right",
color = "lightgrey",
style = "solid",
weight = px(2),
include_labels = TRUE
) %>%
tab_source_note(source_note = "From https://github.com/fivethirtyeight/data/blob/master/nba-raptor/README.md")| NBA Player Stats | ||||||||||||
| Comparing performance during the regular and post=season for 2021-2022 | ||||||||||||
| Name | Team | Regular Season | Playoffs | Radial Plots5 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Possessions Played | MP1 | WAR2 | RAPTOR3 | PREDATOR4 | Possessions Played | MP1 | WAR2 | RAPTOR3 | PREDATOR4 | |||
| Giannis Antetokounmpo | 4735 | 2204 | 12.0 | 7.7 | 6.8 | 934.0 | 448.0 | 3.0 | 9.7 | 7.4 | ||
| Jimmy Butler | 3882 | 1931 | 6.7 | 4.1 | 4.1 | 1,237.0 | 629.0 | 4.9 | 12.0 | 11.1 | ||
| Stephen Curry | 4644 | 2211 | 10.1 | 6.1 | 7.1 | 1,574.0 | 764.0 | 4.8 | 8.9 | 10.5 | ||
| DeMar DeRozan | 5717 | 2743 | 6.2 | 1.7 | 0.9 | 429.0 | 203.0 | 0.0 | −3.0 | −4.2 | ||
| Luka Doncic | 4611 | 2301 | 10.1 | 5.7 | 6.3 | 1,072.0 | 552.0 | 3.5 | 9.2 | 12.2 | ||
| Kevin Durant | 4314 | 2047 | 8.9 | 5.7 | 5.1 | 353.0 | 176.0 | −0.7 | −9.6 | −6.9 | ||
| Joel Embiid | 4640 | 2297 | 12.7 | 8.0 | 8.4 | 737.0 | 385.0 | 1.8 | 6.2 | 6.3 | ||
| Nikola Jokic | 5130 | 2476 | 22.7 | 14.9 | 14.7 | 351.0 | 171.0 | 1.2 | 10.3 | 12.2 | ||
| Ja Morant | 3993 | 1889 | 5.6 | 3.1 | 4.0 | 721.0 | 338.0 | 2.1 | 8.8 | 8.0 | ||
| Chris Paul | 4461 | 2139 | 6.9 | 3.6 | 4.5 | 868.0 | 448.0 | 2.0 | 5.9 | 4.4 | ||
| From https://github.com/fivethirtyeight/data/blob/master/nba-raptor/README.md | ||||||||||||
| 1 Minutes Played | ||||||||||||
| 2 Wins Above Replacement | ||||||||||||
| 3 Points above average per 100 possessions added by player on both offense and defense, using both box and on-off components | ||||||||||||
| 4 Predictive points above average per 100 possessions added by player on both offense and defense | ||||||||||||
| 5 Radial plots where regular season and playoff metrics are on the opposite side of each other. Points closer to the edge of the circle indicate higher scores. | ||||||||||||