2022-08-22 · 5 min

sdvplotR: Sports Team Logo Plots in 'ggplot2', 'gt' and 'reactable'

sdvplotR plots team logos, wordmarks, player headshots and official colors across eight leagues — NFL, NBA, WNBA, MLB, NHL, college football, and men's and women's college basketball — inside ggplot2 plots, gt tables and reactable tables. Every function takes a sport argument, so the same call shape works whether you are plotting an NFL box score or an NCAA tournament bracket. It is built on ggpath and unifies the approach established by nflplotR, cfbplotR, nbaplotR and mlbplotR behind that one argument, and it is designed to sit next to the companion SportsDataverse data packages rather than fetch data itself. It is the general-purpose plotting layer of the SportsDataverse.

Installation

sdvplotR is not on CRAN yet. Install the development version from GitHub with pak:

pak::pak("sportsdataverse/sdvplotR")

Or from the SportsDataverse r-universe for a prebuilt binary:

install.packages("sdvplotR", repos = c("https://sportsdataverse.r-universe.dev", "https://cloud.r-project.org"))

It has no API key of its own. It only needs a data frame with a team identifier column; pair it with cfbfastR, hoopR, wehoop, baseballr or fastRhockey for the numbers.

Getting started

library(sdvplotR)
library(ggplot2)
 
df <- data.frame(
  a     = rep(1:8, 4),
  b     = sort(rep(1:4, 8), decreasing = TRUE),
  teams = valid_team_names("nfl")
)
 
ggplot(df, aes(x = a, y = b)) +
  geom_sdv_logos(aes(team = teams), sport = "nfl", width = 0.075) +
  theme_void()

valid_team_names(sport) returns the abbreviations sdvplotR recognizes for one of supported_sports() ("nfl", "nba", "wnba", "mlb", "nhl", "cfb", "mbb", "wbb"). geom_sdv_logos() maps a team aesthetic to that team's logo image for the given sport; team keys are cleaned automatically, so full names, alternate provider abbreviations and historical abbreviations of relocated franchises ("OAK" to "LV", "SEA" to "OKC") all resolve to the same team.

What's in the box

  • Logos, wordmarks and headshots — geom_sdv_logos(), geom_sdv_wordmarks(), geom_sdv_headshots() draw images as plot layers; every one takes sport.
  • Theme elements and scales — element_sdv_logo() (and the wordmark/headshot variants) swap axis tick text for images; scale_color_sdv() / scale_fill_sdv() map a team column to official colors; scale_x_sdv() / scale_y_sdv() turn an axis into logos.
  • gt table helpers — gt_sdv_logos(), gt_sdv_wordmarks(), gt_sdv_headshots() embed images in gt cells; gt_sdv_cols_label() builds logo column headers; gt_merge_stack_team_color() stacks two columns colored by team.
  • SportsDataverse table themes — gt_theme_sdv() (light or style = "dark") is the house gt theme; gt_theme_sdv_team() dresses a table in one team's own colors.
  • gt table themes (ported from gtUtils) — eighteen editorial and broadcast-style themes, among them gt_theme_kenpom(), gt_theme_savant(), gt_theme_athletic() and gt_theme_ncaa(), plus pal_midnight() for a matching palette.
  • gt table annotations — gt_538_caption(), gt_cutline(), gt_marginalia(), gt_watermark() and gt_social_tag() add captions, cut lines and social branding.
  • gt table coloring — gt_color_pills(), gt_percentile_bar(), gt_color_ranks(), gt_highlight_cells() and gt_legend_continuous() / gt_legend_discrete() color cells and draw matching legends.
  • gt table formatting — gt_delta(), gt_fmt_rank(), gt_fmt_tally(), gt_significance() and gt_tiers() format deltas, ranks, tallies and significance notation.
  • gt table layout and saving — gt_grid(), gt_snake() and gt_stack_tables() arrange several tables into one graphic; gt_save_crop() and gt_social_crop() save and crop a table for publication.
  • reactable table helpers — reactable_sdv_logos(), reactable_sdv_headshots() and reactable_sdv_wordmarks() render images as reactable cells; reactable_sdv_team_color_bar() and reactable_sdv_team_color_bg() color cells by team; reactable_sdv_cols_label() builds the matching headers.
  • Team utilities — supported_sports() lists the eight sport keys; valid_team_names() and team_reference() expose the reference table (ESPN ids, colors, conference/division) per team; clean_team_abbrs() and resolve_historical_abbr() clean and map provider abbreviations; sdv_team_colors() and sdv_color_palette() return raw color values; sdv_team_factor() orders a team column; sdvplotR_clear_cache() empties the image cache.
  • Premade plots and titles — sdv_team_tiers() builds a full tier-list chart; ggtitle_image() adds an image next to a ggplot2 title.
  • Re-exported from ggpath — geom_from_path(), element_path(), geom_mean_lines() and friends, the generic image-geom primitives underneath every sdvplotR function.
  • Deprecated — the former gtUtils function names are kept working under sdvplotR-deprecated, for code ported straight from that package.

A worked example

library(sdvplotR)
library(ggplot2)
library(gt)
 
df2 <- data.frame(
  team  = c("KC", "BUF", "SF", "DAL"),
  score = c(42, 38, 35, 30)
)
 
ggplot(df2, aes(x = team, y = score)) +
  geom_col(aes(fill = team), show.legend = FALSE) +
  scale_fill_sdv(sport = "nfl") +
  theme_minimal() +
  theme(axis.text.x = element_sdv_logo(sport = "nfl", size = 1))
 
data.frame(team = c("KC", "BUF", "SF"), wins = c(13, 12, 11)) |>
  gt() |>
  gt_sdv_logos(columns = "team", sport = "nfl") |>
  gt_theme_sdv()

The bar chart colors each column in the team's own color via scale_fill_sdv(sport = "nfl"), and swaps the x-axis text for logos via element_sdv_logo(). The gt table repeats three of the same teams with the team column rendered as inline logos, in the house gt_theme_sdv() look.

A reactable table follows the same team-first pattern as the gt helpers:

library(reactable)
 
df3 <- data.frame(team = c("KC", "BUF", "SF"), wins = c(13, 12, 11))
 
reactable(
  df3,
  columns = list(
    team = reactable::colDef(cell = reactable_sdv_logos(sport = "nfl"), html = TRUE),
    wins = reactable::colDef(style = reactable_sdv_team_color_bar(df3, "team", sport = "nfl"))
  )
)

reactable_sdv_logos() returns a cell renderer that swaps team abbreviations for logo images; reactable_sdv_team_color_bar() returns a style function that draws a bar in the row's team color behind the wins value, so the two columns read as one branded table rather than a plain reactable grid.

Good to know

  • Every function's sport argument is one of supported_sports(); passing anything else errors rather than silently returning nothing.
  • Team keys are cleaned before lookup, so a plot built from ESPN abbreviations, a different provider's abbreviations, or a relocated franchise's old abbreviation all resolve to the same logo and color.
  • variant = "dark" in the table helpers switches to a dark-mode logo variant, for tables rendered on a dark background.
  • The gtUtils toolkit (themes, legends, cut lines, outlier flags, gt_save_crop() / gt_social_crop()) is folded in directly rather than left as a separate dependency, credited to Andrew Weatherman as its original author.
  • The reference data covers every current franchise in the five pro leagues plus all FBS/FCS football programs and Division I basketball programs; NFL rows additionally carry nflverse wordmarks.

sdvplotR generalizes cfbplotR, the college-football-only plotting package that came first, across every SportsDataverse league behind one sport argument. It is designed to work with cfbfastR, hoopR, wehoop, baseballr and fastRhockey for the underlying data, and with the sportsdataverse (R) meta-package for installing the whole family at once.

Data and automation

  • Package checks: R CMD check pkgdown site test coverage headshot map refresh
  • Cheat sheets for the rest of the family are at sportsdataverse.org/cheatsheets; this package does not have one.
  • Ecosystem status — a nightly snapshot of every SportsDataverse repo: workflow conclusions, release-asset freshness, open PRs and issues.
@misc{gilani_carl_lee_kay_weatherman_sdvplotR,
  author = {Gilani, Saiem and Carl, Sebastian and Lee, Jared and Kay, Camden and Weatherman, Andrew},
  title = {sdvplotR: The SportsDataverse's R Package for Multi-League Sports Plotting.},
  url = {https://sdvplotR.sportsdataverse.org},
  year = {2026}
}

My role: author and maintainer. Part of the SportsDataverse — open sports data tooling for R, Python and JavaScript.