First CRAN release. Earlier development builds were published only on r-universe, every one of them numbered 0.1.0 (no 0.1.0 or 0.2.0 was released to CRAN or tagged), so this section describes the whole package.
The cfbplotR features sdvplotR lacked; every other cfbplotR export already had
a counterpart with league = "cfb":
scale_color_sdv(), scale_colour_sdv() and scale_fill_sdv() take
alt_colors, teams drawn in their other colour (cfbplotR's alt_colors).sdv_teams() takes division: "P4", "P5" and "G5" from each college
football team's conference in the index, "FBS", "FCS", "DI", "DII"
and "DIII" from the index's new division column, and "Conference"
(cfbplotR's division filter). sdv_teams() has a division column; the
bundled snapshot carries it, so the division filters work offline, and it
is NA only in an older cached index.sdv_clean_names() cleans names, abbreviations and ids to one display name
per team, keeping values that do not resolve unless keep_non_matches = FALSE (cfbplotR's clean_school_names() and its alias).sdv_aliases() returns the index's alias table (cfbplotR's
team_name_mapping); sdv_teams() with sdv_logo_url() stands in for
logo_ref (its examples show how).sdv_add_athlete_id() adds ESPN athlete ids to a data frame of college
football player names, matched on name, team and season to cfbfastR-data's
rosters (cfbplotR's add_athlete_id_col()). A name that matches more than
one athlete is left NA; offline it warns and returns NA ids."cfbplotr-legacy",
rank after every other source when a team has more than one wordmark. The
bundled team index (e04c50e5682e) maps 360 of those 362 college
wordmarks, so geom_sdv_wordmarks(league = "cfb"), gt_sdv_wordmarks() and
element_sdv_wordmark() draw most FBS and FCS teams, and it carries the
division column sdv_teams(division = "FBS") reads.sdv_ggpreview() previews a plot at the size it will be saved
(nflplotR's and cfbplotR's ggpreview(); 'rstudioapi' in RStudio, now in
Suggests).{league}_team_aliases tables (NFL,
college football, NBA, WNBA, men's and women's college basketball, MLB,
NHL). Yahoo ids resolve under "auto" (sdv_resolve("ncaaf.t.1", "cfb"));
Fox, CBS, 247Sports and On3 numbers are other teams' ESPN ids, so they
resolve only with an explicit id_system: sdv_resolve("25", "cfb") is
ESPN's California and sdv_resolve("25", "cfb", id_system = "fox") is Ohio
State. KenPom and Torvik team names come before "name" under "auto".sdv_headshot_url(), geom_sdv_headshots(),
gt_sdv_headshots() and the rest) take other providers' player ids:
id_system = "fox", "yahoo", "cbs", "kenpom", "ncaa",
"nba_stats" or "wnba_stats" (by league, as sdv_headshot_url() lists)
draw the ESPN headshot of the athlete sdv-reference-data's
{league}_player_aliases matches the id to. Each league and provider's map
is downloaded when first needed and kept for the session.id_system = "ncaa" for men's and women's college basketball and college
baseball, org ids for college softball (sdv_resolve(193, "mbb", id_system = "ncaa") is Duke), and WNBA Stats team ids and tricodes as "nba_api"
(sdv_resolve(1611661319, "wnba", id_system = "nba_api") is the Aces).
Under "auto" an ESPN id wins over an equal NCAA id, so pass
id_system = "ncaa" for NCAA ids.Penalty - Scored /
Penalty - Missed), and its StatsBomb map notes why a 4-2 final shows five
goals: the own goal is its own event type (sdvplot#101).theme_title_image() and the image axis scales (scale_x_sdv() and the
rest) read each image before 'gridtext' draws it. An image that cannot be
read (an unreachable host, offline) is left out with a warning, and an axis
label falls back to its text, where 'gridtext' used to stop the plot with
an error. A failed read is not tried again in the session until
sdv_clear_cache(). SVG paths are passed through unchanged: 'gridtext'
never reads one, and draws it blank.tools::R_user_dir("sdvplotR", "cache")).sdv_surface() needs 'sportyR' 2.4.5 or later, which is on CRAN
(install.packages("sportyR")); Suggests declares the floor and
sdv_surface() checks it with rlang::check_installed(). It reads a
field's parameters through sportyR::get_surface_dimensions() and no
longer reads anything internal to 'sportyR'.color_updates = list(field_border_outline = ...));
a team's end zones are painted inside it. The lacrosse markings (neutral
zones, penalty boxes, goal fans, goal mouths, face-off markers) and the
nhl92 hockey goal crease are drawn correctly.gt_theme_sdv() previews drop their logo column, and ?gt_theme_tier
previews the theme on a standings table instead of a tier list of logos.sdv_resolve("HB Koge", "soccer") finds HB Køge (#70).Team logos, wordmarks, player headshots and team colours for
ggplot2, gt and reactable, and for interactive plotly, ggiraph and leaflet
charts, across the 49 leagues of the SportsDataverse team index
(sdv_leagues()), built on 'ggpath'. It shares its team index, logo
archive and argument names with the Python package sdvplot and the
JavaScript packages @sportsdataverse/sdvplot and @sportsdataverse/sdvtables.
sdv_resolve() turns team identifiers from any of 18 id systems (ESPN,
nflverse, MLB Stats, nba_api, NHL, HockeyTech, CFBD, NCAA, PFF, Sports
Reference, FanGraphs, names, ...) into canonical team ids, using season
for codes reused across eras; sdv_suggest() proposes candidates for a
value that does not resolve. The helpers that take a team take league and
id_system. Those that draw team marks or colours also take season
(the geom_sdv_* layers read it as an aesthetic or a constant).
strict (raise instead of warn when a value does not resolve) is taken by
sdv_resolve(), sdv_logo_url(), sdv_team_colors(),
sdv_color_palette(), sdv_team_tiers() and the logo, wordmark, label and
colour-bar helpers (geom_sdv_logos(), geom_sdv_wordmarks(),
add_sdv_logos(), add_sdv_wordmarks(), addSdvLogoMarkers(),
sdv_axis_logos() and the gt_sdv_* and reactable_sdv_* helpers that draw
them), but not by sdv_marks(), element_sdv_logo(),
element_sdv_wordmark(), scale_x_sdv(), scale_y_sdv(), sdv_colorway()
or sdv_team_factor(). Headshot helpers take no season;
ggtitle_image(), scale_colour_sdv(), scale_color_sdv() and
scale_fill_sdv() take neither season nor id_system; sdv_surface()
takes league and season but no id_system.sdv_teams(), sdv_leagues(), sdv_team_colors(), sdv_color_palette()
and sdv_team_factor() list and colour teams.sdv_versions(), sdv_clear_cache()); a copy is
bundled for offline use (options(sdvplotR.offline = TRUE)).sdv_logo_url() and sdv_marks() choose a team's archived mark by
variant ("default", "dark", or a named variant) and season.sdv_headshot_url() and the headshot helpers read ESPN athlete ids in
every league by default; id_system = "gsis" reads nflverse NFL ids and
id_system = "league" the league's own player ids."nbagl", ESPN files its photos
with the NBA's) and soccer by ESPN athlete id, and the 20 HockeyTech
leagues by HockeyTech player id with id_system = "league"
(assets.leaguestat.com): the PWHL, AHL, ECHL, OHL, WHL, QMJHL and USHL,
and the junior and minor leagues "sphl", "chl", "bchl", "ajhl",
"sjhl", "ojhl", "cchl", "gojhl", "mhl", "nojhl", "vijhl",
"kijhl" and "mjhl" (each league's key is its leaguestat client code).
F1 driver headshots are not covered: formula1.com keys them by its own
driver reference (MAXVER01), not a driver number or Jolpica driver_id.sdv_bins() bins x/y points into hexagons (shape = "hex", the default) or
squares (shape = "square"), sized in data units by radius (a hexagon's
circumradius), side (a square's) or, with equal_area = TRUE, squares of
a radius-radius hexagon's area. It returns one row per cell (cell_id,
centre, count and the rows it holds, in first-seen order);
sdv_bin_ids() gives each point's cell id. The lattice, argument names and
ids are sdvplot-js's binner() and sdvplot's: on 2000 real NBA shots every
cell id matches sdvplot-js byte for byte under six lattices, d3-hexbin's
nearest-centre quirk included.geom_sdv_bins() draws those cells as true hexagons or squares in data
space, filled by after_stat(count) (also density and cell_id), on any
plot or an sdv_surface() court.geom_sdv_bins_interactive() is its ggiraph twin: each cell's data_id is
its cell id, so points given sdv_bin_ids() link to their cell for hover
and selection in one girafe(). Ids are strings, "x,y", as in
sdvplot-js's linked interactivity. plotly::ggplotly() draws the cells too.origin = c(x, y), the point a cell is centred on (a
hoop-centred lattice: origin = the basket's coordinates; ids stay the
absolute centres), and weights: sdv_bins(weights = ) and a weight
aesthetic on the geoms add each cell's weight (the sum of its points'
weights, its count without them; after_stat(weight), and density is a
share of it). geom_sdv_bins() and geom_sdv_bins_interactive() draw
each cell at cell_fill of the lattice cell (by default 0.88 for squares,
so they no longer touch, and 1 for hexagons; sdvplot's fill) and leave
out cells under min_count points (min_count = 2 draws no single
attempts). In ggplotly() each cell is its own trace, with its tooltip on
the fill; with the data as a plotly::highlight_key() on sdv_bin_ids(),
plotly::highlight() links cells and points without Shiny.add_sdv_logos(), add_sdv_wordmarks(), add_sdv_headshots(),
sdv_axis_logos() and sdv_colorway().geom_sdv_logos_interactive(), geom_sdv_wordmarks_interactive()
and geom_sdv_headshots_interactive(), which embed images at most max_px
(160) pixels a side, so 32 logos add about half a megabyte to the page.addSdvLogoMarkers().geom_sdv_logos(), geom_sdv_wordmarks() and geom_sdv_headshots()
draw images at x / y positions; geom_sdv_logos() takes a season
aesthetic, so a team is drawn with the mark it wore that season.element_sdv_logo(), element_sdv_wordmark() and
element_sdv_headshot() replace axis text with images; scale_x_sdv(),
scale_y_sdv() and the headshot variants do the same through
ggtext::element_markdown() with theme_x_sdv() / theme_y_sdv(). Both
draw a copy of each image at most four times its drawn size (sharp in a
300 dpi export, and a few KB a logo in an SVG or ggiraph widget). All of
them work after a complete theme such as theme_minimal() on 'ggplot2' 4,
which sdvplotR requires.gt_theme_source() and reactable_sdv_theme() apply any of 122 surveyed
table styles, named for their source ("datagolf", "wikipedia", "nejm",
...); sdv_table_themes() lists them and table_theme_spec() resolves one.
The registry is shared with sdvplot and sdvtables. Twenty shortcuts such as
gt_theme_datagolf() and gt_theme_wikipedia() name the most useful.scale_color_sdv() and scale_fill_sdv() map teams to their primary or
secondary colours.sdv_teams(include_conferences = TRUE) lists them and the
image helpers draw them from their short keys ("SEC", "Big Ten",
"Pac-12") or their other names ("Southeastern Conference", "B1G").
A team's code wins over a conference's: cfb's "MAC" is Macalester."MLB", "AL", "NL",
"NBA", "East", "West", "WNBA", "NHL", the NHL's divisions
("Atlantic", "Metropolitan", "Central", "Pacific"), "AAF" and "NCAA"
in each college league (team index 387c6729bd3f). An NHL division's mark is
archived at level "division", which the mark lookup now reads as non-team."f1", by Jolpica constructor id), national teams pooled as
"fiba" and "iihf", and 13 junior and minor hockey leagues (SPHL, CHL, BCHL,
AJHL, SJHL, OJHL, CCHL, GOJHL, MHL, NOJHL, VIJHL, KIJHL, MJHL). sdv_surface()
takes a team on "cfl", "fiba" and "iihf"."Eastern" and "Western" conferences draw their Conference Final
wordmarks as their logos (a conference or league row with no logo takes its
wordmark; a team never does). Division II and III football conferences have
logos too.conference; a soccer club's conference is its domestic league ("eng.1").conference value draws
its conference's logo ("Hockey East Association"), not only the short key
(team index b2f30ebdd911).sdv_team_tiers() builds tier charts, with dark marks on its dark theme
(variant = "auto") and a theme = "light" option; ggtitle_image() with
theme_title_image() places a logo next to a plot title.sdv_surface() draws a court, field, rink, pitch or sheet through 'sportyR'
for 59 surface keys (the table sdvplot-js uses; sdvplot, the Python
package, is moving to it), as a
ggplot to plot data on: every sport 'sportyR' draws (basketball, football,
baseball, softball, hockey, soccer, lacrosse, tennis, volleyball, curling)
and its leagues, from the NFL to NFHS, Little League, the ATP and the WCF.
Leagues without a surface of their own use their sport's (the WHL, for one,
uses the NHL rink); the PWHL draws its own rink. Given a team, a few features
take its colours, and center_logo = TRUE puts its logo at the center; on a
baseball or softball field, whose origin is home plate, it goes in shallow
center field instead, midway between second base and the center-field fence
and 0.15 x the center-field distance across (it used to warn and draw no
logo). These
are stylized surfaces built from team colours, not the teams' real floor,
field or rink designs. Keys that are not team leagues ("fifa", "atp",
"nll", "epl", ...) take no team. "ncaa_softball" is both a team
league and a surface.sdv_court_coords() converts stats.nba.com / stats.wnba.com legacy shot
locations (x_legacy/y_legacy, or LOC_X/LOC_Y from the
Shot_Chart_Detail element of hoopR::nba_shotchartdetail()) into the
sportyR::geom_basketball("nba") court frame; the converted points also
fit sportyR's "wnba" and "ncaa" courts.
sdv_court_coords(provider = "euroleague") converts the Euroleague shot
frame of hoopR's euroleague_game_points() (coord_x/coord_y: integer
centimeters, hoop at the origin, both teams on one basket, free throws as
-1,-1) onto the FIBA court sdv_surface("fiba") draws, in meters, with
the -1,-1 free throws as NA.sdv_pitch_coords() converts soccer event coordinates from Opta /
Stats Perform, Wyscout, StatsBomb, UEFA, Impect, ESPN and the tracking
providers (Tracab, SkillCorner, Second Spectrum, Metrica) to one
regulation 105 x 68 m frame, piecewise-linearly between pitch landmarks.gt_sdv_logos(), gt_sdv_wordmarks(), gt_sdv_headshots(),
gt_sdv_cols_label() and gt_merge_stack_team_color() render images and
team-coloured text inside 'gt' tables. gt_sdv_logos(include_name = TRUE)
keeps the cell's text after the logo. gt_merge_stack_team_color() keeps
its text readable: a primary colour under 4.5:1 contrast against the cell
background gives way to the secondary colour, or is darkened until it
passes.reactable_sdv_logos(), reactable_sdv_wordmarks(),
reactable_sdv_headshots(), reactable_sdv_cols_label(),
reactable_sdv_team_color_bar() and reactable_sdv_team_color_bg() do the
same for 'reactable' tables; a logo or wordmark swaps to the default image in
the browser if a variant fails to load.gt_theme_sdv() is the SportsDataverse house table theme, in light and
style = "dark", and gt_theme_sdv_team() dresses a table in one team's
colours from sdv_team_colors(), picking title text and line colours by
contrast.gt_theme_*() table themes plus gt_theme_preview(), continuous and
discrete colour legends, gt_cutline(), gt_significance(),
gt_outliers(), colour pills / ranks / results, percentile bars, border
bars, gt_grid(), gt_snake() and gt_stack_tables() layouts,
gt_save_crop(), gt_save_batch() and gt_social_crop(), and the
theme_bg background lookup. The eight gtUtils articles are on the
website under "Tables cookbook".gt_theme_*() keeps its own row colours on a Bootstrap page (pkgdown,
Quarto) in either colour mode. gt_color_pills(), gt_percentile_bar(),
gt_fmt_tally(), gt_significance() and gt_merge_stack_team_color()
decorate each cell from its own row when row groups reorder the table.
gt_grid() and gt_stack_tables() scroll inside their own box when they
are wider than the screen.gt_spotlight() dims the other rows to a readable tone: with
dim_color = "auto" it blends the table's text toward its background until
it sits just above 4.5:1 contrast. gt_tiers() gives each image its own
alt text, and takes an alt argument for your own text.gt_save_crop(), gt_social_crop(),
gt_save_batch(), gt_grid(), gt_stack_tables()) gives headless Chrome
60 seconds to start; a longer options(chromote.timeout = ) of your own is
kept. gt_save_batch() needs an explicit dir.gt_theme_*()
themes, gt_cutline(), gt_watermark(), gt_538_caption(),
gt_border_grid(), gt_border_bars_*()) after a call that reorders gt's
options, such as gt::opt_row_striping(), keeps its id and its options. The
id used to be written over the first option instead, so the table lost the
id its CSS is scoped to and, after opt_row_striping(), failed to render.gt_grid() and gt_stack_tables() given a single table rather than a list
of them, or a list with more than one item that is not a table, and
gt_cutline() given a non-numeric after, now raise their own error
messages. They used to fail inside cli's pluralization instead.\donttest{}
blocks that run in an interactive session with webshot2 and Chrome
available. The reference examples use real SportsDataverse data:
sdv_example_standings holds the final 2025 NFL and 2025-26 NBA
regular-season standings, built by data-raw/sdv_examples.R from the
nflreadr / nflseedR and hoopR release loaders.Development version number of the builds published on r-universe before the first CRAN release; never released to CRAN or tagged. Its changes are described under 0.3.0.