Skip to contents

Introduction

This vignette demonstrates how to create rich WBB (Women’s College Basketball) visualizations by combining wehoop for player and team data and sdvplotR for team logos, headshots, colors, and gt tables.

Setup

library(sdvplotR)
library(ggplot2)
library(wehoop)
library(dplyr)
library(gt)

# Get valid WBB team abbreviations
wbb_teams <- valid_team_names("wbb")
length(wbb_teams)  # ~350+ D1 teams
head(wbb_teams)

Loading WBB Data

Use wehoop to load this season’s ESPN team and player box scores:

# The last completed regular season (wehoop names a season for the year it
# ends; the regular season ends in mid-March)
season <- as.integer(format(Sys.Date(), "%Y")) -
  (format(Sys.Date(), "%m-%d") < "03-20")

# One row per team per game (ESPN box scores), regular season only; Division I
# teams only (the box scores also hold their games against other divisions)
team_stats <- wehoop::load_wbb_team_box(seasons = season) |>
  filter(season_type == 2, team_abbreviation %in% team_reference("wbb")$team_abbr)

# One row per player per game, with ESPN athlete IDs; players who did not
# play are dropped so games played counts real games
player_stats <- wehoop::load_wbb_player_box(seasons = season) |>
  filter(season_type == 2, !did_not_play)

WBB Team Performance

Visualize team performance with team logos:

# Calculate team metrics
team_perf <- team_stats |>
  filter(!is.na(team_abbreviation)) |>
  group_by(team_id, team_abbreviation) |>
  summarise(
    avg_points = mean(team_score, na.rm = TRUE),
    avg_rebounds = mean(total_rebounds, na.rm = TRUE),
    games = n(),
    .groups = "drop"
  ) |>
  filter(games >= 10)

ggplot(team_perf, aes(x = avg_points, y = avg_rebounds)) +
  geom_sdv_logos(
    aes(team = team_abbreviation),
    sport = "wbb",
    width = 0.075
  ) +
  labs(
    title = "WBB Team Performance",
    subtitle = paste("Season", season),
    x = "Average Points per Game",
    y = "Average Rebounds per Game",
    caption = "Data: wehoop | Viz: sdvplotR"
  ) +
  theme_minimal()

WBB Team Colors

Use team colors to visualize win percentages:

# Calculate win percentage
team_wins <- team_stats |>
  filter(!is.na(team_abbreviation)) |>
  group_by(team_id, team_abbreviation) |>
  summarise(
    wins = sum(team_winner, na.rm = TRUE),
    games = n(),
    .groups = "drop"
  ) |>
  filter(games >= 10) |>
  mutate(win_pct = wins / games) |>
  arrange(desc(win_pct)) |>
  head(25)

ggplot(team_wins, aes(x = reorder(team_abbreviation, win_pct), y = win_pct)) +
  geom_col(aes(fill = team_abbreviation), width = 0.7) +
  scale_fill_sdv(sport = "wbb", alpha = 0.8) +
  scale_y_continuous(labels = scales::percent) +
  labs(
    title = "Top 25 WBB Teams by Win Percentage",
    x = NULL,
    y = "Win Percentage"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "none"
  )

Player Headshots

Visualize top performers with player headshots:

# Top scorers
top_scorers <- player_stats |>
  filter(!is.na(athlete_id)) |>
  group_by(athlete_id, athlete_display_name) |>
  summarise(
    avg_points = mean(points, na.rm = TRUE),
    games = n(),
    .groups = "drop"
  ) |>
  filter(games >= 15) |>
  arrange(desc(avg_points)) |>
  head(8)

ggplot(top_scorers, aes(x = games, y = avg_points)) +
  geom_sdv_headshots(
    aes(player_id = athlete_id),
    sport = "wbb",
    height = 0.15
  ) +
  geom_label(
    aes(label = athlete_display_name),
    nudge_y = -1.5,
    size = 3,
    alpha = 0.7
  ) +
  labs(
    title = "Top 8 WBB Scorers",
    subtitle = paste("Season", season),
    x = "Games Played",
    y = "Average Points per Game"
  ) +
  theme_minimal()

Tournament Seeds with Logos

Plot a set of tournament seeds with team logos. These seeds are an example; swap in the real bracket once it is announced:

# For demonstration, create sample bracket data
bracket_data <- data.frame(
  seed = 1:16,
  team = c("SC", "LSU", "IOWA", "UCLA", "TEXAS", "NOTRE DAME",
           "STANFORD", "OREGON", "MARYLAND", "INDIANA", "VILLANOVA",
           "DUKE", "BAYLOR", "UTAH", "UNC", "MSU")
)

ggplot(bracket_data, aes(x = seed, y = 1)) +
  geom_sdv_logos(
    aes(team = team),
    sport = "wbb",
    width = 0.075
  ) +
  scale_x_continuous(breaks = 1:16) +
  labs(
    title = "NCAA Women's Tournament Seeds",
    subtitle = paste("Season", season),
    x = "Seed",
    y = NULL
  ) +
  theme_minimal() +
  theme(
    axis.text.y = element_blank(),
    panel.grid.major.y = element_blank(),
    panel.grid.minor = element_blank()
  )

WBB Team Tiers

Create a tier plot ranking WBB teams:

# Top 25 teams by win percentage
top_25 <- team_wins |>
  mutate(
    tier_no = case_when(
      win_pct > 0.85 ~ 1,
      win_pct > 0.75 ~ 2,
      win_pct > 0.65 ~ 3,
      win_pct > 0.55 ~ 4,
      TRUE ~ 5
    )
  ) |>
  select(tier_no, team = team_abbreviation)

sdv_team_tiers(
  top_25,
  sport = "wbb",
  title = "WBB Power Rankings",
  subtitle = paste("Example tiers,", season, "season"),
  tier_desc = c(
    "1" = "Elite",
    "2" = "Championship Contenders",
    "3" = "Top 25",
    "4" = "Bubble Teams",
    "5" = "Rebuilding"
  ),
  presort = TRUE
)

WBB Conference Map

Show each major conference’s teams in a column:

# The five major conferences, from the conferences sdvplotR keeps for every team
conference_map <- team_reference("wbb") |>
  filter(conference %in% c("ACC", "Big 12", "Big East", "Big Ten", "SEC")) |>
  arrange(conference, team_location) |>
  group_by(conference) |>
  mutate(team_rank = row_number()) |>
  ungroup() |>
  mutate(conference_num = as.numeric(factor(conference)))

ggplot(conference_map, aes(x = conference_num, y = team_rank)) +
  geom_sdv_logos(
    aes(team = team_abbr),
    sport = "wbb",
    width = 0.05
  ) +
  scale_x_continuous(
    breaks = seq_along(levels(factor(conference_map$conference))),
    labels = levels(factor(conference_map$conference))
  ) +
  scale_y_reverse() +
  labs(
    title = "WBB Teams in the Major Conferences",
    x = NULL,
    y = NULL
  ) +
  theme_minimal() +
  theme(
    axis.text.y = element_blank(),
    panel.grid = element_blank()
  )

WBB Standings Table with Logos

Create a gt table with team logos:

standings_table <- team_wins |>
  head(20) |>
  mutate(
    logo = team_abbreviation,
    rank = row_number()
  ) |>
  select(rank, logo, team_abbreviation, wins, games, win_pct)

standings_table |>
  gt() |>
  gt_sdv_logos(columns = "logo", sport = "wbb", height = 30) |>
  fmt_number(columns = "win_pct", decimals = 3) |>
  cols_label(
    rank = "#",
    logo = "Team",
    team_abbreviation = "Abbrev",
    wins = "Wins",
    games = "Games",
    win_pct = "Win %"
  ) |>
  tab_header(
    title = "WBB Top 20",
    subtitle = paste("Season", season)
  )

Axis Labels with Logos

Replace axis labels with team logos:

top_8 <- team_wins |>
  head(8) |>
  mutate(team_abbreviation = factor(team_abbreviation, levels = team_abbreviation))

ggplot(top_8, aes(x = team_abbreviation, y = win_pct)) +
  geom_col(aes(fill = team_abbreviation), width = 0.6) +
  scale_fill_sdv(sport = "wbb", alpha = 0.7) +
  scale_x_sdv(sport = "wbb") +
  theme_minimal() +
  theme_x_sdv() +
  labs(
    title = "Top 8 WBB Teams by Win %",
    x = NULL,
    y = "Win Percentage"
  ) +
  theme(legend.position = "none")

Next Steps