dunks <- tibble::tribble(
~season,~games,~class,~player,~school,~dunks,~attempts,~pct,
"2016-17",36,"Sophomore","Tacko Fall","UCF",104,108,.963,
"2017-18",36,"Sophomore","Udoka Azubuike","Kansas",122,132,.924,
"2018-19",32,"Sophomore","Daniel Gafford","Arkansas",86,91,.945,
"2019-20",31,"Sophomore","Obi Toppin","Dayton",107,115,.930,
"2020-21",31,"Sophomore","Kofi Cockburn","Illinois",78,82,.951,
"2021-22",32,"Sophomore","Clifford Omoruyi","Rutgers",93,107,.869,
"2022-23",34,"Sophomore","Aziz Bandaogo","Utah Valley",90,99,.909,
"2023-24",39,"Senior","Zach Edey","Purdue",113,120,.942,
"2024-25",35,"Senior","Ryan Kalkbrenner","Creighton",107,115,.930,
"2025-26",6,"Freshman","Caleb Wilson","North Carolina",25,27,.959
)
bball_header <-glue::glue(
"<div style='display: flex; justify-content: space-between; align-items: center;'>
<div>
<img src='https://a.espncdn.com/combiner/i?img=/redesign/assets/img/icons/ESPN-icon-basketball.png'
style='height: 40px; width: auto; vertical-align: middle;'>
</div>
<div style='flex-grow:1; margin-left: 30px; margin-right: 30px'>
<span style='display: block; font-weight: bold; text-align: center; font-size: 24px;'>Dunks per game over past 10 seasons</span>
<span style='font-size: 14px; font-weight: normal; display: block; text-align: center;'>Shows leaders in dunks per game and total dunks over past 10 seasons.</span>
</div>
<div>
<img src='https://a.espncdn.com/combiner/i?img=/redesign/assets/img/icons/ESPN-icon-basketball.png'
style='height: 40px; width: auto; vertical-align: middle;'>
</div>
</div>
<br>"
)
dunk_tbl <- dunks |>
dplyr::mutate(
dpg = dunks/games,
dunklist = paste0(dunks, "-", attempts, " (", pct, ")"),
gamelist = paste0(games, " games"),
class_school = paste0(class, " | ", school)
) |>
dplyr::arrange(-dpg) |>
dplyr::select(season, gamelist, player, class_school, dpg, dunklist) |>
gt::gt() |>
gt::fmt_number(
dpg, decimals = 2
) |>
gtUtils::gt_theme_gtutils() |>
gt::cols_align(
columns = c(player, class_school), align = "left") |>
gtExtras::gt_merge_stack(
col1 = season,
col2 = gamelist,
palette = c("black", "#333333")
) |>
gtExtras::gt_merge_stack(
col1 = player,
col2 = class_school,
palette = c("black", "#333333")
) |>
gtExtras::gt_merge_stack(
col1 = dpg,
col2 = dunklist,
palette = c("black", "#333333")
) |>
gtUtils::gt_column_subheaders(
season = list(heading = "Season", subtitle = "Total Games"),
player = list(heading = "Player", subtitle = "Class | Team"),
dpg = list(heading = "Dunks Per Game", subtitle = "Dunks-Attempts (%)"),
heading_color = "black",
subtitle_color = "gray"
) |>
gtUtils::gt_border_grid(color = "black",
weight = 0.5,
include_labels = FALSE) |>
gt::data_color(
columns = c(dpg),
direction = c("column"),
method = c("numeric"),
palette = c("#fdae61",
"#ffffbf", "#a6d96a",
"#1a9641"),
alpha = 0.6
) |>
gt::tab_header(title = gt::html(bball_header)) |>
gt::tab_source_note(
source_note =
gt::html(
"<hr>Data via barttorvik.com | theme via {gtUtils} <br>
<hr><b>Table by Chris at Bless your Chart | 2025-2026 data through November 25 games</b>"
)
) |>
gtUtils::gt_border_bars_bottom(c("#636363", "#969696", "#cccccc")) |>
gt::tab_options(table.width = gt::px(425)) |>
gt::tab_style(
locations = gt::cells_source_notes(),
style = gt::cell_text(
font = gt::google_font("Signika Negative"),
size = gt::px(11.5),
weight = 250
)
) |>
gt::tab_style(
style = list(
gt::cell_text(font = gt::google_font("Signika Negative"),
size = gt::px(14)
)
),
locations = gt::cells_body(
rows = gt::everything(),
columns = gt::everything()
)
) |>
gt::tab_style(
style = list(gt::cell_borders(
sides = c("left", "right", "top", "bottom"),
color = "black",
weight = gt::px(2)
)),
locations = list(
gt::cells_body(),
gt::cells_column_labels(),
gt::cells_row_groups()
)
)
gt_save_crop(
dunk_tbl,
file = "dunk_tbl.png",
whitespace = 40,
bg = "#FFFDF5"
)
dunk_tbl