055: Rush Defense

gt_table
Published

October 29, 2023

Load data

Code
# function to loop through years 
# years <- 2004:2023

# regular_season <- data.frame()

# for (year in years) {
  
#  team_stats <- cfbfastR::cfbd_game_team_stats(
#    year = year,
#    season_type = "regular",
#    team = "North Carolina",
#    rows_per_team = 1
#  ) |> 
#    dplyr::select(opponent, rushing_attempts_allowed, 
#                  rushing_yards_allowed, 
#                  yards_per_rush_attempt_allowed, 
#                  rush_tds_allowed)
  
#  team_stats <- team_stats |> 
#    dplyr::mutate(year = year) |> 
#    dplyr::relocate(year, .before = opponent)
  
#  regular_season <- rbind(regular_season, team_stats) |> 
#    dplyr::mutate_at(dplyr::vars(-opponent), as.numeric) # |> 
#    dplyr::arrange(-rushing_yards_allowed)
  
# }

# return(regular_season)

# }

wc <- readr::read_csv("wc.csv")

GT Athletic Theme

Code
gt_theme_athletic <- function(gt_object, ...) {
  
  # get id, if one is passed through to use with CSS
  table_id <- subset(gt_object[['_options']], parameter == 'table_id')$value[[1]]
  
  table <- gt_object |> 
    # set table font
    gt::opt_table_font(
      font = list(
        gt::google_font('Spline Sans Mono'),
        gt::default_fonts()
      ),
      weight = 500
    ) |> 
    # set the column label font and style
    gt::tab_style(
      locations = gt::cells_column_labels(
        columns = gt::everything()
      ),
      style = gt::cell_text(
        font = gt::google_font('Work Sans'),
        weight = 650,
        size = gt::px(14),
        transform = 'uppercase', # column labels to uppercase
        align = 'left'
      )
    ) |> 
    gt::tab_style(
      locations = gt::cells_title('title'),
      style = gt::cell_text(
        font = gt::google_font('Work Sans'),
        weight = 650
      )
    ) |> 
    gt::tab_style(
      locations = gt::cells_title('subtitle'),
      style = gt::cell_text(
        font = gt::google_font('Work Sans'),
        weight = 500
      )
    ) |>
    # set think black column sep.
    gt::tab_style(
      style = gt::cell_borders(sides = 'left', weight = gt::px(0.5), color = 'black'),
      locations = gt::cells_body(
        # everything but the first column
        columns = c(-names(gt_object[['_data']])[1])
      )
    ) |> 
    # set thin dotted row sep.
    gt::tab_style(
      style = gt::cell_borders(sides = "top", color = 'black', weight = gt::px(1.5), style = 'dotted'),
      locations = gt::cells_body(
        rows = gt::everything()
      )
    )|>
    # left align cell text
    gt::cols_align(
      align = 'left',
      columns = gt::everything()
    ) |> 
    gt::tab_options(
      table.font.size = 14,
      column_labels.border.bottom.width = 2,
      column_labels.border.bottom.color = 'black',
      column_labels.border.top.color = 'white',
      row_group.border.bottom.color = 'white',
      table.border.top.style = 'none',
      table.border.bottom.style = 'none',
      heading.border.bottom.style = 'none',
      heading.align = 'left',
      heading.title.font.size = gt::px(30),
      source_notes.border.lr.style = 'none',
      source_notes.font.size = 10
    )
  
  # add css if table id is passed through
  table <- if(!is.null(table_id)) {
    table |> 
      # remove the border from the bottom cell
      gt::opt_css(
        paste0("#", table_id, " tbody tr:last-child {border-bottom: 2px solid #ffffff00;}"),
        add = TRUE
      )
  }
  
  return(table)
  
}

GT Table

Code
rush_table <- wc |> 
  dplyr::mutate(logo = opponent) |>
  dplyr::relocate(logo, .before = opponent) |>
  dplyr::select(year, logo, opponent, result, 
               score, rushing_attempts_allowed, rushing_yards_allowed, yards_per_rush_attempt_allowed) |> 
  dplyr::arrange(-yards_per_rush_attempt_allowed) |>
  gt::gt() |>
  gt::cols_label(
    # rename columns
    year = "Season",
    logo = "",
    opponent = "Opponent",
    rushing_attempts_allowed = "Attempts",
    rushing_yards_allowed = "Yards",
    yards_per_rush_attempt_allowed = "Yds/Att"
  ) |>
  gt::tab_spanner(label = "Rush Defense",
                  columns = c(rushing_attempts_allowed, rushing_yards_allowed, yards_per_rush_attempt_allowed)) |>
  cfbplotR::gt_fmt_cfb_logo(columns = "logo") |>
  gt::data_color(
    columns = c(yards_per_rush_attempt_allowed),
    colors = scales::col_numeric(
      c(
        "lightpink",
        "#CBC3E3"
      ),
      domain = NULL
    )
  ) |>
  gtExtras::gt_highlight_rows(
    rows = c(8),
    fill = "#ffffd8",
    bold_target_only = FALSE
  ) |> 
  gt::tab_header(title = "North Carolina's Ugly Rush Defense", subtitle = "Highest yards per rush attempt by an opponent in a single game since 2009 season.") |>
  gt::tab_source_note(source_note = "Bless your chart | October 29 | data via SportSourceAnalytics + gt athletic theme from @andreweatherman")  |>
  gt_theme_athletic() |>
  gt::tab_style(style = list(gt::cell_borders(
    sides = c("left"),
    color = "#c1c1c1",
    weight = gt::px(2)
  )),
  locations = list(gt::cells_body(columns = c(result, rushing_attempts_allowed))))

gtExtras::gtsave_extra(rush_table,
                       filename = "rush.png",
                       vheight = 875,
                       vwidth = 650)

rush_table
North Carolina's Ugly Rush Defense
Highest yards per rush attempt by an opponent in a single game since 2009 season.
Season Opponent result score Rush Defense
Attempts Yards Yds/Att
2014 Rutgers L 21-40 42 340 8.10
2015 Baylor L 38-49 84 645 7.68
2018 Duke L 35-42 35 268 7.66
2014 East Carolina L 41-70 46 343 7.46
2015 Duke W 66-31 44 327 7.43
2014 Georgia Tech W 48-43 51 376 7.37
2011 Missouri L 24-41 46 337 7.33
2023 Georgia Tech L 42-46 48 348 7.25
2017 Louisville L 35-47 44 312 7.09
2022 Duke W 38-35 42 297 7.07
2021 Notre Dame L 34-44 42 296 7.05
Bless your chart | October 29 | data via SportSourceAnalytics + gt athletic theme from @andreweatherman