| Title: | Sports Team Logo Plots in 'ggplot2', 'gt' and 'reactable' |
|---|---|
| Description: | A unified set of functions to visualize sports data across the 28 leagues of the SportsDataverse team index, including the National Football League, National Basketball Association, Women's National Basketball Association, Major League Baseball, National Hockey League, college football and basketball, and soccer, in 'ggplot2' plots, 'gt' tables and 'reactable' tables, and in interactive 'plotly', 'ggiraph' and 'leaflet' charts and maps. Team logos, wordmarks and player headshots can be drawn as plot layers, as axis text and inside table cells, in the design a team used in a given season, and team color scales map team identifiers to their official colors. Playing surfaces from 'sportyR' can be painted in a team's colors. Team identifiers from many data providers, including the codes of relocated franchises, are resolved to one canonical team id per league through the team index and logo manifest of the SportsDataverse logo archive <https://github.com/sportsdataverse/sdv-assets>, read at run time with a copy bundled in the package. Built on 'ggpath' following the conventions of 'nflplotR' and designed to work with the companion SportsDataverse data packages. Also includes the 'gtUtils' table themes, color legends, cut lines, significance notation, outlier flags and cropping and saving helpers for 'gt' tables. |
| Authors: | Saiem Gilani [aut, cre, cph] (ORCID: <https://orcid.org/0000-0002-7194-9067>), Sebastian Carl [aut], Jared Lee [aut], Camden Kay [aut], Andrew Weatherman [aut] |
| Maintainer: | Saiem Gilani <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-10-12 23:14:24 UTC |
| Source: | https://github.com/sportsdataverse/sdvplotR |
Places team marks on a plotly::plot_ly() chart at data
coordinates, as layout images. The R counterpart of sdvplot's plotly
adapter. Works on native plotly charts; plotly::ggplotly() drops layout
images, so draw a ggplot with geom_sdv_logos() or
geom_sdv_logos_interactive() instead.
add_sdv_logos( p, x, y, team, league, size = 0.08, season = NULL, variant = "default", id_system = "auto", strict = FALSE, xref = "x", yref = "y" ) add_sdv_wordmarks( p, x, y, team, league, size = 0.08, season = NULL, variant = "default", id_system = "auto", strict = FALSE, xref = "x", yref = "y" ) add_sdv_headshots( p, x, y, player_id, league, size = 0.08, id_system = "espn", xref = "x", yref = "y" )add_sdv_logos( p, x, y, team, league, size = 0.08, season = NULL, variant = "default", id_system = "auto", strict = FALSE, xref = "x", yref = "y" ) add_sdv_wordmarks( p, x, y, team, league, size = 0.08, season = NULL, variant = "default", id_system = "auto", strict = FALSE, xref = "x", yref = "y" ) add_sdv_headshots( p, x, y, player_id, league, size = 0.08, id_system = "espn", xref = "x", yref = "y" )
p |
A plotly object. |
x, y
|
Positions: numbers, or category names on a categorical axis. |
team |
Team identifiers, one per position. |
league |
A league key from |
size |
Each image is fitted by height to |
season |
|
variant |
|
id_system |
For headshots, as in |
strict |
If |
xref, yref
|
The axes the positions refer to ( |
player_id |
Player ids, one per position. |
Images are placed in data units and fitted by height: each is sized to
size times the y-axis span, as sdvplot's plotly adapter sizes them. The span
is the axis range when one is set, and otherwise everything the chart's traces
on that axis cover plus the new marks (the number of categories on a
categorical axis), so marks for a subset of the plotted points are sized
against the whole axis. Images already
on the chart, including ones set with plotly::layout(), are kept. Date axes
are not supported yet.
The plotly object (an htmlwidget) with the images added.
if (requireNamespace("plotly", quietly = TRUE)) { d <- data.frame( team = c("KC", "BUF", "BAL"), off = c(0.12, 0.15, 0.18), def = c(-0.05, 0.02, -0.08) ) plotly::plot_ly(d, x = ~off, y = ~def, type = "scatter", mode = "markers", text = ~team) |> add_sdv_logos(d$off, d$def, d$team, "nfl") }if (requireNamespace("plotly", quietly = TRUE)) { d <- data.frame( team = c("KC", "BUF", "BAL"), off = c(0.12, 0.15, 0.18), def = c(-0.05, 0.02, -0.08) ) plotly::plot_ly(d, x = ~off, y = ~def, type = "scatter", mode = "markers", text = ~team) |> add_sdv_logos(d$off, d$def, d$team, "nfl") }
Adds a marker per row with the team's logo as its icon. A row whose team has no logo keeps leaflet's default marker, so no point is dropped silently.
addSdvLogoMarkers( map, lng, lat, team, league, size = 32, season = NULL, variant = "default", id_system = "auto", strict = FALSE, data = leaflet::getMapData(map), ... )addSdvLogoMarkers( map, lng, lat, team, league, size = 32, season = NULL, variant = "default", id_system = "auto", strict = FALSE, data = leaflet::getMapData(map), ... )
map |
A leaflet map. |
lng, lat
|
Longitudes and latitudes: vectors, or formulas read from |
team |
Team identifiers: a vector, or a formula read from |
league |
A league key from |
size |
Icon width and height, in pixels. |
season |
|
variant |
|
id_system |
|
strict |
If |
data |
The data formulas read; defaults to the map's. |
... |
Passed to |
The leaflet map (an htmlwidget) with the markers added.
if (requireNamespace("leaflet", quietly = TRUE)) { d <- data.frame(team = c("KC", "BUF"), lon = c(-94.48, -78.79), lat = c(39.05, 42.77)) leaflet::leaflet(d) |> leaflet::addTiles() |> addSdvLogoMarkers(~lon, ~lat, ~team, league = "nfl", label = ~team) }if (requireNamespace("leaflet", quietly = TRUE)) { d <- data.frame(team = c("KC", "BUF"), lon = c(-94.48, -78.79), lat = c(39.05, 42.77)) leaflet::leaflet(d) |> leaflet::addTiles() |> addSdvLogoMarkers(~lon, ~lat, ~team, league = "nfl", label = ~team) }
In conjunction with the ggplot2::theme system, the following element_
functions enable images in non-data components of the plot, e.g. axis text.
element_sdv_logo(): draws team logos instead of their abbreviations.
element_sdv_wordmark(): draws team wordmarks instead of their abbreviations.
element_sdv_headshot(): draws player headshots instead of their IDs.
element_sdv_raster(): draws a single image in a rectangular theme
element such as plot.background. A thin wrapper around
ggpath::element_raster().
element_sdv_logo( league, alpha = NULL, colour = NA, color = NULL, hjust = NULL, vjust = NULL, size = 0.5, season = NULL, id_system = "auto" ) element_sdv_wordmark( league, alpha = NULL, colour = NA, color = NULL, hjust = NULL, vjust = NULL, size = 0.5, season = NULL, id_system = "auto" ) element_sdv_headshot( league, alpha = NULL, colour = NA, color = NULL, hjust = NULL, vjust = NULL, size = 0.5, id_system = "espn" ) element_sdv_raster( image_path, x = grid::unit(0.5, "npc"), y = grid::unit(0.5, "npc"), width = grid::unit(1, "npc"), height = grid::unit(1, "npc"), just = "centre", hjust = 0.5, vjust = 0.5, interpolate = TRUE, ... )element_sdv_logo( league, alpha = NULL, colour = NA, color = NULL, hjust = NULL, vjust = NULL, size = 0.5, season = NULL, id_system = "auto" ) element_sdv_wordmark( league, alpha = NULL, colour = NA, color = NULL, hjust = NULL, vjust = NULL, size = 0.5, season = NULL, id_system = "auto" ) element_sdv_headshot( league, alpha = NULL, colour = NA, color = NULL, hjust = NULL, vjust = NULL, size = 0.5, id_system = "espn" ) element_sdv_raster( image_path, x = grid::unit(0.5, "npc"), y = grid::unit(0.5, "npc"), width = grid::unit(1, "npc"), height = grid::unit(1, "npc"), just = "centre", hjust = 0.5, vjust = 0.5, interpolate = TRUE, ... )
league |
A league key from |
alpha |
The alpha channel (transparency) between 0 and 1. |
colour, color
|
The image will be colorized with this color. Use |
hjust |
Horizontal justification. |
vjust |
Vertical justification. |
size |
The output grob size in |
season |
|
id_system |
|
image_path |
A file path or url to an image. |
x, y, width, height, just, interpolate
|
Passed on to
|
... |
Other arguments passed on to |
The elements translate team abbreviations or player IDs into
logo images or player headshots for the specified league. Rendering is
delegated to ggpath::element_path(), which they extend. Set on a parent
element such as axis.text.x, they also replace the position children
(axis.text.x.bottom, axis.text.y.left, ...) that complete themes like
ggplot2::theme_minimal() set, keeping the child's spacing.
element_sdv_logo(), element_sdv_wordmark() and
element_sdv_headshot() return a theme element extending
ggpath::element_path(); element_sdv_raster() returns a
ggpath::element_raster().
ggpath::element_path(), ggpath::element_raster()
library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:16] df <- data.frame( random_value = runif(length(team_abbr), 0, 1), teams = team_abbr ) # use logos for x-axis ggplot(df, aes(x = teams, y = random_value)) + geom_col(aes(color = teams, fill = teams), width = 0.5) + scale_color_sdv(league = "nfl", which = "secondary") + scale_fill_sdv(league = "nfl", alpha = 0.4) + theme_minimal() + theme(axis.text.x = element_sdv_logo(league = "nfl"))library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:16] df <- data.frame( random_value = runif(length(team_abbr), 0, 1), teams = team_abbr ) # use logos for x-axis ggplot(df, aes(x = teams, y = random_value)) + geom_col(aes(color = teams, fill = teams), width = 0.5) + scale_color_sdv(league = "nfl", which = "secondary") + scale_fill_sdv(league = "nfl", alpha = 0.4) + theme_minimal() + theme(axis.text.x = element_sdv_logo(league = "nfl"))
This geom is used to plot player headshots instead
of points in a ggplot. It requires x, y aesthetics as well as a valid
player identifier: an ESPN athlete ID by default, in every league. Set
id_system to plot IDs from another source (nflverse's gsis IDs, or the
league's own player IDs). A team's ESPN athlete IDs come
with its roster: hoopR::espn_mbb_team_roster() and
espn_nba_team_roster(), wehoop::espn_wbb_team_roster() and
espn_wnba_team_roster(), and cfbfastR::espn_cfb_team_roster() each
return an athlete_id column.
geom_sdv_headshots( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., league, id_system = "espn", na.rm = FALSE, show.legend = FALSE, inherit.aes = TRUE ) GeomSDVheadshotgeom_sdv_headshots( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., league, id_system = "espn", na.rm = FALSE, show.legend = FALSE, inherit.aes = TRUE ) GeomSDVheadshot
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
stat |
The statistical transformation to use on the data for this layer.
When using a
|
position |
A position adjustment to use on the data for this layer. This
can be used in various ways, including to prevent overplotting and
improving the display. The
|
... |
Other arguments passed on to
|
league |
A league key from |
id_system |
|
na.rm |
If |
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
ESPN and league IDs are plain digits, so a mismatch draws the wrong player or no image rather than an error. League CDNs draw a silhouette for an unknown ID, and the NBA and WNBA CDNs refuse requests from datacenter IPs, so a plot drawn on CI or a server can come back without those headshots.
A ggplot2 layer.
geom_sdv_headshots() understands the following aesthetics (required aesthetics are in bold):
- The x-coordinate.
- The y-coordinate.
- The player's ID: ESPN athlete ID, or as id_system says.
alpha = NULL- The alpha channel.
colour = NULL - The image will be colorized with this colour. Use "b/w" for black and white.
angle = 0- The angle of the image.
hjust = 0.5- The horizontal adjustment.
vjust = 0.5- The vertical adjustment.
width = 1.0 - The desired width in npc.
height = 1.0 - The desired height in npc.
library(sdvplotR) library(ggplot2) df <- data.frame( a = 1:3, b = 3:1, player_id = c("3139477", "12483", "3917315"), player_name = c("P.Mahomes", "M.Stafford", "K.Murray") ) ggplot(df, aes(x = a, y = b)) + geom_sdv_headshots(aes(player_id = player_id), league = "nfl", height = 0.2) + geom_label(aes(label = player_name), nudge_y = -0.35, alpha = 0.5) + coord_cartesian(xlim = c(0.5, 3.5), ylim = c(0.5, 3.5)) + theme_void()library(sdvplotR) library(ggplot2) df <- data.frame( a = 1:3, b = 3:1, player_id = c("3139477", "12483", "3917315"), player_name = c("P.Mahomes", "M.Stafford", "K.Murray") ) ggplot(df, aes(x = a, y = b)) + geom_sdv_headshots(aes(player_id = player_id), league = "nfl", height = 0.2) + geom_label(aes(label = player_name), nudge_y = -0.35, alpha = 0.5) + coord_cartesian(xlim = c(0.5, 3.5), ylim = c(0.5, 3.5)) + theme_void()
This geom is used to plot sports team logos instead
of points in a ggplot. It requires x, y aesthetics as well as a valid
team identifier: anything sdv_resolve() accepts, or a conference or
league key. A league's teams are listed by sdv_teams().
geom_sdv_logos( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., league, id_system = "auto", strict = FALSE, na.rm = FALSE, show.legend = FALSE, inherit.aes = TRUE ) GeomSDVlogogeom_sdv_logos( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., league, id_system = "auto", strict = FALSE, na.rm = FALSE, show.legend = FALSE, inherit.aes = TRUE ) GeomSDVlogo
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
stat |
The statistical transformation to use on the data for this layer.
When using a
|
position |
A position adjustment to use on the data for this layer. This
can be used in various ways, including to prevent overplotting and
improving the display. The
|
... |
Other arguments passed on to
|
league |
A league key from |
id_system |
|
strict |
If |
na.rm |
If |
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
A ggplot2 layer (ggplot2::layer()) that can be added to a plot
created with ggplot2::ggplot().
geom_sdv_logos() understands the following aesthetics (required aesthetics are in bold):
- The x-coordinate.
- The y-coordinate.
- The team: an abbreviation, name or id, resolved by sdv_resolve().
alpha = NULL- The alpha channel, i.e. transparency level, as a numerical value between 0 and 1.
colour = NULL - The image will be colorized with this colour. Use the special
character "b/w" to set it to black and white.
angle = 0- The angle of the image as a numerical value between 0 and 360 degrees.
hjust = 0.5- The horizontal adjustment relative to the given x coordinate.
vjust = 0.5- The vertical adjustment relative to the given y coordinate.
width = 1.0 - The desired width of the image in npc (Normalised Parent
Coordinates). A typical size is width = 0.075.
height = 1.0 - The desired height of the image in npc. A typical size is height = 0.1.
season = NA - The season whose logo to draw: the ending year for
the NHL (1990 for 1989-90), the year elsewhere. NA draws the
team's logo today. See the Historical logos section.
Given a season, a team is drawn with the mark it wore that season where
the SportsDataverse logo archive dates its marks, and with its current
mark otherwise. The season also picks the team a reused code meant then
(see sdv_resolve()). The images are copies kept in the archive, so they
don't change when a league reuses a file name. SVG marks are read with the
'rsvg' package. season takes single years: the ending year for split
seasons (2005 for 2004-05).
library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:8] df <- data.frame( a = rep(1:4, 2), b = rep(2:1, each = 4), teams = team_abbr ) ggplot(df, aes(x = a, y = b)) + geom_sdv_logos(aes(team = teams), league = "nfl", width = 0.075) + geom_label(aes(label = teams), nudge_y = -0.35, alpha = 0.5) + theme_void() # the logo each team wore that season (NHL seasons are ending years; # the NHL's marks are SVG files, read with the 'rsvg' package) if (requireNamespace("rsvg", quietly = TRUE)) { old <- data.frame( x = 1:4, y = 1, team = c("QUE", "HFD", "ATL", "WPG"), season = c(1990, 1995, 2005, 2015) ) ggplot(old, aes(x = x, y = y)) + geom_sdv_logos(aes(team = team, season = season), league = "nhl", width = 0.2) + theme_void() }library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:8] df <- data.frame( a = rep(1:4, 2), b = rep(2:1, each = 4), teams = team_abbr ) ggplot(df, aes(x = a, y = b)) + geom_sdv_logos(aes(team = teams), league = "nfl", width = 0.075) + geom_label(aes(label = teams), nudge_y = -0.35, alpha = 0.5) + theme_void() # the logo each team wore that season (NHL seasons are ending years; # the NHL's marks are SVG files, read with the 'rsvg' package) if (requireNamespace("rsvg", quietly = TRUE)) { old <- data.frame( x = 1:4, y = 1, team = c("QUE", "HFD", "ATL", "WPG"), season = c(1990, 1995, 2005, 2015) ) ggplot(old, aes(x = x, y = y)) + geom_sdv_logos(aes(team = team, season = season), league = "nhl", width = 0.2) + theme_void() }
geom_sdv_logos() and its siblings with ggiraph's
interactivity: map tooltip, data_id or onclick, then render with
ggiraph::girafe(). Each returns two layers: the images, and an
invisible interactive point over each that takes the hover.
geom_sdv_logos_interactive( mapping = NULL, data = NULL, ..., league, hover_size = 8, max_px = 160, id_system = "auto", strict = FALSE, inherit.aes = TRUE ) geom_sdv_wordmarks_interactive( mapping = NULL, data = NULL, ..., league, hover_size = 8, max_px = 160, id_system = "auto", strict = FALSE, inherit.aes = TRUE ) geom_sdv_headshots_interactive( mapping = NULL, data = NULL, ..., league, hover_size = 8, max_px = 160, id_system = "espn", inherit.aes = TRUE )geom_sdv_logos_interactive( mapping = NULL, data = NULL, ..., league, hover_size = 8, max_px = 160, id_system = "auto", strict = FALSE, inherit.aes = TRUE ) geom_sdv_wordmarks_interactive( mapping = NULL, data = NULL, ..., league, hover_size = 8, max_px = 160, id_system = "auto", strict = FALSE, inherit.aes = TRUE ) geom_sdv_headshots_interactive( mapping = NULL, data = NULL, ..., league, hover_size = 8, max_px = 160, id_system = "espn", inherit.aes = TRUE )
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
... |
Passed to the image layer ( |
league |
A league key from |
hover_size |
The size of the invisible hover target, in ggplot2 point size. |
max_px |
The longest side, in pixels, of each image embedded in the
page. ggiraph writes every image into the widget, and a source logo
(500 px) or headshot is 20-300 KB, so 30 of them make a page of megabytes;
160 px stays sharp at the size these geoms draw. |
id_system |
For headshots, as in |
strict |
If |
inherit.aes |
If |
A list of two ggplot2 layers, to add with +.
if (requireNamespace("ggiraph", quietly = TRUE)) { library(ggplot2) d <- data.frame(x = 1:3, y = c(2, 3, 1), team = c("KC", "BUF", "BAL")) p <- ggplot(d, aes(x, y)) + geom_sdv_logos_interactive( aes(team = team, tooltip = team, data_id = team), league = "nfl", width = 0.1 ) ggiraph::girafe(ggobj = p) }if (requireNamespace("ggiraph", quietly = TRUE)) { library(ggplot2) d <- data.frame(x = 1:3, y = c(2, 3, 1), team = c("KC", "BUF", "BAL")) p <- ggplot(d, aes(x, y)) + geom_sdv_logos_interactive( aes(team = team, tooltip = team, data_id = team), league = "nfl", width = 0.1 ) ggiraph::girafe(ggobj = p) }
This geom is used to plot sports team wordmarks instead
of points in a ggplot. It requires x, y aesthetics as well as a valid
team identifier: anything sdv_resolve() accepts. A league's teams are
listed by sdv_teams().
geom_sdv_wordmarks( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., league, id_system = "auto", strict = FALSE, na.rm = FALSE, show.legend = FALSE, inherit.aes = TRUE ) GeomSDVwordmarkgeom_sdv_wordmarks( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., league, id_system = "auto", strict = FALSE, na.rm = FALSE, show.legend = FALSE, inherit.aes = TRUE ) GeomSDVwordmark
mapping |
Set of aesthetic mappings created by |
data |
The data to be displayed in this layer. There are three options: If A A |
stat |
The statistical transformation to use on the data for this layer.
When using a
|
position |
A position adjustment to use on the data for this layer. This
can be used in various ways, including to prevent overplotting and
improving the display. The
|
... |
Other arguments passed on to
|
league |
A league key from |
id_system |
|
strict |
If |
na.rm |
If |
show.legend |
logical. Should this layer be included in the legends?
|
inherit.aes |
If |
A ggplot2 layer (ggplot2::layer()) that can be added to a plot
created with ggplot2::ggplot().
geom_sdv_wordmarks() understands the following aesthetics (required aesthetics are in bold):
- The x-coordinate.
- The y-coordinate.
- The team: an abbreviation, name or id, resolved by sdv_resolve().
alpha = NULL- The alpha channel, i.e. transparency level, as a numerical value between 0 and 1.
colour = NULL - The image will be colorized with this colour. Use "b/w" for black and white.
angle = 0- The angle of the image as a numerical value between 0 and 360 degrees.
hjust = 0.5- The horizontal adjustment relative to the given x coordinate.
vjust = 0.5- The vertical adjustment relative to the given y coordinate.
width = 1.0 - The desired width of the image in npc. A typical size is width = 0.12.
height = 1.0 - The desired height of the image in npc. A typical size is height = 0.1.
season = NA - The season whose wordmark to draw, as for geom_sdv_logos().
library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:8] df <- data.frame( a = rep(1:4, 2), b = sort(rep(1:2, 4), decreasing = TRUE), teams = team_abbr ) ggplot(df, aes(x = a, y = b)) + geom_sdv_wordmarks(aes(team = teams), league = "nfl", width = 0.12) + geom_label(aes(label = teams), nudge_y = -0.20, alpha = 0.5) + scale_x_continuous(expand = expansion(add = 0.5)) + theme_void()library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:8] df <- data.frame( a = rep(1:4, 2), b = sort(rep(1:2, 4), decreasing = TRUE), teams = team_abbr ) ggplot(df, aes(x = a, y = b)) + geom_sdv_wordmarks(aes(team = teams), league = "nfl", width = 0.12) + geom_label(aes(label = teams), nudge_y = -0.20, alpha = 0.5) + scale_x_continuous(expand = expansion(add = 0.5)) + theme_void()
These functions work together to place an image to the left or
right of the title in a ggplot. ggtitle_image() is the main function but
must be used with theme_title_image(), which renders the title as
markdown and centers the image on the title text.
ggtitle_image( title_image = ggplot2::waiver(), title = ggplot2::waiver(), image_height = 15, image_side = c("left", "right"), subtitle = ggplot2::waiver(), league ) theme_title_image(...)ggtitle_image( title_image = ggplot2::waiver(), title = ggplot2::waiver(), image_height = 15, image_side = c("left", "right"), subtitle = ggplot2::waiver(), league ) theme_title_image(...)
title_image |
The URL of the image to add to the title. If a valid
team identifier for |
title |
The text for the title. |
image_height |
The height of the image in pixels. |
image_side |
One of |
subtitle |
Optional text for the subtitle. |
league |
A league key from |
... |
Other arguments passed on to |
The title is markdown with an inline <img> tag. 'gridtext' draws
inline images on the text baseline and ignores CSS vertical-align, so a
logo taller than the text would rise above it (ESPN's marks, padded with
transparent space, can sit wholly above the title). theme_title_image()
lines the middle of each image up with the middle of the capital letters
on its line. Setting plot.title to a plain ggtext::element_markdown()
instead also renders the image, on the baseline.
Style the title through theme_title_image(...) (size, face,
hjust, ...), never with a later theme(plot.title = ...): adding
theme(plot.title = ggtext::element_markdown(hjust = 0.5)) after it
replaces the centering element with a plain markdown one, so the image
drops back to the baseline, and theme(plot.title = element_text(...))
is an error. Add theme_title_image() after any complete theme such as
ggplot2::theme_minimal(), which replaces every element.
A ggplot2 labs object (for ggtitle_image) or theme object (for theme_title_image).
library(sdvplotR) library(ggplot2) nfl <- subset(sdv_example_standings, league == "nfl") p <- ggplot(nfl, aes(x = points_for, y = points_against)) + geom_point() + labs( title = "This Title will be overwritten", subtitle = "Points scored and allowed, 2025 regular season" ) if (requireNamespace("ggtext", quietly = TRUE)) { p + ggtitle_image( title_image = "SEA", title = "Seattle Seahawks Analysis", image_height = 20, image_side = "left", league = "nfl" ) + theme_title_image(size = 20, hjust = 0.5) }library(sdvplotR) library(ggplot2) nfl <- subset(sdv_example_standings, league == "nfl") p <- ggplot(nfl, aes(x = points_for, y = points_against)) + geom_point() + labs( title = "This Title will be overwritten", subtitle = "Points scored and allowed, 2025 regular season" ) if (requireNamespace("ggtext", quietly = TRUE)) { p + ggtitle_image( title_image = "SEA", title = "Seattle Seahawks Analysis", image_height = 20, image_side = "left", league = "nfl" ) + theme_title_image(size = 20, hjust = 0.5) }
gt tableAdds a caption block beneath the table with a rule under its top line, in the
style of FiveThirtyEight tables. The top_caption renders as a footnote with
a border drawn under it, and the bottom_caption renders as a right-aligned
source note below it. Both accept markdown.
gt_538_caption( gt_object, top_caption = NULL, bottom_caption = NULL, rule_color = NULL, rule_width = 1, size = 12, align = "right", ... )gt_538_caption( gt_object, top_caption = NULL, bottom_caption = NULL, rule_color = NULL, rule_width = 1, size = 12, align = "right", ... )
gt_object |
A |
top_caption |
Character. Text rendered as a footnote beneath the table,
with a rule drawn under it. Accepts markdown. Defaults to |
bottom_caption |
Character. Text rendered as a source note below the top
caption, aligned by |
rule_color |
Optional. A hex color for the rule under the top caption.
When |
rule_width |
Numeric. The rule width in pixels. Defaults to |
size |
Numeric. The font size of the top caption in pixels. Defaults to
|
align |
Character. The alignment of the bottom caption. Defaults to
|
... |
Additional arguments. Currently unused. |
The top caption is attached with gt::tab_footnote() on the column labels,
which places it in the table footer. Scoped CSS then hides the footnote mark
and draws a bottom border under the footnote, so it reads as a ruled caption
rather than a numbered note. When rule_color is NULL the border color is
taken from the first text color found in the rendered table (via
htmltools::as.tags()), so it tracks the theme across light and dark color
modes, and falls back to a neutral gray when the render carries no color. The
rules are keyed on the table id. If the table has none, one is generated and
assigned.
Apply the theme before this function. The rule color is read off the rendered
table, so calling it first on a dark theme borrows a near-black (#333333)
and the rule disappears into the background. Pass rule_color to sidestep the
question entirely.
Returns a modified gt table with the styled captions.
library(gt) nfc_north <- subset( sdv_example_standings, division == "NFC North", c(team_name, wins:points_against) ) gt(nfc_north) |> gt_538_caption( top_caption = "The NFC North in 2025", bottom_caption = "Source: *nflreadr* schedules, ranked by *nflseedR*" )library(gt) nfc_north <- subset( sdv_example_standings, division == "NFC North", c(team_name, wins:points_against) ) gt(nfc_north) |> gt_538_caption( top_caption = "The NFC North in 2025", bottom_caption = "Source: *nflreadr* schedules, ranked by *nflseedR*" )
gt tableBolds the body cells of chosen rows, with an option to recolor their text and fill their background. Rows are chosen by index or by a filter expression; with neither, every row is bolded.
gt_bold_rows( gt_object, rows = NULL, text_color = "black", highlight_color = NULL )gt_bold_rows( gt_object, rows = NULL, text_color = "black", highlight_color = NULL )
gt_object |
A |
rows |
The rows to bold. Either an expression evaluated against the
table's data, such as |
text_color |
Character. The text color for the bolded rows. Defaults to
|
highlight_color |
Character. The background fill for the bolded rows. Set
to |
rows is evaluated against the table's underlying data, so rows = wins > 10
bolds the rows where that is TRUE; a numeric vector picks rows by index. The
styling is applied with a single
gt::tab_style() over gt::cells_body(), so it covers every column of the
chosen rows.
Returns a modified gt table with the chosen rows bolded.
library(gt) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins:points_against) ) # bold every row gt(nfc_west) |> gt_bold_rows() # bold and fill the teams with a winning record gt(nfc_west) |> gt_bold_rows(rows = win_pct > 0.5, highlight_color = "#FFF3B0")library(gt) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins:points_against) ) # bold every row gt(nfc_west) |> gt_bold_rows() # bold and fill the teams with a winning record gt(nfc_west) |> gt_bold_rows(rows = win_pct > 0.5, highlight_color = "#FFF3B0")
gt tableAdds a row of horizontal color bars below a gt table from a vector of hex
colors, optionally carrying an image and a line of text. The bars are attached
as a source note, so they sit below everything else. It is the bottom-edge
counterpart to gt_border_bars_top().
gt_border_bars_bottom( gt_object, colors, bar_height = 10, bar_width = "100%", bar_align = "center", img = NULL, img_width = 30, img_height = 30, img_padding = 10, img_align = "right", text = NULL, text_weight = "bold", text_color = "#FFFFFF", text_size = 18, text_align = "left", text_padding = 10 )gt_border_bars_bottom( gt_object, colors, bar_height = 10, bar_width = "100%", bar_align = "center", img = NULL, img_width = 30, img_height = 30, img_padding = 10, img_align = "right", text = NULL, text_weight = "bold", text_color = "#FFFFFF", text_size = 18, text_align = "left", text_padding = 10 )
gt_object |
A |
colors |
Character. Hex color codes, one per bar. When |
bar_height |
Numeric. The height of the bars in pixels. Defaults to |
bar_width |
Character. The width of the bar block, as a CSS width.
Defaults to |
bar_align |
Character. Alignment of the block when |
img |
Optional. A URL for an image to render in the bar. It is
decorative, so it carries an empty |
img_width |
Numeric. The image width in pixels. Defaults to |
img_height |
Numeric. The image height in pixels. Defaults to |
img_padding |
Numeric. Padding around the image in pixels, so it does not
touch the edge. Defaults to |
img_align |
Character. The side the image padding is applied to,
|
text |
Optional. Text to display in the bar. Defaults to |
text_weight |
Character. The font weight of the text. Defaults to
|
text_color |
Character. The text color. Defaults to |
text_size |
Numeric. The font size in pixels. Defaults to |
text_align |
Character. The side the text padding is applied to,
|
text_padding |
Numeric. Padding around the text in pixels. Defaults to
|
The bars are added with gt::tab_source_note(), and a table id is resolved or
generated so scoped CSS can zero the source-note padding. With neither img
nor text, each entry in colors becomes its own full-width bar stacked in a
block. When img or text is supplied, a single bar is drawn in the first
color as a flex row with the text at one end and the image at the other. The
text font is read from the table's source-note styling and imported as a
Google Font, falling back to the inherited font when none is set, so it renders
in an exported table.
Returns a modified gt table with a row of bars below it.
library(gt) afc_north <- subset( sdv_example_standings, division == "AFC North", c(team_name, wins:points_against) ) gt(afc_north) |> gt_border_bars_bottom(c("#1B7837", "#FFFFFF", "#B2182B")) # a single bar carrying a credit line atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses, win_pct:points_against) ) gt(atlantic) |> gt_border_bars_bottom("#22223B", text = "Source: hoopR", bar_height = 28)library(gt) afc_north <- subset( sdv_example_standings, division == "AFC North", c(team_name, wins:points_against) ) gt(afc_north) |> gt_border_bars_bottom(c("#1B7837", "#FFFFFF", "#B2182B")) # a single bar carrying a credit line atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses, win_pct:points_against) ) gt(atlantic) |> gt_border_bars_bottom("#22223B", text = "Source: hoopR", bar_height = 28)
gt tableAdds a row of horizontal color bars above a gt table from a vector of hex
colors, optionally carrying an image and a line of text. The bars are attached
as the table caption, so they sit above everything else.
gt_border_bars_top( gt_object, colors, bar_height = 10, bar_width = "100%", bar_align = "center", img = NULL, img_width = 30, img_height = 30, img_padding = 10, img_align = "right", text = NULL, text_weight = "bold", text_color = "#FFFFFF", text_size = 18, text_align = "left", text_padding = 10 )gt_border_bars_top( gt_object, colors, bar_height = 10, bar_width = "100%", bar_align = "center", img = NULL, img_width = 30, img_height = 30, img_padding = 10, img_align = "right", text = NULL, text_weight = "bold", text_color = "#FFFFFF", text_size = 18, text_align = "left", text_padding = 10 )
gt_object |
A |
colors |
Character. Hex color codes, one per bar. When |
bar_height |
Numeric. The height of the bars in pixels. Defaults to |
bar_width |
Character. The width of the bar block, as a CSS width.
Defaults to |
bar_align |
Character. Alignment of the block when |
img |
Optional. A URL for an image to render in the bar. It is
decorative, so it carries an empty |
img_width |
Numeric. The image width in pixels. Defaults to |
img_height |
Numeric. The image height in pixels. Defaults to |
img_padding |
Numeric. Padding around the image in pixels, so it does not
touch the edge. Defaults to |
img_align |
Character. The side the image padding is applied to,
|
text |
Optional. Text to display in the bar. Defaults to |
text_weight |
Character. The font weight of the text. Defaults to
|
text_color |
Character. The text color. Defaults to |
text_size |
Numeric. The font size in pixels. Defaults to |
text_align |
Character. The side the text padding is applied to,
|
text_padding |
Numeric. Padding around the text in pixels. Defaults to
|
The bars are added with gt::tab_caption(), and a table id is resolved or
generated so scoped CSS can zero the caption padding. With neither img nor
text, each entry in colors becomes its own full-width bar stacked in a
block. When img or text is supplied, a single bar is drawn in the first
color as a flex row with the text at one end and the image at the other. The
text font is read from the table's title styling and imported as a Google
Font, falling back to the inherited font when none is set, so it renders in an
exported table.
Returns a modified gt table with a row of bars above it.
library(gt) afc_north <- subset( sdv_example_standings, division == "AFC North", c(team_name, wins:points_against) ) gt(afc_north) |> gt_border_bars_top(c("#1B7837", "#FFFFFF", "#B2182B")) # a single bar carrying a title atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses, win_pct:points_against) ) gt(atlantic) |> gt_border_bars_top("#22223B", text = "Atlantic Division, 2025-26", bar_height = 34)library(gt) afc_north <- subset( sdv_example_standings, division == "AFC North", c(team_name, wins:points_against) ) gt(afc_north) |> gt_border_bars_top(c("#1B7837", "#FFFFFF", "#B2182B")) # a single bar carrying a title atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses, win_pct:points_against) ) gt(atlantic) |> gt_border_bars_top("#22223B", text = "Atlantic Division, 2025-26", bar_height = 34)
gt tableDraws borders between every column and every row of a gt table, giving it a
full grid, with an option to extend the borders around the column and row
labels.
gt_border_grid(gt_object, color = "black", weight = 1, include_labels = FALSE)gt_border_grid(gt_object, color = "black", weight = 1, include_labels = FALSE)
gt_object |
A |
color |
Character. The border color. Defaults to |
weight |
Numeric. The border thickness in pixels. Defaults to |
include_labels |
Logical. Should the borders extend around the row and
column labels? Defaults to |
Column borders are drawn as right cell borders on every column but
the last, and the row borders are added as scoped CSS on the .gt_row top
border. A table id is resolved or generated first, since that CSS is keyed on
#<table_id>.
Returns a modified gt table with the grid borders applied.
library(gt) afc_south <- subset( sdv_example_standings, division == "AFC South", c(team_name, wins:points_against) ) gt(afc_south) |> gt_border_grid() # heavier gray lines, including around the labels pacific <- subset( sdv_example_standings, division == "Pacific", c(team_name, wins, losses, win_pct:points_against) ) gt(pacific) |> gt_border_grid(color = "#BBBBBB", weight = 2, include_labels = TRUE)library(gt) afc_south <- subset( sdv_example_standings, division == "AFC South", c(team_name, wins:points_against) ) gt(afc_south) |> gt_border_grid() # heavier gray lines, including around the labels pacific <- subset( sdv_example_standings, division == "Pacific", c(team_name, wins, losses, win_pct:points_against) ) gt(pacific) |> gt_border_grid(color = "#BBBBBB", weight = 2, include_labels = TRUE)
gt table columnsRenders values as rounded color pills, filled from a palette by either the raw
value or the ordinal rank. Accepts a plain vector of hex colors or a
paletteer palette, and an explicit domain or one taken from the data.
gt_color_ranks() fills the whole cell background instead of a pill.
gt_color_pills( gt_object, columns, rows = NULL, palette = c("#C84630", "#5DA271"), fill_type = "continuous", rank_order = "desc", digits = NULL, domain = NULL, format_type = "number", scale_percent = TRUE, suffix = "", reverse = FALSE, outline_color = NULL, outline_width = 0.25, pal_type = "discrete", pill_height = 25, text_color = NULL, na_color = NULL, ... )gt_color_pills( gt_object, columns, rows = NULL, palette = c("#C84630", "#5DA271"), fill_type = "continuous", rank_order = "desc", digits = NULL, domain = NULL, format_type = "number", scale_percent = TRUE, suffix = "", reverse = FALSE, outline_color = NULL, outline_width = 0.25, pal_type = "discrete", pill_height = 25, text_color = NULL, na_color = NULL, ... )
gt_object |
A |
columns |
The columns to fill with pills, using tidyselect. |
rows |
The rows to fill. Either an expression evaluated against the
table's data, such as |
palette |
A vector of hex colors, or a |
fill_type |
Character. Either |
rank_order |
Character. Either |
digits |
Integer. Decimal places to round the printed value to. Defaults
to |
domain |
Numeric. A length-2 vector giving the value range mapped onto the
palette. If |
format_type |
Character. How to format the printed value. One of
|
scale_percent |
Logical. When |
suffix |
Character. A string appended to each formatted value, such as
|
reverse |
Logical. Should the palette be reversed? Defaults to |
outline_color |
Optional. A hex color for a border around each pill.
Defaults to |
outline_width |
Numeric. The border width in pixels. Defaults to |
pal_type |
Character. Which |
pill_height |
Numeric. The height of each pill in pixels. Defaults to |
text_color |
Optional. A hex color for the pill text. When |
na_color |
Optional. A hex color for the pill drawn over a missing value.
When |
... |
Additional arguments passed to |
Pills are drawn as HTML spans through gt::text_transform(), so they survive
gtsave(). The fill is mapped with scales::col_numeric() over domain, and
the text is set to black or white, whichever measures higher contrast against
that fill, unless text_color is set. A missing value takes an na_color
pill, or is left blank when na_color is NULL.
Selecting several columns maps them all onto one domain, taken from the
selection as a whole when domain is unset, so their colors stay comparable.
Pill width is worked out per column, in ch units, so each column's pills
line up with each other rather than with the widest value in the selection.
With fill_type = "rank", each column is ranked against itself.
When fill_type is "rank", ranks are computed with rank() using averaged
ties, then flipped when rank_order is "desc" so the top value anchors the
high end of the palette. Leaving domain unset falls back to the observed
range and warns, since the color mapping then depends on the data present.
Returns a modified gt table with color pills in the selected columns.
gt_color_ranks() for filling the whole cell, and
gt_legend_continuous() for a legend explaining the scale.
library(gt) # the AFC's seven playoff teams afc <- subset( sdv_example_standings, conference == "AFC" & conference_rank <= 7, c(team_name, wins, losses, points_for, points_against) ) gt(afc) |> gt_color_pills(wins, domain = c(0, 17)) # several columns on one shared domain gt(afc) |> gt_color_pills(c(points_for, points_against), domain = c(250, 550)) # tidyselect works too gt(afc) |> gt_color_pills(starts_with("points"), domain = c(250, 550)) # only the rows that clear a threshold; the rest keep their raw value gt(afc) |> gt_color_pills(wins, rows = wins >= 13, domain = c(0, 17)) # color by rank rather than value, with a paletteer palette if (requireNamespace("paletteer", quietly = TRUE)) { gt(afc) |> gt_color_pills(points_for, fill_type = "rank", palette = "viridis::mako", domain = c(1, 7), digits = 0 ) }library(gt) # the AFC's seven playoff teams afc <- subset( sdv_example_standings, conference == "AFC" & conference_rank <= 7, c(team_name, wins, losses, points_for, points_against) ) gt(afc) |> gt_color_pills(wins, domain = c(0, 17)) # several columns on one shared domain gt(afc) |> gt_color_pills(c(points_for, points_against), domain = c(250, 550)) # tidyselect works too gt(afc) |> gt_color_pills(starts_with("points"), domain = c(250, 550)) # only the rows that clear a threshold; the rest keep their raw value gt(afc) |> gt_color_pills(wins, rows = wins >= 13, domain = c(0, 17)) # color by rank rather than value, with a paletteer palette if (requireNamespace("paletteer", quietly = TRUE)) { gt(afc) |> gt_color_pills(points_for, fill_type = "rank", palette = "viridis::mako", domain = c(1, 7), digits = 0 ) }
gt tableA shorthand around gt::data_color() for filling columns that already hold
rank values, where 1 is best. It takes either a plain vector of hex colors or a
paletteer palette, and either an explicit domain or one derived from the
data. Values are colored as they are; no ranking is computed for you.
gt_color_ranks( gt_object, columns, rows = NULL, palette = c("#3D8B6E", "#9DC5A7", "#EDE0CC", "#DB9070", "#BE4D3A"), domain = NULL, reverse = FALSE, na_color = "white", autocolor_text = TRUE, pal_type = "discrete", ... )gt_color_ranks( gt_object, columns, rows = NULL, palette = c("#3D8B6E", "#9DC5A7", "#EDE0CC", "#DB9070", "#BE4D3A"), domain = NULL, reverse = FALSE, na_color = "white", autocolor_text = TRUE, pal_type = "discrete", ... )
gt_object |
A |
columns |
The column or columns to color. |
rows |
The rows to color. Either an expression evaluated against the
table's data, such as |
palette |
A color palette to use. If you want a palette from |
domain |
A length-2 numeric vector giving the value range mapped onto the
palette. If |
reverse |
Logical. Should the palette be reversed? Defaults to |
na_color |
Character. The color used for |
autocolor_text |
Logical. Should the text color be set automatically for
contrast against the fill? Defaults to |
pal_type |
Character. Either |
... |
Additional arguments passed to |
The whole cell background is filled. gt_color_pills() does the same job with
rounded pill spans instead.
Returns a modified gt table with the selected columns filled by value.
gt_legend_continuous() for explaining the scale, and gt_color_pills()
for a pill treatment instead of a full-cell fill.
library(gt) west <- subset(sdv_example_standings, league == "nba" & conference == "Western") ranked <- data.frame( team = west$team_name, offense_rank = rank(-west$points_for, ties.method = "min"), defense_rank = rank(west$points_against, ties.method = "min") ) gt(ranked) |> gt_color_ranks(c(offense_rank, defense_rank)) # a paletteer palette, reversed if (requireNamespace("paletteer", quietly = TRUE)) { gt(ranked) |> gt_color_ranks(offense_rank, palette = "viridis::mako", pal_type = "continuous", reverse = TRUE ) }library(gt) west <- subset(sdv_example_standings, league == "nba" & conference == "Western") ranked <- data.frame( team = west$team_name, offense_rank = rank(-west$points_for, ties.method = "min"), defense_rank = rank(west$points_against, ties.method = "min") ) gt(ranked) |> gt_color_ranks(c(offense_rank, defense_rank)) # a paletteer palette, reversed if (requireNamespace("paletteer", quietly = TRUE)) { gt(ranked) |> gt_color_ranks(offense_rank, palette = "viridis::mako", pal_type = "continuous", reverse = TRUE ) }
gt table by win, loss, or tie resultFills and recolors each row according to a result read from a column. Results
can be encoded as "W" and "L" or as 1 and 0, with an optional tie
state. Rows holding none of the values are left unchanged.
gt_color_results( gt_object, result_column = "result", win_color = "#5DA271", loss_color = "#C84630", tie_color = NULL, wins_text_color = "white", loss_text_color = "white", tie_text_color = "white", tie_value = "T", result_type = "wl" )gt_color_results( gt_object, result_column = "result", win_color = "#5DA271", loss_color = "#C84630", tie_color = NULL, wins_text_color = "white", loss_text_color = "white", tie_text_color = "white", tie_value = "T", result_type = "wl" )
gt_object |
A |
result_column |
The column holding the result indicators, as a bare
column name or a string. Defaults to |
win_color |
Character. The background fill for winning rows. Defaults to
|
loss_color |
Character. The background fill for losing rows. Defaults to
|
tie_color |
Optional. The background fill for tie rows. When |
wins_text_color |
Character. The text color for winning rows. Defaults to
|
loss_text_color |
Character. The text color for losing rows. Defaults to
|
tie_text_color |
Character. The text color for tie rows. Defaults to
|
tie_value |
The value in |
result_type |
Character. The encoding of |
A gt::tab_style() pass fills and recolors the body rows whose
result_column equals the win value, then the loss value, and then, when
tie_color is set, the tie_value. Under result_type = "wl" the win and
loss values compared are "W" and "L"; under "binary" they are 1 and
0. Any row matching none of the values keeps its existing styling.
Returns a modified gt table with winning and losing rows colored.
library(gt) results <- data.frame( game = paste("Game", 1:4), pts = c(88, 74, 102, 65), result = c("W", "L", "W", "L") ) gt(results) |> gt_color_results() # binary encoding, with custom colors results$result <- c(1, 0, 1, 0) gt(results) |> gt_color_results( result_type = "binary", win_color = "#1B7837", loss_color = "#762A83" )library(gt) results <- data.frame( game = paste("Game", 1:4), pts = c(88, 74, 102, 65), result = c("W", "L", "W", "L") ) gt(results) |> gt_color_results() # binary encoding, with custom colors results$result <- c(1, 0, 1, 0) gt(results) |> gt_color_results( result_type = "binary", win_color = "#1B7837", loss_color = "#762A83" )
gt tableReplaces each column label with a two-line header: a main heading stacked over
a smaller subtitle. The heading and subtitle colors and font weights are set
through arguments, and the per-column heading and subtitle text is supplied
through ....
gt_column_subheaders( gt_object, heading_color = "black", subtitle_color = "#808080", heading_weight = "bold", subtitle_weight = "normal", heading_size = 14, subtitle_size = 10, font = NULL, ... )gt_column_subheaders( gt_object, heading_color = "black", subtitle_color = "#808080", heading_weight = "bold", subtitle_weight = "normal", heading_size = 14, subtitle_size = 10, font = NULL, ... )
gt_object |
A |
heading_color |
Character. Color for the main heading text. Defaults to |
subtitle_color |
Character. Color for the subtitle text. Defaults to |
heading_weight |
Character. Font weight for the main heading. Defaults to |
subtitle_weight |
Character. Font weight for the subtitle. Defaults to |
heading_size |
Numeric. Font size of the main heading in pixels. Defaults to |
subtitle_size |
Numeric. Font size of the subtitle in pixels. Defaults to |
font |
Optional. A font family applied to both lines. It is set as a CSS
|
... |
Named arguments where each name is a column in the |
Every column in the table is relabeled, not only the ones named in .... The
loop walks the full set of column names, looks each one up in ..., and builds
an HTML label holding the heading at heading_size over the subtitle at
subtitle_size, joined by a line break. A column with no entry in ... falls back to its own name as the
heading and a non-breaking space as the subtitle, so the second line still
takes vertical space and the headers stay aligned. Labels are applied with
gt::cols_label(), so call this after any other label changes or they will be
overwritten.
Returns a modified gt table with stacked headers and subtitles.
library(gt) sdv_example_standings |> subset(division == "AFC West", c(team_name, wins, points_for)) |> gt() |> gt_column_subheaders( wins = list(heading = "Wins", subtitle = "W"), points_for = list(heading = "Points", subtitle = "PF"), heading_color = "blue", subtitle_color = "gray" )library(gt) sdv_example_standings |> subset(division == "AFC West", c(team_name, wins, points_for)) |> gt() |> gt_column_subheaders( wins = list(heading = "Wins", subtitle = "W"), points_for = list(heading = "Points", subtitle = "PF"), heading_color = "blue", subtitle_color = "gray" )
gt tableDraws a rule across the table after a given row, with an optional label on it. This is the cut line convention used in ranked and sorted tables to mark a cutoff or qualifying threshold.
gt_cutline( gt_object, after, label = NULL, color = "#A6081A", weight = 2, style = "dashed", label_color = NULL, label_size = 9, label_position = c("below", "above"), gap = 0 )gt_cutline( gt_object, after, label = NULL, color = "#A6081A", weight = 2, style = "dashed", label_color = NULL, label_size = 9, label_position = c("below", "above"), gap = 0 )
gt_object |
A |
after |
Numeric. The row number or numbers to draw a line after. |
label |
Optional. The label or labels for the lines, recycled against
|
color |
Character. A hex color for the rule. Defaults to |
weight |
Numeric. The thickness of the rule in pixels. Defaults to |
style |
Character. The line style. One of |
label_color |
Optional. A hex color for the label. Defaults to |
label_size |
Numeric. The label size in pixels. Defaults to |
label_position |
Character. Either |
gap |
Numeric. Extra space in pixels added around the line to set the two
sections further apart. A single number is applied above and below the line;
a length-2 vector |
The line is positional, not data-driven. gt::tab_row_group() splits a table
on a value in the data and turns the result into labeled sections with heading
rows. A cut line leaves the table flowing and marks a fixed row number.
The label is drawn as an inline SVG background image on the row, because
gt's CSS inliner strips the ::before and ::after pseudo-elements this would
normally be built with. That costs two things. An SVG background cannot use
the page's webfonts, so the label renders in a system sans-serif rather than
the theme's font. And a background image cannot straddle a border, so the
labeled row is given extra padding for the label to sit in.
The labeled row's cell backgrounds are cleared, since row striping and themed
body fills would otherwise cover the label. The row's own color is then
reapplied to the row itself, so a striped theme such as gt_theme_almanac()
keeps an unbroken stripe pattern. Colors set on individual cells in that row,
such as gt_color_ranks() or gt_color_pills() fills, are cleared too; on a
table with colored cells, draw the line unlabeled and describe it in a caption.
Labeled lines assume the table has no row groups, since group heading rows shift the row positions the label CSS targets. The rule itself is unaffected.
Apply the theme before this function. The stripe color is read from the table's options, so a line labeled first loses the stripe under its own row.
Returns a modified gt table with the cut line or lines added.
gt_spotlight() for drawing attention to a row.
library(gt) east <- subset( sdv_example_standings, league == "nba" & conference == "Eastern", c(conference_rank, team_name, wins, losses, win_pct) ) east <- east[order(east$conference_rank), ] # mark where the six teams that skip the play-in end gt(east) |> gt_theme_broadsheet() |> gt_cutline(after = 6, label = "Playoffs") # the play-in line as well, unlabeled gt(east) |> gt_cutline(after = c(6, 10), label = c("Playoffs", NA), color = "#0054AD")library(gt) east <- subset( sdv_example_standings, league == "nba" & conference == "Eastern", c(conference_rank, team_name, wins, losses, win_pct) ) east <- east[order(east$conference_rank), ] # mark where the six teams that skip the play-in end gt(east) |> gt_theme_broadsheet() |> gt_cutline(after = 6, label = "Playoffs") # the play-in line as well, unlabeled gt(east) |> gt_cutline(after = c(6, 10), label = c("Playoffs", NA), color = "#0054AD")
gt tableTakes two numeric columns and inserts a new column holding the change between
them, signed and colored by direction. The change is to minus from, so a
later period as to and an earlier one as from gives a positive number when
the value has grown. The arithmetic, the formatting, and the sign coloring
happen in one call.
gt_delta( gt_object, from, to, column_label = "Change", percent = FALSE, decimals = 1, arrows = FALSE, color = TRUE, color_positive = "#1B7837", color_negative = "#B2182B", color_neutral = NULL, force_sign = TRUE, after = NULL )gt_delta( gt_object, from, to, column_label = "Change", percent = FALSE, decimals = 1, arrows = FALSE, color = TRUE, color_positive = "#1B7837", color_negative = "#B2182B", color_neutral = NULL, force_sign = TRUE, after = NULL )
gt_object |
A |
from |
The starting column, a single numeric column. |
to |
The ending column, a single numeric column. The change is
|
column_label |
Character. The label for the new column. Defaults to
|
percent |
Logical. Should the change be shown as a percent of |
decimals |
Integer. The number of decimal places. Defaults to |
arrows |
Logical. Should an up or down triangle lead the value in place
of a sign? Defaults to |
color |
Logical. Should the values be colored by direction? Defaults to
|
color_positive |
Character. The color for an increase. Defaults to a
green, |
color_negative |
Character. The color for a decrease. Defaults to a red,
|
color_neutral |
Optional. The color for no change. Defaults to |
force_sign |
Logical. Should a plus be shown on an increase? Ignored when
|
after |
Optional. The column the new one is placed after, a position or a
name. Defaults to |
gt::fmt_number(force_sign = TRUE) formats a difference you have already
worked out, and gtExtras::gt_fa_rank_change() handles movement in a rank
column. This computes the delta from two columns, formats it, and colors it by
sign together.
A row is left blank where either from or to is missing, and where a
percent change divides by a from of zero. When arrows is TRUE the value
is shown as a magnitude behind the triangle, so a decrease reads as a down
triangle in front of a positive number.
Returns a modified gt table with the change column added.
gt_scale_note() for disclosing a divided scale.
library(gt) nfc_north <- subset( sdv_example_standings, division == "NFC North", c(team_name, last_season_wins, wins) ) # the change in wins from 2024, colored by sign gt(nfc_north) |> gt_delta(last_season_wins, wins) # as a percent of last season's wins, with arrows gt(nfc_north) |> gt_delta(last_season_wins, wins, percent = TRUE, arrows = TRUE)library(gt) nfc_north <- subset( sdv_example_standings, division == "NFC North", c(team_name, last_season_wins, wins) ) # the change in wins from 2024, colored by sign gt(nfc_north) |> gt_delta(last_season_wins, wins) # as a percent of last season's wins, with arrows gt(nfc_north) |> gt_delta(last_season_wins, wins, percent = TRUE, arrows = TRUE)
gt tableTurns plain integers into ordinals: 1 becomes 1st, 2 becomes 2nd, 23 becomes 23rd. The suffix can be rendered as superscript, which is the usual treatment in a ranked column.
gt_fmt_rank(gt_object, columns, superscript = TRUE, suffix_size = "0.7em")gt_fmt_rank(gt_object, columns, superscript = TRUE, suffix_size = "0.7em")
gt_object |
A |
columns |
The column or columns to format. |
superscript |
Logical. Should the suffix be rendered as superscript?
Defaults to |
suffix_size |
Character. The size of the suffix, as a CSS size. Defaults
to |
Teens are handled correctly, so 11, 12 and 13 take "th" and not "st", "nd" and "rd". Values that are not numeric are left alone.
Returns a modified gt table with ordinal formatting applied.
library(gt) nfc <- subset( sdv_example_standings, conference == "NFC" & conference_rank <= 5, c(team_name, conference_rank) ) nfc <- nfc[order(nfc$conference_rank), ] gt(nfc) |> gt_fmt_rank(conference_rank) # flat, without the superscript gt(nfc) |> gt_fmt_rank(conference_rank, superscript = FALSE)library(gt) nfc <- subset( sdv_example_standings, conference == "NFC" & conference_rank <= 5, c(team_name, conference_rank) ) nfc <- nfc[order(nfc$conference_rank), ] gt(nfc) |> gt_fmt_rank(conference_rank) # flat, without the superscript gt(nfc) |> gt_fmt_rank(conference_rank, superscript = FALSE)
gt tableMerges two or more count columns into one "32-5" style cell, optionally with
one of them shown as a share of the row total. Any set of tallies works, from
wins and losses to tests passed and failed.
gt_fmt_tally( gt_object, columns, separator = "-", label = NULL, share = FALSE, share_of = 1, share_location = c("inline", "column"), share_decimals = 1, share_label = "%", share_prefix = " (", share_suffix = ")", ... )gt_fmt_tally( gt_object, columns, separator = "-", label = NULL, share = FALSE, share_of = 1, share_location = c("inline", "column"), share_decimals = 1, share_label = "%", share_prefix = " (", share_suffix = ")", ... )
gt_object |
A |
columns |
The count columns to combine, in the order they should read. Two or more. |
separator |
Character. The string placed between the counts. Defaults to
|
label |
Optional. A new label for the combined column. Defaults to
|
share |
Logical. Should one of the counts be shown as a share of the row
total? Defaults to |
share_of |
The column the share is computed for, either a position or a
name. Defaults to |
share_location |
Character. Where the share goes. Either |
share_decimals |
Integer. The number of decimal places for the share.
Defaults to |
share_label |
Character. The label for the share column when
|
share_prefix |
Character. The string placed before an inline share.
Defaults to |
share_suffix |
Character. The string placed after an inline share.
Defaults to |
... |
Additional arguments passed to |
The counts are written into the first column and the rest are hidden, or the last one is reused to carry the share, so the table ends up narrower than it started.
gt::cols_merge() will join columns with a pattern and
gt::cols_merge_n_pct() will pair a count with a percentage column you have
already built. The difference here is that the share is computed for you from
the counts themselves.
A row is left alone if any of its counts are missing, so a partial tally is never shown. The share is also left blank where the counts sum to zero.
Returns a modified gt table with the counts combined.
gt_fmt_rank() for ordinal formatting.
library(gt) atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses) ) # renders as "56-26" gt(atlantic) |> gt_fmt_tally(c(wins, losses), label = "Record") # renders as "56-26 (68.3%)" gt(atlantic) |> gt_fmt_tally(c(wins, losses), share = TRUE) # the losing share instead, in its own column gt(atlantic) |> gt_fmt_tally(c(wins, losses), share = TRUE, share_of = "losses", share_location = "column", share_label = "Loss rate" ) # three counts, as in an NFL standings table nfc_east <- subset( sdv_example_standings, division == "NFC East", c(team_name, wins, losses, ties) ) gt(nfc_east) |> gt_fmt_tally(c(wins, losses, ties), label = "W-L-T")library(gt) atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses) ) # renders as "56-26" gt(atlantic) |> gt_fmt_tally(c(wins, losses), label = "Record") # renders as "56-26 (68.3%)" gt(atlantic) |> gt_fmt_tally(c(wins, losses), share = TRUE) # the losing share instead, in its own column gt(atlantic) |> gt_fmt_tally(c(wins, losses), share = TRUE, share_of = "losses", share_location = "column", share_label = "Loss rate" ) # three counts, as in an NFL standings table nfc_east <- subset( sdv_example_standings, division == "NFC East", c(team_name, wins, losses, ties) ) gt(nfc_east) |> gt_fmt_tally(c(wins, losses, ties), label = "W-L-T")
gt tables in a gridLays a list of tables out in rows and columns as small multiples, one table
per region or per quarter. gtExtras::gt_two_column_layout() handles exactly
two tables and gt_stack_tables() stacks any number of them vertically. This
covers the rest.
gt_grid( tables = NULL, ncol = 2, labels = NULL, label_style = list(), title = NULL, subtitle = NULL, caption = NULL, source_note = NULL, caption_rule = FALSE, title_style = list(), subtitle_style = list(), caption_style = list(), source_note_style = list(), gap = 24, align = c("top", "center", "bottom"), file = NULL, bg = "white", whitespace = 50, zoom = 2 )gt_grid( tables = NULL, ncol = 2, labels = NULL, label_style = list(), title = NULL, subtitle = NULL, caption = NULL, source_note = NULL, caption_rule = FALSE, title_style = list(), subtitle_style = list(), caption_style = list(), source_note_style = list(), gap = 24, align = c("top", "center", "bottom"), file = NULL, bg = "white", whitespace = 50, zoom = 2 )
tables |
A list of |
ncol |
Integer. The number of tables across. The number of rows follows
from the length of |
labels |
Character. An optional caption above each table, recycled
against |
label_style |
A list of style options for the per-table captions. See
|
title |
Character. An optional heading above the whole grid. Set this
instead of giving each table its own |
subtitle |
Character. An optional line below |
caption |
Character. An optional note below the grid. Defaults to |
source_note |
Character. An optional second line below |
caption_rule |
Logical. Should a hairline rule sit between |
title_style, subtitle_style, caption_style, source_note_style
|
Lists of
style options. Recognized keys are |
gap |
Numeric. The space between tables in pixels. Defaults to |
align |
Character. How tables of differing height line up within a row.
Either |
file |
Optional. A path to write a PNG to. If |
bg |
Character. The background color, used when saving. Defaults to
|
whitespace |
Numeric. Padding left around the grid when saving, in
pixels. Defaults to |
zoom |
Numeric. The rendering zoom factor used when saving. Defaults to
|
Unlike most of this package, this does not return a gt table. Separate
tables have their own columns, widths, and headers, so there is no single
table to hand back; the grid is assembled as HTML. That makes it a last step,
after each table is themed and formatted, and it is why saving happens here
through file rather than through gt_save_crop().
Each table also keeps its own heading. Use title when the tables are blocks
of a single thing, as with a long ranking split in two, and per-table
gt::tab_header()s when they are genuinely separate exhibits.
Saving needs the webshot2 package.
An htmltools::browsable() tag list of the grid, which prints in
the viewer; with file, invisibly file after writing the PNG to it.
gt_stack_tables() for a vertical stack, and gt_snake() for
folding a single long table into blocks.
library(gt) afc <- subset(sdv_example_standings, conference == "AFC") by_division <- lapply(split(afc, afc$division), function(d) { gt(d[c("team_name", "wins", "losses", "points_for")]) |> gt_theme_broadsheet() |> tab_header(title = d$division[[1]]) }) gt_grid(by_division, ncol = 2) # one heading over the whole sheet gt_grid(by_division, ncol = 2, title = "The AFC by division", subtitle = "2025 NFL regular season", caption = "Data: nflreadr" ) # a 538-style split caption under the whole sheet gt_grid(by_division, ncol = 2, title = "The AFC by division", caption = gt::md("Teams are grouped by **division**."), source_note = "Data: nflreadr | Andrew Weatherman", caption_rule = TRUE ) # tighten the subtitle up under the title, and open the gap to the grid gt_grid(by_division, ncol = 2, title = "The AFC", subtitle = "2025 regular season", title_style = list(margin_bottom = -2), subtitle_style = list(margin_bottom = 24) ) # styled without writing any css gt_grid(by_division, ncol = 2, title = "The AFC by division", subtitle = "2025 NFL regular season", title_style = list(font = "Oswald", size = 34, transform = "uppercase"), subtitle_style = list(italic = TRUE, color = "#8A8A8A") ) # straight to an image; saving needs a headless Chrome (webshot2) gt_grid(by_division, ncol = 2, file = tempfile(fileext = ".png"), bg = "#FBFAF7")library(gt) afc <- subset(sdv_example_standings, conference == "AFC") by_division <- lapply(split(afc, afc$division), function(d) { gt(d[c("team_name", "wins", "losses", "points_for")]) |> gt_theme_broadsheet() |> tab_header(title = d$division[[1]]) }) gt_grid(by_division, ncol = 2) # one heading over the whole sheet gt_grid(by_division, ncol = 2, title = "The AFC by division", subtitle = "2025 NFL regular season", caption = "Data: nflreadr" ) # a 538-style split caption under the whole sheet gt_grid(by_division, ncol = 2, title = "The AFC by division", caption = gt::md("Teams are grouped by **division**."), source_note = "Data: nflreadr | Andrew Weatherman", caption_rule = TRUE ) # tighten the subtitle up under the title, and open the gap to the grid gt_grid(by_division, ncol = 2, title = "The AFC", subtitle = "2025 regular season", title_style = list(margin_bottom = -2), subtitle_style = list(margin_bottom = 24) ) # styled without writing any css gt_grid(by_division, ncol = 2, title = "The AFC by division", subtitle = "2025 NFL regular season", title_style = list(font = "Oswald", size = 34, transform = "uppercase"), subtitle_style = list(italic = TRUE, color = "#8A8A8A") ) # straight to an image; saving needs a headless Chrome (webshot2) gt_grid(by_division, ncol = 2, file = tempfile(fileext = ".png"), bg = "#FBFAF7")
gt tableShades every other row group, so each group reads as a block. gt::opt_row_striping()
bands every other row, which fights the grouping on a table that is already
divided into sections.
gt_group_stripes(gt_object, color = "#F5F5F5", start = 2, include_stub = TRUE)gt_group_stripes(gt_object, color = "#F5F5F5", start = 2, include_stub = TRUE)
gt_object |
A |
color |
Character. A hex color for the banded groups. Defaults to
|
start |
Integer. Which group to begin banding on, in the order the groups
are rendered. |
include_stub |
Logical. Should the stub column be banded along with the
body? Defaults to |
Groups are banded in the order they render, so this follows
gt::row_group_order() rather than the order the groups happen to appear in
the data.
The fill is applied to body cells rather than through CSS, because a group
heading occupies a row of its own and shifts every nth-child count below it.
Group heading rows are left alone; gt::tab_options(row_group.background.color)
sets those, and it sets all of them at once.
Returns a modified gt table with alternate groups banded.
library(gt) afc <- subset( sdv_example_standings, conference == "AFC", c(team_name, division, wins, losses, points_for) ) gt(afc, groupname_col = "division") |> gt_theme_broadsheet() |> gt_group_stripes() # shade from the first group instead, in a warmer tone gt(afc, groupname_col = "division") |> gt_group_stripes(color = "#FBF3E4", start = 1)library(gt) afc <- subset( sdv_example_standings, conference == "AFC", c(team_name, division, wins, losses, points_for) ) gt(afc, groupname_col = "division") |> gt_theme_broadsheet() |> gt_group_stripes() # shade from the first group instead, in a warmer tone gt(afc, groupname_col = "division") |> gt_group_stripes(color = "#FBF3E4", start = 1)
gt table by a conditionFills each cell in a block of columns that meets a condition and leaves the
rest alone. It is the per-cell counterpart to gtExtras::gt_highlight_cols()
and gtExtras::gt_highlight_rows(), which fill a whole column or a whole row.
The condition is tested against every cell on its own, so a scattered set of
cells can be filled in one call.
gt_highlight_cells( gt_object, columns, condition, fill = "#FFF3B0", text_color = NULL, bold = FALSE, ... )gt_highlight_cells( gt_object, columns, condition, fill = "#FFF3B0", text_color = NULL, bold = FALSE, ... )
gt_object |
A |
columns |
The block of columns to test, the body of the grid. |
condition |
How a cell is chosen. Either a function or a right-hand-side
formula applied to each column and returning a logical vector ( |
fill |
Character. The cell fill color. Defaults to |
text_color |
Optional. A hex color for the text in filled cells. Defaults
to |
bold |
Logical. Should filled cells be bolded? Defaults to |
... |
Additional arguments passed to |
A single gt::tab_style() with gt::cells_body() cannot do this, since it
reads rows and columns as a rectangle, every selected row crossed with
every selected column. Filling a diagonal, a checker pattern, or any scatter
otherwise takes a loop over the columns, one pass each. This wraps that loop.
Each selected column is filled independently, so the pattern can be a diagonal, a checker, or any scatter of cells.
The condition reads the underlying data rather than the rendered cell, so a
test like ~ grepl("home", .x) sees whatever value the column holds, HTML and
all. A formula or function must return one logical per row, and NA counts as
not matched. For more than one color, layer the calls, one per color.
Returns a modified gt table with the matching cells filled.
gtExtras::gt_highlight_cols() and gtExtras::gt_highlight_rows()
for whole-column and whole-row fills.
library(gt) # a correlation matrix: flag strong pairs, but not the diagonal of ones nba <- subset(sdv_example_standings, league == "nba") nba$point_diff <- nba$points_for - nba$points_against vars <- c("wins", "point_diff", "points_for", "points_against", "conference_rank") m <- round(cor(nba[vars]), 2) cordf <- data.frame(var = rownames(m), m, row.names = NULL, check.names = FALSE) cordf |> gt(rowname_col = "var") |> gt_highlight_cells(-var, ~ .x > 0.7 & .x < 1, fill = "#FFD1A9") |> gt_highlight_cells(-var, ~ .x < -0.7, fill = "#A9D0FF") # a grid of team keys, one column per division in finishing order: playoff # teams one color, the conference's top seed another afc <- subset(sdv_example_standings, conference == "AFC") grid <- data.frame(split(afc$team, afc$division), check.names = FALSE) playoffs <- afc$team[afc$conference_rank <= 7] top_seed <- afc$team[afc$conference_rank == 1] gt(grid) |> gt_highlight_cells(everything(), ~ .x %in% playoffs, fill = "#CCE7F5") |> gt_highlight_cells(everything(), ~ .x == top_seed, fill = "#FCCF10")library(gt) # a correlation matrix: flag strong pairs, but not the diagonal of ones nba <- subset(sdv_example_standings, league == "nba") nba$point_diff <- nba$points_for - nba$points_against vars <- c("wins", "point_diff", "points_for", "points_against", "conference_rank") m <- round(cor(nba[vars]), 2) cordf <- data.frame(var = rownames(m), m, row.names = NULL, check.names = FALSE) cordf |> gt(rowname_col = "var") |> gt_highlight_cells(-var, ~ .x > 0.7 & .x < 1, fill = "#FFD1A9") |> gt_highlight_cells(-var, ~ .x < -0.7, fill = "#A9D0FF") # a grid of team keys, one column per division in finishing order: playoff # teams one color, the conference's top seed another afc <- subset(sdv_example_standings, conference == "AFC") grid <- data.frame(split(afc$team, afc$division), check.names = FALSE) playoffs <- afc$team[afc$conference_rank <= 7] top_seed <- afc$team[afc$conference_rank == 1] gt(grid) |> gt_highlight_cells(everything(), ~ .x %in% playoffs, fill = "#CCE7F5") |> gt_highlight_cells(everything(), ~ .x == top_seed, fill = "#FCCF10")
gt tableHighlights missing cells and can relabel them in the same call.
gt::sub_missing() substitutes text only, and only for real NA values.
gt_highlight_na( gt_object, columns = gt::everything(), fill = "#F0F0F0", text_color = NULL, bold = FALSE, italic = FALSE, missing_text = NULL, na_strings = "NA", ignore_case = FALSE, ... )gt_highlight_na( gt_object, columns = gt::everything(), fill = "#F0F0F0", text_color = NULL, bold = FALSE, italic = FALSE, missing_text = NULL, na_strings = "NA", ignore_case = FALSE, ... )
gt_object |
A |
columns |
The column or columns to check. Defaults to all of them. |
fill |
Character. A hex color for the cell fill behind missing values.
Defaults to |
text_color |
Optional. A hex color for the text of missing values.
Defaults to |
bold |
Logical. Should missing values be bolded? Defaults to |
italic |
Logical. Should missing values be italicized? Defaults to |
missing_text |
Optional. Replacement text for missing values, such as
|
na_strings |
A character vector of strings to treat as missing alongside
real |
ignore_case |
Logical. Should |
... |
Additional arguments passed to |
Alongside real NA, this also catches values that are literally the string
"NA", a common artifact of reading a CSV and a frequent reason
sub_missing() appears to do nothing. Widen na_strings to catch other
placeholders such as "-" or "N/A".
Returns a modified gt table with missing values styled.
gt_outliers() for flagging values that are present but suspect.
library(gt) # playoff_wins is NA for the teams that missed the playoffs afc <- subset( sdv_example_standings, conference == "AFC", c(team_name, wins, losses, conference_rank, playoff_wins) ) gt(afc) |> gt_highlight_na(playoff_wins) # relabel as well as highlight gt(afc) |> gt_highlight_na(playoff_wins, missing_text = "missed playoffs", italic = TRUE, fill = "#FFF8E1" ) # also catch placeholder strings left behind by a CSV import gt(afc) |> gt_highlight_na(everything(), na_strings = c("NA", "N/A", "-"))library(gt) # playoff_wins is NA for the teams that missed the playoffs afc <- subset( sdv_example_standings, conference == "AFC", c(team_name, wins, losses, conference_rank, playoff_wins) ) gt(afc) |> gt_highlight_na(playoff_wins) # relabel as well as highlight gt(afc) |> gt_highlight_na(playoff_wins, missing_text = "missed playoffs", italic = TRUE, fill = "#FFF8E1" ) # also catch placeholder strings left behind by a CSV import gt(afc) |> gt_highlight_na(everything(), na_strings = c("NA", "N/A", "-"))
gt tableReplaces column values with colored boxes, filled when a value meets a rule
and left neutral otherwise. By default the box is colored when a value equals
the second element of indicator_vals (1) and left color_no when it equals
the first (0); supply indicator_rule for any other test. Name the columns
to convert with columns, or the ones to leave alone with key_columns.
gt_indicator_boxes( gt_object, columns = NULL, key_columns = NULL, indicator_vals = c(0, 1), indicator_rule = function(x) x == indicator_vals[2], color_yes = "#FCCF10", color_no = "#EEEEEE", show_na_as_na = FALSE, show_text = FALSE, show_only = NULL, per_column_formats = NULL, color_na = NULL, border_color = NULL, border_width = 0.25, box_width = 20, box_height = 20, text_size = 12, text_weight = "bold" )gt_indicator_boxes( gt_object, columns = NULL, key_columns = NULL, indicator_vals = c(0, 1), indicator_rule = function(x) x == indicator_vals[2], color_yes = "#FCCF10", color_no = "#EEEEEE", show_na_as_na = FALSE, show_text = FALSE, show_only = NULL, per_column_formats = NULL, color_na = NULL, border_color = NULL, border_width = 0.25, box_width = 20, box_height = 20, text_size = 12, text_weight = "bold" )
gt_object |
A |
columns |
The columns to convert to boxes, using tidyselect. Defaults to
|
key_columns |
The columns to leave untouched, using tidyselect. Every
other column is converted. Kept for the inverted way of saying the same
thing; give this or |
indicator_vals |
Numeric. A length-2 vector giving the "no" and "yes"
values. Defaults to |
indicator_rule |
A function deciding when a box is colored. It receives
the column values, and optionally the column name as a second argument, and
returns a logical vector. Defaults to testing equality with
|
color_yes |
Character. The fill for boxes meeting the rule. Defaults to
|
color_no |
Character. The fill for boxes not meeting the rule. Defaults to
|
show_na_as_na |
Logical. Should |
show_text |
Logical. Should the formatted value be printed inside the box?
Defaults to |
show_only |
Character. Restrict printed text to one class of box, one of
|
per_column_formats |
A named list keyed by column name, each element a
list of formatting options ( |
color_na |
Character. The fill for |
border_color |
Character. The border color around the boxes. Defaults to
|
border_width |
Numeric. The border width in pixels. Defaults to |
box_width |
Numeric. The box width in pixels, used when |
box_height |
Numeric. The box height in pixels. Defaults to |
text_size |
Numeric. The font size of the box text in pixels, used when
|
text_weight |
Character. The font weight of the box text. Defaults to
|
Every column outside key_columns is replaced with an HTML span through
gt::text_transform(), and the transformed columns are then center-aligned.
The rule is applied to the numeric coercion of each column, so text values
become NA; NA cells take color_na (falling back to color_no) unless
show_na_as_na keeps them labeled NA. Box text is set to black or white,
whichever measures higher contrast against the fill.
When show_text is TRUE the box widens to fit the widest formatted value in
the column; otherwise it is fixed at box_width. indicator_rule may accept a
second argument, the column name, which allows a different test per column.
Returns a modified gt table with the converted columns shown as
colored boxes.
library(gt) roster <- data.frame( player = c("A", "B", "C"), starter = c(1, 0, 1), injured = c(0, 0, 1), captain = c(1, 0, 0) ) gt(roster) |> gt_indicator_boxes(key_columns = "player") # print the underlying values and draw a border gt(roster) |> gt_indicator_boxes( key_columns = "player", show_text = TRUE, border_color = "#333333" )library(gt) roster <- data.frame( player = c("A", "B", "C"), starter = c(1, 0, 1), injured = c(0, 0, 1), captain = c(1, 0, 0) ) gt(roster) |> gt_indicator_boxes(key_columns = "player") # print the underlying values and draw a border gt(roster) |> gt_indicator_boxes( key_columns = "player", show_text = TRUE, border_color = "#333333" )
gt tableDraws a legend for a column colored with gt_color_ranks() or
gt::data_color(). Pass it the same columns and palette you colored with
and the legend will match the table, including the domain it takes from the
data. For a hand-built key of labeled swatches, use gt_legend_discrete().
gt_legend_continuous( gt_object, columns = NULL, palette = c("#3D8B6E", "#9DC5A7", "#EDE0CC", "#DB9070", "#BE4D3A"), domain = NULL, reverse = FALSE, pal_type = "discrete", type = c("continuous", "steps", "blocks"), n_bins = 5, labels = NULL, digits = 0, title = NULL, title_position = c("top", "bottom", "left", "right"), title_style = list(), labels_style = list(), labels_position = c("bottom", "top", "none"), location = c("bottom", "top"), align = c("center", "left", "right"), width = 200, height = 10, border_color = NULL, border_width = 1, radius = 2, gap = 3, title_gap = 4, block_gap = 2 )gt_legend_continuous( gt_object, columns = NULL, palette = c("#3D8B6E", "#9DC5A7", "#EDE0CC", "#DB9070", "#BE4D3A"), domain = NULL, reverse = FALSE, pal_type = "discrete", type = c("continuous", "steps", "blocks"), n_bins = 5, labels = NULL, digits = 0, title = NULL, title_position = c("top", "bottom", "left", "right"), title_style = list(), labels_style = list(), labels_position = c("bottom", "top", "none"), location = c("bottom", "top"), align = c("center", "left", "right"), width = 200, height = 10, border_color = NULL, border_width = 1, radius = 2, gap = 3, title_gap = 4, block_gap = 2 )
gt_object |
A |
columns |
The column or columns the legend describes, used to derive
|
palette |
A color palette to use. If you want a palette from |
domain |
A length-2 numeric vector giving the value range the palette
spans. If |
reverse |
Logical. Should the palette be reversed? Set this to match the
|
pal_type |
Character. Either |
type |
Character. The appearance of the bar. One of |
n_bins |
Integer. The number of bins when |
labels |
The tick labels. If |
digits |
Integer. The number of decimal places used when deriving labels
from |
title |
Optional. A caption for the legend. Defaults to |
title_position |
Character. Which side of the bar the title sits on. One
of |
title_style |
A named list styling the title. See Styling. Defaults to an empty list. |
labels_style |
A named list styling the bound labels. See Styling. Defaults to an empty list. |
labels_position |
Character. One of |
location |
Character. Where to place the legend. |
align |
Character. The horizontal alignment of the whole legend. One of
|
width |
Numeric. The width of the bar in pixels. Defaults to |
height |
Numeric. The height of the bar in pixels. Defaults to |
border_color |
Optional. A hex color for a border around the bar, or
around each block when |
border_width |
Numeric. The border width in pixels. Defaults to |
radius |
Numeric. The corner radius of the bar in pixels. Defaults to |
gap |
Numeric. The gap between the bar and its labels, in pixels.
Defaults to |
title_gap |
Numeric. The gap between the title and the bar, in pixels.
Defaults to |
block_gap |
Numeric. The gap between blocks when |
The bar can be a smooth gradient, a stepped ramp, or separated blocks. The
title can sit on any side of it, and the title and bound labels are styled
independently through title_style and labels_style.
The bar is drawn as a series of solid color segments instead of a CSS
gradient. gt's inline-CSS path, used by the RStudio Viewer, Quarto and R
Markdown, strips gradient backgrounds, and the legend would disappear. Segment
colors come from scales::col_numeric, the same function gt::data_color()
uses, so the ramp matches the cells exactly.
gt_title_header() calls gt::tab_header(), which replaces the whole header.
With location = "top", call gt_title_header() first or it will overwrite
the legend.
Returns a modified gt table with the legend added.
title_style and labels_style are named lists following the same convention
as gt_grid() and gt_title_header(). Recognized keys are font (a Google
font name), size, color, weight, italic, spacing (letter spacing),
transform (such as "uppercase"), and align, plus line_height,
margin_top, margin_bottom, padding_top, and padding_bottom. Any length
takes a number, read as pixels, or a CSS string.
gt_color_ranks(), gt_color_pills() and gt_percentile_bar() record the
columns, palette, domain, reverse and pal_type they used on the
table. This function reads any of those the caller did not supply, so a legend
can be added with no arguments and cannot disagree with the cells it explains:
gt(df) |> gt_color_ranks(net, palette = "viridis::mako", domain = c(-10, 12)) |> gt_legend_continuous()
Anything passed explicitly wins over the recorded value. With several coloring
calls, the most recent one is the one recorded. The record is an attribute on
the table and survives the rest of a pipeline, apart from gt_snake(), which
rebuilds the table from its data; add the legend before snaking, or pass the
arguments directly.
gt_color_ranks(), and gt_legend_discrete() for a discrete key.
library(gt) # the legend matches whatever gt_color_ranks() drew nfc_east <- subset( sdv_example_standings, division == "NFC East", c(team_name, wins, losses, points_for) ) gt(nfc_east) |> gt_color_ranks(columns = points_for) |> gt_legend_continuous(columns = points_for, title = "Points scored") # discrete blocks, labeled at every bin edge, title to the left west <- subset( sdv_example_standings, league == "nba" & conference == "Western", c(team_name, wins, losses) ) gt(west) |> gt_color_ranks(columns = wins) |> gt_legend_continuous( columns = wins, type = "blocks", n_bins = 5, labels = "edges", title = "Wins", title_position = "left", title_style = list( weight = 600, transform = "uppercase", spacing = "0.08em", size = "10px" ), labels_style = list(size = "9px", color = "#999999") )library(gt) # the legend matches whatever gt_color_ranks() drew nfc_east <- subset( sdv_example_standings, division == "NFC East", c(team_name, wins, losses, points_for) ) gt(nfc_east) |> gt_color_ranks(columns = points_for) |> gt_legend_continuous(columns = points_for, title = "Points scored") # discrete blocks, labeled at every bin edge, title to the left west <- subset( sdv_example_standings, league == "nba" & conference == "Western", c(team_name, wins, losses) ) gt(west) |> gt_color_ranks(columns = wins) |> gt_legend_continuous( columns = wins, type = "blocks", n_bins = 5, labels = "edges", title = "Wins", title_position = "left", title_style = list( weight = 600, transform = "uppercase", spacing = "0.08em", size = "10px" ), labels_style = list(size = "9px", color = "#999999") )
gt tableDraws a legend of labeled color swatches, the categorical counterpart to
gt_legend_continuous(), which draws a continuous ramp. Give it the colors and
labels you used elsewhere in the table, such as the fills from
gt_highlight_cells() or gt_indicator_boxes(), and it renders a color key.
After gt_tiers(), which records its mapping on the table, key_info can be
left out entirely.
gt_legend_discrete( gt_object, key_info = NULL, heading = NULL, subtitle = NULL, label_placement = c("outside", "inside"), location = c("top", "bottom"), shape = c("square", "rounded", "circle"), swatch_size = 14, border = TRUE, border_color = NULL, border_width = 1, gap = 14, direction = c("horizontal", "vertical"), align = c("center", "left", "right"), heading_style = list(), subtitle_style = list(), label_style = list() )gt_legend_discrete( gt_object, key_info = NULL, heading = NULL, subtitle = NULL, label_placement = c("outside", "inside"), location = c("top", "bottom"), shape = c("square", "rounded", "circle"), swatch_size = 14, border = TRUE, border_color = NULL, border_width = 1, gap = 14, direction = c("horizontal", "vertical"), align = c("center", "left", "right"), heading_style = list(), subtitle_style = list(), label_style = list() )
gt_object |
A |
key_info |
The key. Either a named character vector of |
heading |
Optional. A heading shown above the key. Defaults to |
subtitle |
Optional. A subtitle shown under the heading. Defaults to
|
label_placement |
Character. Either |
location |
Character. Where the key goes. |
shape |
Character. The swatch shape, one of |
swatch_size |
Numeric. The swatch size in pixels. Defaults to |
border |
Logical. Should a hairline be drawn around each swatch? This
keeps a pale swatch visible against the page. Defaults to |
border_color |
Optional. A hex color for the hairline, applied to every
swatch. When |
border_width |
Numeric. The hairline width in pixels. Defaults to |
gap |
Numeric. The space between keys in pixels. Defaults to |
direction |
Character. Whether the keys run |
align |
Character. The alignment of the whole key, one of |
heading_style |
A named list styling the heading. See Styling. Defaults to an empty list. |
subtitle_style |
A named list styling the subtitle. See Styling. Defaults to an empty list. |
label_style |
A named list styling the swatch labels. See Styling. For
|
The key can sit above the table or below it, run in a row or a column, and take square, rounded, or circular swatches. An optional heading and subtitle can ride along above the swatches, each styled through its own list.
The key is passed as either a named vector, c("Home" = "#cce7f5", "Bye" = "#eeeeee"), where the names are the labels, or a data frame with a color
column and a label column.
When label_placement is "inside", each label takes black or white by
whichever contrasts better with its swatch, so a color in label_style is
ignored in that mode.
gt_title_header() and anything else calling gt::tab_header() replaces the
whole header. With location = "top", add those first or they will overwrite
the key.
Returns a modified gt table with the key added.
heading_style, subtitle_style, and label_style are named lists following
the same convention as gt_grid() and gt_title_header(). Recognized keys are
font (a Google font name), size, color, weight, italic, spacing
(letter spacing), transform (such as "uppercase"), and align, plus
line_height, margin_top, margin_bottom, padding_top, and
padding_bottom. Any length takes a number, read as pixels, or a CSS string.
Any key left out keeps its default. Colors left unset are derived from the
table background, so the key reads on light and dark themes. Apply the theme
first, since an unthemed table reports a white background and the heading and
subtitle come out near-black on whatever ground the theme sets later.
gt_legend_continuous() for a continuous ramp.
library(gt) afc_west <- subset( sdv_example_standings, division == "AFC West", c(team_name, wins, losses, playoff_wins) ) # a named vector is the quickest way in gt(afc_west) |> gt_legend_discrete(c("Playoffs" = "#CCE7F5", "Missed" = "#F5CCCC")) # rounded swatches below the table, labels on the swatches gt(afc_west) |> gt_legend_discrete( c("Yes" = "#FCCF10", "No" = "#EEEEEE"), heading = "Qualified", label_placement = "inside", location = "bottom", shape = "rounded" ) # style the heading and labels through lists, the same way gt_grid() does gt(afc_west) |> gt_legend_discrete( c("Home" = "#CCE7F5", "Away" = "#FFFFFF", "Bye" = "#EEEEEE"), heading = "2025 Schedule", heading_style = list(font = "Oswald", size = 20, transform = "uppercase"), label_style = list(size = 13, color = "#444444") )library(gt) afc_west <- subset( sdv_example_standings, division == "AFC West", c(team_name, wins, losses, playoff_wins) ) # a named vector is the quickest way in gt(afc_west) |> gt_legend_discrete(c("Playoffs" = "#CCE7F5", "Missed" = "#F5CCCC")) # rounded swatches below the table, labels on the swatches gt(afc_west) |> gt_legend_discrete( c("Yes" = "#FCCF10", "No" = "#EEEEEE"), heading = "Qualified", label_placement = "inside", location = "bottom", shape = "rounded" ) # style the heading and labels through lists, the same way gt_grid() does gt(afc_west) |> gt_legend_discrete( c("Home" = "#CCE7F5", "Away" = "#FFFFFF", "Bye" = "#EEEEEE"), heading = "2025 Schedule", heading_style = list(font = "Oswald", size = 20, transform = "uppercase"), label_style = list(size = 13, color = "#444444") )
Styles a text column as commentary instead of data. It applies a muted color, italics, a hairline separating the notes from the figures, a blank column label, and a width constraint so the prose wraps instead of stretching the table.
gt_marginalia( gt_object, columns, width = 220, label = "", italic = TRUE, color = NULL, size = "0.92em", rule = TRUE, rule_color = NULL, align = "left" )gt_marginalia( gt_object, columns, width = 220, label = "", italic = TRUE, color = NULL, size = "0.92em", rule = TRUE, rule_color = NULL, align = "left" )
gt_object |
A |
columns |
The column or columns to treat as margin notes. |
width |
Numeric. The column width in pixels, which is what makes the prose
wrap. Pass |
label |
Character. The column label. Defaults to |
italic |
Logical. Should the notes be italicized? Defaults to |
color |
Optional. A hex color for the text. If |
size |
Character. The font size, as a CSS size. Defaults to |
rule |
Logical. Should a hairline be drawn on the left edge, separating
the notes from the data? Defaults to |
rule_color |
Optional. A hex color for that hairline. Derived from the
table background when |
align |
Character. The text alignment. Defaults to |
A text column with no width set runs to a single long line, so width is what
wraps the prose. On a three-row example, that is the difference between a table
625 pixels wide and one 482 pixels wide.
Colors are derived from the table background instead of being hard-coded, so
the treatment also reads correctly on a dark theme. That means the theme has
to be applied first. An unthemed table reports a white background, and the
notes come out too dark to read once a dark theme lands on top. Pass color
and rule_color to fix them regardless of order.
Returns a modified gt table with the selected columns styled as
margin notes.
gt_cutline() for a labeled break between rows.
library(gt) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins, losses, conference_rank, playoff_wins) ) # a note on each team's postseason, written from its own row nfc_west$note <- with(nfc_west, ifelse( is.na(playoff_wins), "Missed the playoffs.", paste0( "The No. ", conference_rank, " seed; ", playoff_wins, " playoff win", ifelse(playoff_wins == 1, "", "s"), "." ) )) gt(nfc_west) |> gt_theme_broadsheet() |> gt_marginalia(note) # keep a heading, widen it, and drop the italics gt(nfc_west) |> gt_marginalia(note, label = "Postseason", width = 280, italic = FALSE)library(gt) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins, losses, conference_rank, playoff_wins) ) # a note on each team's postseason, written from its own row nfc_west$note <- with(nfc_west, ifelse( is.na(playoff_wins), "Missed the playoffs.", paste0( "The No. ", conference_rank, " seed; ", playoff_wins, " playoff win", ifelse(playoff_wins == 1, "", "s"), "." ) )) gt(nfc_west) |> gt_theme_broadsheet() |> gt_marginalia(note) # keep a heading, widen it, and drop the italics gt(nfc_west) |> gt_marginalia(note, label = "Postseason", width = 280, italic = FALSE)
Takes an existing gt table and merges column 1 and column 2,
stacking column 1's text on top of column 2's. Top text is in all caps with
black bold text, while the lower text is smaller and colored by the team name.
gt_merge_stack_team_color( gt_object, col1, col2, team_col, league, font_size_top = 14, font_size_bottom = 12, color = "black", background = NULL, season = NULL, id_system = "auto" )gt_merge_stack_team_color( gt_object, col1, col2, team_col, league, font_size_top = 14, font_size_bottom = 12, color = "black", background = NULL, season = NULL, id_system = "auto" )
gt_object |
An existing gt table object of class |
col1 |
The column to stack on top. Will be all caps, black bold text. |
col2 |
The column to merge and place below. Will be smaller and colored. |
team_col |
The column of team names for the color of the bottom text. |
league |
A league key from |
font_size_top |
Font size for the top text. |
font_size_bottom |
Font size for the bottom text. |
color |
The color for the top text. |
background |
The cell background the lower text is checked against.
|
season |
|
id_system |
|
The lower text takes the team's primary color when it clears a 4.5:1 contrast ratio (WCAG AA) against the cell background, else the secondary color, else the primary darkened (or lightened, on a dark background) until it does, so a light primary such as Missouri's gold stays readable on a white table and keeps its gold on a dark one.
An object of class gt_tbl.
library(gt) library(sdvplotR) df <- data.frame( team = c("KC", "BUF", "SF"), mascot = c("Chiefs", "Bills", "49ers"), wins = c(11, 10, 12) ) df |> gt() |> gt_merge_stack_team_color(team, mascot, team, league = "nfl")library(gt) library(sdvplotR) df <- data.frame( team = c("KC", "BUF", "SF"), mascot = c("Chiefs", "Bills", "49ers"), wins = c(11, 10, 12) ) df |> gt() |> gt_merge_stack_team_color(team, mascot, team, league = "nfl")
gt tableMarks cells that fall outside a threshold, either beyond an interquartile fence, beyond a number of standard deviations, or outside bounds you supply.
gt_outliers( gt_object, columns, method = c("iqr", "sd", "bounds"), threshold = NULL, bounds = NULL, side = c("both", "high", "low"), fill = NULL, color = NULL, bold = TRUE, symbol = NULL, note = NULL )gt_outliers( gt_object, columns, method = c("iqr", "sd", "bounds"), threshold = NULL, bounds = NULL, side = c("both", "high", "low"), fill = NULL, color = NULL, bold = TRUE, symbol = NULL, note = NULL )
gt_object |
A |
columns |
The column or columns to test. Non-numeric columns are skipped. |
method |
Character. How to decide what counts as an outlier. One of
|
threshold |
Numeric. The cutoff used by |
bounds |
A length-2 numeric vector giving |
side |
Character. Which tail to flag. One of |
fill |
Optional. A hex color for the cell fill behind flagged values.
Defaults to |
color |
Optional. A hex color for flagged text. If |
bold |
Logical. Should flagged values be bolded? Defaults to |
symbol |
Optional. A marker appended to flagged values, such as |
note |
Optional. A source note describing the rule that was applied. Pass
|
gt::data_color() shades a continuous scale; this flags a value as unusual.
Thresholds are computed separately for each column, so every column is judged
against its own distribution.
The default rule is the interquartile fence, not standard deviations, because
an SD fence is built from a spread that the outlier itself inflates. On
c(10.2, 10.4, 10.1, 19.8, 10.3, 10.0) the mean is 11.8 and the standard
deviation 3.92, so a three-SD fence reaches 23.6 and misses the 19.8. The
quartiles barely move, so the IQR fence stops at 10.75 and catches it. The
masking is worst in small samples. Use method = "sd" if you want it anyway.
Returns a modified gt table with outlying values marked.
gt_highlight_na() for missing values, and gt_spotlight() for
drawing attention to whole rows.
library(gt) nba <- subset( sdv_example_standings, league == "nba", c(team_name, points_for, points_against) ) # the default fence (1.5 times the IQR) catches the league's lowest scorer gt(nba) |> gt_outliers(c(points_for, points_against), note = TRUE) # an explicit acceptance range, flagging only the high side gt(nba) |> gt_outliers(c(points_for, points_against), method = "bounds", bounds = c(NA, 9800), side = "high", fill = "#FDECEA", symbol = "†" ) # works on wider data too nfl <- subset( sdv_example_standings, league == "nfl", c(team_name, wins, points_for, points_against) ) gt(nfl) |> gt_outliers(c(wins, points_for, points_against))library(gt) nba <- subset( sdv_example_standings, league == "nba", c(team_name, points_for, points_against) ) # the default fence (1.5 times the IQR) catches the league's lowest scorer gt(nba) |> gt_outliers(c(points_for, points_against), note = TRUE) # an explicit acceptance range, flagging only the high side gt(nba) |> gt_outliers(c(points_for, points_against), method = "bounds", bounds = c(NA, 9800), side = "high", fill = "#FDECEA", symbol = "†" ) # works on wider data too nfl <- subset( sdv_example_standings, league == "nfl", c(team_name, wins, points_for, points_against) ) gt(nfl) |> gt_outliers(c(wins, points_for, points_against))
gt tableDraws a percentile as a filled track with a circular marker at the tip of the fill, the value printed inside it. The bar, the marker, and the number are all CSS, so the whole thing stays vector at any export scale.
gt_percentile_bar( gt_object, columns, rows = NULL, domain = c(0, 100), scale = "auto", palette = c("#3661AD", "#C9C9C9", "#D22D49"), reverse = FALSE, pal_type = "discrete", track_color = "#E9E9E9", track_height = 6, marker_size = 22, text_color = "#FFFFFF", font_size = NULL, ring_color = NULL, ring_width = 2, full_track = TRUE, na_label = "—", na_track_color = NULL, na_text_color = "#9A9A9A", decimals = 0, width = 220 )gt_percentile_bar( gt_object, columns, rows = NULL, domain = c(0, 100), scale = "auto", palette = c("#3661AD", "#C9C9C9", "#D22D49"), reverse = FALSE, pal_type = "discrete", track_color = "#E9E9E9", track_height = 6, marker_size = 22, text_color = "#FFFFFF", font_size = NULL, ring_color = NULL, ring_width = 2, full_track = TRUE, na_label = "—", na_track_color = NULL, na_text_color = "#9A9A9A", decimals = 0, width = 220 )
gt_object |
A |
columns |
The columns holding percentiles. |
rows |
The rows to draw bars in. Either an expression evaluated against
the table's data, such as |
domain |
A length-2 numeric vector giving the percentile range. Defaults
to |
scale |
How to handle a column stored as 0-1 proportions rather than
0-100 percentiles. |
palette |
Colors mapped across |
reverse |
Logical. Should the palette be reversed? Defaults to |
pal_type |
Character. Which |
track_color |
Character. The color of the unfilled track. Defaults to
|
track_height |
Numeric. The track thickness in pixels. Defaults to |
marker_size |
Numeric. The marker diameter in pixels. Defaults to |
text_color |
Character. The color of the number inside the marker.
Defaults to |
font_size |
Numeric. The size of the number in pixels. If |
ring_color |
Character. A ring drawn around the marker, which separates it
from the fill. |
ring_width |
Numeric. The ring thickness in pixels. Defaults to |
full_track |
Logical. Should the track run the full width, or stop at the
marker? Defaults to |
na_label |
Character. What to show for a missing percentile, such as
|
na_track_color |
Character. The track color for missing rows. If |
na_text_color |
Character. The color of |
decimals |
Integer. Decimal places on the number. Defaults to |
width |
Numeric. The column width in pixels. Defaults to |
gtExtras::gt_plt_percentile() covers percentiles as a ggplot dot plot
rendered to a raster image. This is the filled-bar-and-marker treatment
instead.
The track is inset by half the marker so that a value at either extreme keeps the marker inside the cell rather than hanging over the edge. The fill and the marker take the same color, mapped from the value.
Returns a modified gt table with percentile bars.
library(gt) metrics <- data.frame( metric = c("Barrel %", "Exit velocity", "Chase rate", "Whiff %"), pct = c(94, 41, 72, 18) ) gt(metrics) |> gt_percentile_bar(pct) # the same values stored 0-1 render identically under the default scale = "auto" metrics$pct <- metrics$pct / 100 gt(metrics) |> gt_percentile_bar(pct) # a row that did not qualify metrics$pct[2] <- NA gt(metrics) |> gt_percentile_bar(pct, na_label = "Not qualified")library(gt) metrics <- data.frame( metric = c("Barrel %", "Exit velocity", "Chase rate", "Whiff %"), pct = c(94, 41, 72, 18) ) gt(metrics) |> gt_percentile_bar(pct) # the same values stored 0-1 render identically under the default scale = "auto" metrics$pct <- metrics$pct / 100 gt(metrics) |> gt_percentile_bar(pct) # a row that did not qualify metrics$pct[2] <- NA gt(metrics) |> gt_percentile_bar(pct, na_label = "Not qualified")
Draws a short color bar down the left edge of every row, keyed to a column in the data such as a team, category, or brand color. It serves as a per-row key without taking up a column.
gt_row_accent( gt_object, column, palette = NULL, rows = NULL, width = 4, side = c("left", "right"), hide = TRUE, na_color = "transparent" )gt_row_accent( gt_object, column, palette = NULL, rows = NULL, width = 4, side = c("left", "right"), hide = TRUE, na_color = "transparent" )
gt_object |
A |
column |
The column the color is keyed to. Either a column already
holding colors, or a grouping column used together with |
palette |
Optional. Colors to map |
rows |
The rows to accent. Either an expression evaluated against the
table's data, such as |
width |
Numeric. The bar width in pixels. Defaults to |
side |
Character. Which edge the bar sits on, |
hide |
Logical. Should |
na_color |
Character. The color for rows where the key is missing.
Defaults to |
It draws the same bar gt_spotlight() uses for emphasis, applied per row here.
gtExtras::gt_highlight_rows() fills the whole row instead.
The bar is drawn as a cell border on the leftmost rendered column, or on the stub when the table has one, so it lines up with the row rather than sitting inside a column of its own.
Rows sharing a color are styled together rather than one at a time, so a long table with a handful of categories stays cheap.
Returns a modified gt table with a color bar on each row.
gt_spotlight() for emphasis rather than a key.
library(gt) teams <- data.frame( team = c("Duke", "Kansas", "Auburn", "Houston"), conf = c("ACC", "B12", "SEC", "B12"), net = c(10, 20, 5, 1) ) # keyed to a grouping column gt(teams) |> gt_row_accent(conf, palette = c( ACC = "#003366", B12 = "#C8102E", SEC = "#B8232F" )) # or straight from a column of colors teams$color <- c("#003366", "#C8102E", "#B8232F", "#C8102E") gt(teams) |> gt_row_accent(color) # only some rows: by expression, by indices, or by one row number gt(teams) |> gt_row_accent(color, rows = net <= 10) gt(teams) |> gt_row_accent(color, rows = c(1, 3)) gt(teams) |> gt_row_accent(color, rows = 2)library(gt) teams <- data.frame( team = c("Duke", "Kansas", "Auburn", "Houston"), conf = c("ACC", "B12", "SEC", "B12"), net = c(10, 20, 5, 1) ) # keyed to a grouping column gt(teams) |> gt_row_accent(conf, palette = c( ACC = "#003366", B12 = "#C8102E", SEC = "#B8232F" )) # or straight from a column of colors teams$color <- c("#003366", "#C8102E", "#B8232F", "#C8102E") gt(teams) |> gt_row_accent(color) # only some rows: by expression, by indices, or by one row number gt(teams) |> gt_row_accent(color, rows = net <= 10) gt(teams) |> gt_row_accent(color, rows = c(1, 3)) gt(teams) |> gt_row_accent(color, rows = 2)
Splits data by a column, builds a table for each group with a function you supply, and writes one image per group. The images are padded to a common width so a posted series does not come out at ragged sizes.
gt_save_batch( data, group, fn, file, dir, match_width = TRUE, bg = "white", whitespace = 50, zoom = 2, quiet = FALSE )gt_save_batch( data, group, fn, file, dir, match_width = TRUE, bg = "white", whitespace = 50, zoom = 2, quiet = FALSE )
data |
A data frame to split. |
group |
The column to split on. |
fn |
A function building one table. It is called as |
file |
Character. A file name pattern containing |
dir |
Character. The directory to write into. Created if it does not
exist. There is no default, so a batch never lands in the working
directory unasked; pass |
match_width |
Logical. Should every image be padded to the width of the
widest one, so a posted series shares one width? Defaults to |
bg |
Character. The background color of the padding. Defaults to
|
whitespace |
Numeric. Padding left around each table, in pixels. Defaults
to |
zoom |
Numeric. The rendering zoom factor. Defaults to |
quiet |
Logical. Suppress the per-group progress message. Defaults to
|
A group whose table fails to build does not abandon the run. The error is collected, the remaining groups are written, and a warning at the end names every group that failed.
Group values are used in file names with anything awkward replaced by a dash,
so a group called "North / East" writes to north-east.
Without match_width, each image is trimmed to its own content, so a set
posted together can come out at different widths. With it, every image is
padded to the width of the widest before its border is added.
Invisibly, a character vector of the files written.
gt_grid() for the same split composed into one image instead.
library(gt) build <- function(df, group) { gt(df[c("team_name", "wins", "losses", "points_for")]) |> gt_theme_broadsheet() |> tab_header(title = group) } nfl <- subset(sdv_example_standings, league == "nfl") gt_save_batch(nfl, conference, build, "nfl-{group}.png", dir = tempdir())library(gt) build <- function(df, group) { gt(df[c("team_name", "wins", "losses", "points_for")]) |> gt_theme_broadsheet() |> tab_header(title = group) } nfl <- subset(sdv_example_standings, league == "nfl") gt_save_batch(nfl, conference, build, "nfl-{group}.png", dir = tempdir())
gt table to an image and trim its whitespaceRenders a table to a PNG, JPG, or JPEG, trims the whitespace the screenshot leaves
around it, and pads a uniform border back on. Saving runs through
headless Chrome (webshot2) and the trimming and padding through magick.
gt_save_crop( data, file = NULL, bg = "white", whitespace = 50, zoom = 2, expand = 5, width = NULL )gt_save_crop( data, file = NULL, bg = "white", whitespace = 50, zoom = 2, expand = 5, width = NULL )
data |
A |
file |
Character. A path ending in |
bg |
Character. The background color of the padded border. Defaults to
|
whitespace |
Numeric. The border, in pixels, left around the trimmed
table. Defaults to |
zoom |
Numeric. The rendering zoom factor passed to the underlying save.
A higher value gives a sharper image. Defaults to |
expand |
Numeric. The pixel expansion passed to the underlying save.
Defaults to |
width |
Optional. A final output width in pixels. The image is scaled to
it, height following, so a series of tables can share one width. Defaults to
|
The table is first written to a temporary file at zoom and expand, then
read back with magick, trimmed to its content, and given a whitespace
border in bg. When width is set the finished image is resized to that
width with the height following, so several tables saved at the same width
line up when posted together. The temporary file is removed afterward.
Invisibly, file after writing the cropped image to it, or the
encoded image as a raw vector when file is NULL.
gt_social_crop() for padding onto a fixed-ratio canvas.
library(gt) afc_east <- subset( sdv_example_standings, division == "AFC East", c(team_name, wins:points_against) ) gt(afc_east) |> gt_theme_broadsheet() |> gt_save_crop(tempfile(fileext = ".png")) # pin a shared width across a series atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses, win_pct:points_against) ) gt(atlantic) |> gt_save_crop(tempfile(fileext = ".png"), width = 900, bg = "#FBFAF7")library(gt) afc_east <- subset( sdv_example_standings, division == "AFC East", c(team_name, wins:points_against) ) gt(afc_east) |> gt_theme_broadsheet() |> gt_save_crop(tempfile(fileext = ".png")) # pin a shared width across a series atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses, win_pct:points_against) ) gt(atlantic) |> gt_save_crop(tempfile(fileext = ".png"), width = 900, bg = "#FBFAF7")
Divides the selected columns and records the scaling in the same call, so the numbers and the disclosure cannot drift apart.
gt_scale_note( gt_object, columns, divisor = 1000, note = NULL, where = c("source_note", "label", "both"), label_suffix = NULL, decimals = 0, ... )gt_scale_note( gt_object, columns, divisor = 1000, note = NULL, where = c("source_note", "label", "both"), label_suffix = NULL, decimals = 0, ... )
gt_object |
A |
columns |
The column or columns to scale. |
divisor |
Numeric. The amount to divide by. Defaults to |
note |
Optional. The disclosure text. If |
where |
Character. Where the disclosure goes. One of |
label_suffix |
Optional. The suffix appended to column labels when |
decimals |
Integer. The number of decimal places for the scaled values.
Defaults to |
... |
Additional arguments passed to |
Scaling is applied through gt::fmt_number() and its scale_by argument, so
the underlying data is left untouched.
Returns a modified gt table with the columns scaled and the scaling
disclosed.
library(gt) # an NBA season's points, scored and allowed atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, points_for, points_against) ) # Boston's 9,418 points render as 9.4, with "Figures in thousands." beneath gt(atlantic) |> gt_scale_note(c(points_for, points_against), divisor = 1e3, decimals = 1) # disclose in the column labels instead gt(atlantic) |> gt_scale_note(c(points_for, points_against), divisor = 1e3, decimals = 2, where = "label" )library(gt) # an NBA season's points, scored and allowed atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, points_for, points_against) ) # Boston's 9,418 points render as 9.4, with "Figures in thousands." beneath gt(atlantic) |> gt_scale_note(c(points_for, points_against), divisor = 1e3, decimals = 1) # disclose in the column labels instead gt(atlantic) |> gt_scale_note(c(points_for, points_against), divisor = 1e3, decimals = 2, where = "label" )
Translate team abbreviations into logos and render these images in column labels of 'gt' tables.
gt_sdv_cols_label( gt_object, columns = gt::everything(), league, height = 30, mark_type = c("logo", "wordmark", "headshot"), id_system = "auto", season = NULL, strict = FALSE )gt_sdv_cols_label( gt_object, columns = gt::everything(), league, height = 30, mark_type = c("logo", "wordmark", "headshot"), id_system = "auto", season = NULL, strict = FALSE )
gt_object |
A table object created using |
columns |
The columns whose labels should be replaced with logos. |
league |
A league key from |
height |
The absolute height (px) of the image. |
mark_type |
One of |
id_system |
How the column names are read. |
season, strict
|
For logo and wordmark labels only (headshots take
neither): the season whose mark to show, and whether an unresolved label
is an error. With |
An object of class gt_tbl.
gt_sdv_logos(), gt_sdv_wordmarks(), gt_sdv_headshots()
library(gt) library(sdvplotR) df <- data.frame( KC = 1:3, BUF = 4:6, SF = 7:9 ) df |> gt() |> gt_sdv_cols_label(columns = c("KC", "BUF", "SF"), league = "nfl")library(gt) library(sdvplotR) df <- data.frame( KC = 1:3, BUF = 4:6, SF = 7:9 ) df |> gt() |> gt_sdv_cols_label(columns = c("KC", "BUF", "SF"), league = "nfl")
Translate player IDs to player headshots and render these
images in html tables with the 'gt' package. IDs are ESPN athlete IDs in
every league, or as id_system says. IDs that resolve to no headshot
are left as text.
gt_sdv_headshots( gt_object, columns, league, height = 30, locations = NULL, id_system = "espn" )gt_sdv_headshots( gt_object, columns, league, height = 30, locations = NULL, id_system = "espn" )
gt_object |
A table object created using |
columns |
The columns for which the image translation should be applied.
Argument has no effect if |
league |
A league key from |
height |
The absolute height (px) of the image in the table cell. |
locations |
If |
id_system |
|
An object of class gt_tbl.
gt_sdv_logos(), gt_sdv_wordmarks(), gt_sdv_cols_label()
library(gt) library(sdvplotR) df <- data.frame( player_id = c("00-0033873", "00-0026498", "00-0035228"), player_name = c("P.Mahomes", "M.Stafford", "K.Murray") ) df |> gt() |> gt_sdv_headshots(columns = "player_id", league = "nfl", id_system = "gsis")library(gt) library(sdvplotR) df <- data.frame( player_id = c("00-0033873", "00-0026498", "00-0035228"), player_name = c("P.Mahomes", "M.Stafford", "K.Murray") ) df |> gt() |> gt_sdv_headshots(columns = "player_id", league = "nfl", id_system = "gsis")
Translate team abbreviations into logos and render these images in html tables with the 'gt' package.
gt_sdv_logos( gt_object, columns, league, height = 30, locations = NULL, include_name = FALSE, season = NULL, id_system = "auto", strict = FALSE )gt_sdv_logos( gt_object, columns, league, height = 30, locations = NULL, include_name = FALSE, season = NULL, id_system = "auto", strict = FALSE )
gt_object |
A table object created using |
columns |
The columns for which the image translation should be applied.
Argument has no effect if |
league |
A league key from |
height |
The absolute height (px) of the image in the table cell. |
locations |
If |
include_name |
If |
season |
|
id_system, strict
|
How the team values are read and what an unresolved
one does, as in |
An object of class gt_tbl.
Given a season, a team is drawn with the mark it wore that season where
the SportsDataverse logo archive dates its marks, and with its current
mark otherwise. The season also picks the team a reused code meant then
(see sdv_resolve()). The images are copies kept in the archive, so they
don't change when a league reuses a file name. SVG marks are read with the
'rsvg' package. season takes single years: the ending year for split
seasons (2005 for 2004-05).
gt_sdv_wordmarks(), gt_sdv_headshots(), gt_sdv_cols_label()
library(gt) library(sdvplotR) teams <- sdv_teams("nfl")$abbr[1:8] df <- data.frame( team = teams, logo = teams, wins = sample(1:16, 8) ) df |> gt() |> gt_sdv_logos(columns = "logo", league = "nfl") # logo and name in one cell; NCAA.com school names resolve too data.frame(team = c("Iowa St.", "St. John's (NY)"), net = c(8, 12)) |> gt() |> gt_sdv_logos(columns = "team", league = "mbb", height = 20, include_name = TRUE) # the marks of the 1994-95 season data.frame(team = c("QUE", "HFD", "WIN"), pts = c(65, 43, 39)) |> gt() |> gt_sdv_logos(columns = "team", league = "nhl", season = 1995)library(gt) library(sdvplotR) teams <- sdv_teams("nfl")$abbr[1:8] df <- data.frame( team = teams, logo = teams, wins = sample(1:16, 8) ) df |> gt() |> gt_sdv_logos(columns = "logo", league = "nfl") # logo and name in one cell; NCAA.com school names resolve too data.frame(team = c("Iowa St.", "St. John's (NY)"), net = c(8, 12)) |> gt() |> gt_sdv_logos(columns = "team", league = "mbb", height = 20, include_name = TRUE) # the marks of the 1994-95 season data.frame(team = c("QUE", "HFD", "WIN"), pts = c(65, 43, 39)) |> gt() |> gt_sdv_logos(columns = "team", league = "nhl", season = 1995)
Translate team abbreviations into wordmarks and render these images in html tables with the 'gt' package.
gt_sdv_wordmarks( gt_object, columns, league, height = 30, locations = NULL, season = NULL, id_system = "auto", strict = FALSE )gt_sdv_wordmarks( gt_object, columns, league, height = 30, locations = NULL, season = NULL, id_system = "auto", strict = FALSE )
gt_object |
A table object created using |
columns |
The columns for which the image translation should be applied.
Argument has no effect if |
league |
A league key from |
height |
The absolute height (px) of the image in the table cell. |
locations |
If |
season |
|
id_system, strict
|
How the team values are read and what an unresolved
one does, as in |
An object of class gt_tbl.
gt_sdv_logos(), gt_sdv_headshots(), gt_sdv_cols_label()
library(gt) df <- data.frame(team = c("KC", "BUF", "SF"), wins = c(14, 13, 12)) df |> gt() |> gt_sdv_wordmarks(columns = "team", league = "nfl")library(gt) df <- data.frame(team = c("KC", "BUF", "SF"), wins = c(14, 13, 12)) df |> gt() |> gt_sdv_wordmarks(columns = "team", league = "nfl")
gt tableApplies a single font family to every styleable part of a gt table in one
call: the title and subtitle, the stubhead, column spanners and labels, row
groups, the stub, the body, footnotes, and source notes. Setting the same font
through gt::tab_options() means naming each *_font option in turn.
gt_set_font( gt_object, font_family, from_google_font = TRUE, weight = NULL, style = NULL )gt_set_font( gt_object, font_family, from_google_font = TRUE, weight = NULL, style = NULL )
gt_object |
A |
font_family |
Character. The font family to apply to the whole table. |
from_google_font |
Logical. Should the font be pulled from Google Fonts
through |
weight |
The font weight applied to every part, passed to
|
style |
Character. The font style applied to every part, one of
|
The font is applied with a single gt::tab_style() over a list of cell
locations covering each part of the table. Summary and grand-summary cells are
not included, so a font set here does not reach them. When from_google_font
is TRUE the family is wrapped in gt::google_font(), which adds the import
so the font renders in an exported table without relying on it being installed
locally.
Returns a modified gt table with the font family applied to every
covered part.
library(gt) nfc_south <- subset( sdv_example_standings, division == "NFC South", c(team_name, wins:points_against) ) gt(nfc_south) |> gt_set_font("Oswald") # use a font already installed locally gt(nfc_south) |> gt_set_font("Helvetica", from_google_font = FALSE)library(gt) nfc_south <- subset( sdv_example_standings, division == "NFC South", c(team_name, wins:points_against) ) gt(nfc_south) |> gt_set_font("Oswald") # use a font already installed locally gt(nfc_south) |> gt_set_font("Helvetica", from_google_font = FALSE)
gt tableAppends significance notation to an estimate column based on a column of p-values, then writes the matching legend into a source note. The p-value column is hidden by default, since the stars stand in for it. This is the usual convention for regression tables in the social and medical sciences.
gt_significance( gt_object, columns, p_columns, levels = c(0.01, 0.05, 0.1), symbols = c("***", "**", "*"), superscript = TRUE, size = "0.7em", legend = TRUE, legend_text = NULL, hide_p = TRUE )gt_significance( gt_object, columns, p_columns, levels = c(0.01, 0.05, 0.1), symbols = c("***", "**", "*"), superscript = TRUE, size = "0.7em", legend = TRUE, legend_text = NULL, hide_p = TRUE )
gt_object |
A |
columns |
The estimate column or columns to annotate. |
p_columns |
The column or columns holding the p-values, paired
positionally with |
levels |
A numeric vector of significance thresholds, in ascending order
(strictest first). Defaults to |
symbols |
A character vector of notation for each level. Must be the same
length as |
superscript |
Logical. Should the stars be rendered as superscript?
Defaults to |
size |
Character. The size of the stars, as a CSS size. Defaults to |
legend |
Logical. Should the legend be added as a source note? Defaults
to |
legend_text |
Optional. Custom legend text. If |
hide_p |
Logical. Should the p-value columns be hidden once the stars are
applied? Defaults to |
The legend is generated from the same levels and symbols used to place the
stars, so changing one updates the other.
Each value takes the notation for the strictest threshold it satisfies, so with
the defaults a p-value of 0.004 gets *** and not *. Values that meet none
of the thresholds are left alone, as are NA p-values.
Returns a modified gt table with significance notation applied.
gt_fmt_rank(), which uses the same superscript approach for
ordinal suffixes.
library(gt) # what a season's points scored and allowed say about its win percentage nfl <- subset(sdv_example_standings, league == "nfl") fit <- lm(win_pct ~ points_for + points_against + conference, data = nfl) results <- data.frame( Term = rownames(summary(fit)$coefficients), Estimate = summary(fit)$coefficients[, 1], SE = summary(fit)$coefficients[, 2], p = summary(fit)$coefficients[, 4] ) gt(results) |> fmt_number(c(Estimate, SE), decimals = 4) |> gt_significance(Estimate, p) # daggers instead of stars, at a single threshold gt(results) |> gt_significance(Estimate, p, levels = 0.05, symbols = "†", legend_text = "† p < .05" )library(gt) # what a season's points scored and allowed say about its win percentage nfl <- subset(sdv_example_standings, league == "nfl") fit <- lm(win_pct ~ points_for + points_against + conference, data = nfl) results <- data.frame( Term = rownames(summary(fit)$coefficients), Estimate = summary(fit)$coefficients[, 1], SE = summary(fit)$coefficients[, 2], p = summary(fit)$coefficients[, 4] ) gt(results) |> fmt_number(c(Estimate, SE), decimals = 4) |> gt_significance(Estimate, p) # daggers instead of stars, at a single threshold gt(results) |> gt_significance(Estimate, p, levels = 0.05, symbols = "†", legend_text = "† p < .05" )
Breaks a long table into two or more blocks set beside each other, each with its own column labels. A sixty-row ranking becomes two columns of thirty, which is the usual treatment in print and the difference between an image that is unreadably tall and one that fits the frame.
gt_snake( gt_object, n_cols = 2, rows_per_col = NULL, gap = 20, fill = "", clean_gaps = TRUE )gt_snake( gt_object, n_cols = 2, rows_per_col = NULL, gap = 20, fill = "", clean_gaps = TRUE )
gt_object |
A |
n_cols |
Integer. The number of blocks to lay out. Defaults to |
rows_per_col |
Integer. Rows in each block. Given this, |
gap |
Numeric. The space between blocks in pixels, added as an empty
spacer column so it does not disturb the alignment of the columns either
side of it. Its borders, fill, and rules are scrubbed so it stays clean
whitespace under any theme (see Details). |
fill |
Character. What to show in the trailing cells when the rows do not
divide evenly. Defaults to |
clean_gaps |
Logical. Should the spacer columns be scrubbed of borders,
fill, and rules so the gap reads as clean whitespace (see Details)? Set
|
The table is rebuilt from its data. Body-cell styles set beforehand, with
gt_highlight_cells() or tab_style() on cells_body(), are carried through:
each is moved to its block's suffixed column and its row within that block, so
a fill on the long table lands on the same cell once snaked. This means you can
color the natural, un-snaked grid and snake afterwards.
Formatting and content transforms are not styles and are not remapped, so
fmt_*(), text_transform(), and gtExtras::gt_img_rows() still have to be
applied after the snake, against the suffixed names above. Themes go afterwards
too. Any heading and source notes already set are carried over.
To reshape a parallel frame (a precomputed mask, per-cell colors) to match the
same blocks, see gt_snake_align().
gt::gt_split() also divides a table, but it returns a group of separate
tables to be rendered one after another, and it errors on any table carrying
body-cell styles, which every theme in this package sets.
Returns a gt table laid out in blocks.
Snaking is a reshape. The same columns appear once per block, so they cannot all keep the same name: each is suffixed with its block number. A four-column table split into two blocks becomes eight columns.
before after gt_snake(n_cols = 2)
----------------------- -----------------------------------------
team wins losses win_pct team_1 wins_1 losses_1 win_pct_1 <- rows 1-15
team_2 wins_2 losses_2 win_pct_2 <- rows 16-30
The labels are untouched, so the table still reads
team wins losses win_pct twice over. Only the names you address in code
change.
That gives three ways to target columns afterwards:
# every block of one column, via a tidyselect helper
fmt_number(starts_with("win_pct"), decimals = 3)
# one block only, by its full name
tab_style(cell_text(weight = "bold"), cells_body(columns = team_2))
# the whole table, exactly as usual
cols_align(columns = everything(), align = "center")
Reach for starts_with() rather than listing team_1, team_2 by hand: it keeps
working if you change n_cols later. Watch out for prefixes that overlap,
though. With columns named pts and pts_pg, starts_with("pts") catches
both blocks of both; matches("^pts_[0-9]+$") catches only pts.
The gap between blocks is itself an empty column, named .gap1, .gap2,
and so on. It holds nothing and carries no label. To target the spacers in a
later call, use starts_with(".gap") or matches("^\\.gap"); everything()
selects them too. Set gap = 0 if you would rather it did not exist.
Because the gap is a real column, a theme or gt_border_grid() would
otherwise draw its column borders and row rules straight through it, leaving
the "whitespace" boxed in. When clean_gaps = TRUE (the default), the body of
each spacer and the inner edges of the columns either side are cleared with
scoped !important CSS, so it wins even against borders applied after the
snake; the spacer's own column label is cleared through gt directly, which
holds up even when tab_spanner() merges header cells. The table's id is
set (or carried over from the input) so the CSS can be scoped to it. Set
clean_gaps = FALSE to style the gap yourself instead.
gt_stack_tables() for stacking separate tables vertically.
library(gt) nba <- subset( sdv_example_standings, league == "nba", c(team, wins, losses, win_pct) ) nba <- nba[order(-nba$win_pct), ] # three blocks of ten gt(nba) |> gt_snake(n_cols = 3) |> gt_theme_broadsheet() # or set the block length and let the count follow gt(nba) |> gt_snake(rows_per_col = 8, gap = 30) |> gt_theme_swiss() # formatting after the reshape: note the suffixed names gt(nba) |> gt_snake(n_cols = 3) |> gt_theme_swiss() |> fmt_number(starts_with("win_pct"), decimals = 3) |> cols_align(columns = everything(), align = "center") # and picking out a single block gt(nba) |> gt_snake(n_cols = 3) |> gt_theme_swiss() |> tab_style( gt::cell_text(weight = "bold"), gt::cells_body(columns = team_1) )library(gt) nba <- subset( sdv_example_standings, league == "nba", c(team, wins, losses, win_pct) ) nba <- nba[order(-nba$win_pct), ] # three blocks of ten gt(nba) |> gt_snake(n_cols = 3) |> gt_theme_broadsheet() # or set the block length and let the count follow gt(nba) |> gt_snake(rows_per_col = 8, gap = 30) |> gt_theme_swiss() # formatting after the reshape: note the suffixed names gt(nba) |> gt_snake(n_cols = 3) |> gt_theme_swiss() |> fmt_number(starts_with("win_pct"), decimals = 3) |> cols_align(columns = everything(), align = "center") # and picking out a single block gt(nba) |> gt_snake(n_cols = 3) |> gt_theme_swiss() |> tab_style( gt::cell_text(weight = "bold"), gt::cells_body(columns = team_1) )
Lays a data frame out in side-by-side blocks the same way gt_snake() lays
out the table, so a frame you computed against the long data still lines up
after the snake. It is the escape hatch for a precomputed grid you do not want
to rebuild as a condition: a logical mask for gt_highlight_cells(), a frame
of per-cell colors or text, anything the same shape as the snaked body.
gt_snake_align(x, n_cols = 2, rows_per_col = NULL, fill = NA)gt_snake_align(x, n_cols = 2, rows_per_col = NULL, fill = NA)
x |
A data frame or matrix with one row per row of the un-snaked table. |
n_cols |
Integer. The number of blocks, matching the |
rows_per_col |
Integer. Rows in each block. Given this, |
fill |
What to put in the trailing cells when the rows do not divide
evenly. Defaults to |
Most of the time you do not need this. Body-cell styling applied before
gt_snake() is carried through the reshape on its own, so coloring the long
grid and then snaking already lands the fills in the right place. Reach for
this only when the grid lives outside the table's styles.
Pass the same n_cols (or rows_per_col) you passed to gt_snake(). Each
block's columns are suffixed with its block number, _1, _2, and so on, to
match the names gt_snake() gives the table. The result has
ceiling(nrow(x) / n_cols) rows and ncol(x) * n_cols columns, so it is the
shape gt_highlight_cells() expects for the block of snaked columns.
Returns a data frame of the reshaped blocks.
gt_snake(), which reshapes the table itself and carries body
styling through.
library(gt) nfc <- subset( sdv_example_standings, conference == "NFC", c(team, wins, losses) ) # a logical grid the same shape as the data, built before the snake: # double-digit wins or losses mask <- data.frame(team = FALSE, nfc[c("wins", "losses")] >= 10) # after the snake, each column carries its block number as a suffix snaked <- unlist(lapply(1:2, function(i) paste0(names(nfc), "_", i))) nfc |> gt() |> gt_snake(n_cols = 2) |> gt_highlight_cells(tidyselect::all_of(snaked), condition = gt_snake_align(mask, n_cols = 2), fill = "#EDBD68" )library(gt) nfc <- subset( sdv_example_standings, conference == "NFC", c(team, wins, losses) ) # a logical grid the same shape as the data, built before the snake: # double-digit wins or losses mask <- data.frame(team = FALSE, nfc[c("wins", "losses")] >= 10) # after the snake, each column carries its block number as a suffix snaked <- unlist(lapply(1:2, function(i) paste0(names(nfc), "_", i))) nfc |> gt() |> gt_snake(n_cols = 2) |> gt_highlight_cells(tidyselect::all_of(snaked), condition = gt_snake_align(mask, n_cols = 2), fill = "#EDBD68" )
gt table onto a fixed-ratio canvasA variant of gt_save_crop() that centers the trimmed table on a canvas of a
given aspect ratio, for posting to social platforms. The table itself is never
cropped; the short side of the canvas is expanded until the ratio is met.
gt_social_crop( data, file = NULL, aspect_ratio = "1:1", bg = "white", whitespace = 60, gravity = "center", zoom = 2, expand = 5, width = NULL )gt_social_crop( data, file = NULL, aspect_ratio = "1:1", bg = "white", whitespace = 60, gravity = "center", zoom = 2, expand = 5, width = NULL )
data |
A |
file |
Optional. A path to write the image to. Defaults to |
aspect_ratio |
Character or numeric. The target ratio, given as |
bg |
Character. The background color of the canvas. Defaults to |
whitespace |
Numeric. The amount of whitespace to leave around the table
before padding out to the ratio. Defaults to |
gravity |
Character. Where the table sits on the canvas, passed to
|
zoom |
Numeric. The rendering zoom factor. Defaults to |
expand |
Numeric. The pixel expansion passed to the underlying save.
Defaults to |
width |
Optional. A final output width in pixels. The finished canvas is
scaled to it, keeping the aspect ratio, so a series of posts can share one
width. Defaults to |
Invisibly, file after writing the cropped and padded image to it,
or the encoded image as a raw vector when file is NULL.
gt_save_crop() for a plain trimmed save.
library(gt) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins:points_against) ) gt(nfc_west) |> gt_theme_broadsheet(density = "social") |> gt_social_crop(tempfile(fileext = ".png"), aspect_ratio = "4:5") # match the canvas to a dark theme gt(nfc_west) |> gt_theme_midnight() |> gt_social_crop(tempfile(fileext = ".png"), bg = "#0C0D10")library(gt) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins:points_against) ) gt(nfc_west) |> gt_theme_broadsheet(density = "social") |> gt_social_crop(tempfile(fileext = ".png"), aspect_ratio = "4:5") # match the canvas to a dark theme gt(nfc_west) |> gt_theme_midnight() |> gt_social_crop(tempfile(fileext = ".png"), bg = "#0C0D10")
gt tableRenders a set of accounts, each an icon plus a handle, into the table's source
note, styled like the bottom line of gt_538_caption(). Icons come from Font
Awesome through the fontawesome package.
gt_social_tag( gt_object, accounts, caption = NULL, stack = FALSE, separator = " | ", align = "right", icon_color = NULL, icon_height = "0.9em", text_size = NULL, text_weight = NULL, ... )gt_social_tag( gt_object, accounts, caption = NULL, stack = FALSE, separator = " | ", align = "right", icon_color = NULL, icon_height = "0.9em", text_size = NULL, text_weight = NULL, ... )
gt_object |
A |
accounts |
A named character vector mapping platform to handle, such as
|
caption |
Optional. A caption rendered as the top footnote line. Defaults
to |
stack |
Logical. Should the accounts be stacked vertically, one per line,
instead of sitting in a row? Defaults to |
separator |
Character. The string placed between accounts when not
stacked. Defaults to |
align |
Character. The alignment of the handle line. One of |
icon_color |
Optional. A hex color for the icons. If |
icon_height |
Character. The height of the icons, as a CSS size. Given in
|
text_size |
Optional. The font size for the handles, as a CSS size. If
|
text_weight |
Optional. The font weight for the handles. If |
... |
Additional arguments passed to |
If a caption is supplied it becomes the top line, a bordered footnote in the
same manner as gt_538_caption(), with the handles beneath it. With no
caption, only the handle line is shown.
If an icon name is not present in your installed version of fontawesome, the
function stops with a message naming the icon and the version, instead of
rendering a broken glyph.
Returns a modified gt table with the handles, and any caption, added.
library(gt) afc_east <- subset( sdv_example_standings, division == "AFC East", c(team_name, wins:points_against) ) gt(afc_east) |> gt_social_tag(c(x = "@yourhandle", gh = "yourname")) # with a caption line above, stacked and left-aligned gt(afc_east) |> gt_social_tag( c(x = "@yourhandle", web = "example.com"), caption = "Data: nflreadr and nflseedR", stack = TRUE, align = "left" )library(gt) afc_east <- subset( sdv_example_standings, division == "AFC East", c(team_name, wins:points_against) ) gt(afc_east) |> gt_social_tag(c(x = "@yourhandle", gh = "yourname")) # with a caption line above, stacked and left-aligned gt(afc_east) |> gt_social_tag( c(x = "@yourhandle", web = "example.com"), caption = "Data: nflreadr and nflseedR", stack = TRUE, align = "left" )
gt table by dimming the restEmphasizes one or more rows and mutes everything else.
gtExtras::gt_highlight_rows() makes a row louder; this leaves it as the only
row at full strength.
gt_spotlight( gt_object, rows, columns = gt::everything(), fill = NULL, text_color = NULL, bold = TRUE, accent_color = NULL, accent_width = 4, accent_column = NULL, dim_color = "auto", if_none = c("warn", "dim", "ignore") )gt_spotlight( gt_object, rows, columns = gt::everything(), fill = NULL, text_color = NULL, bold = TRUE, accent_color = NULL, accent_width = 4, accent_column = NULL, dim_color = "auto", if_none = c("warn", "dim", "ignore") )
gt_object |
A |
rows |
The rows to focus on. Either an expression evaluated against the
table's data, such as |
columns |
The columns the spotlight covers. Cells outside this selection are dimmed, in the focused rows as well as the others, so only the selected cells are left at full strength. Defaults to all of them, which lights the whole row. |
fill |
Optional. A hex color for the fill behind the focused rows.
Defaults to |
text_color |
Optional. A hex color for the text of the focused rows.
Defaults to |
bold |
Logical. Should the focused rows be bolded? Defaults to |
accent_color |
Optional. A color for a bar drawn on the left edge of the
focused rows. Supplying one is what turns the bar on, the same way |
accent_width |
Numeric. The width of that bar in pixels, used only when
|
accent_column |
The column to draw the bar against, on its left edge. If
|
dim_color |
Character. The text color applied to every other row.
|
if_none |
Character. What to do when |
Rows can be given as a filtering expression evaluated against the underlying data, or as plain row numbers.
Returns a modified gt table with the chosen rows emphasized.
gt_cutline() for marking a threshold rather than a row.
library(gt) nfc <- subset( sdv_example_standings, division %in% c("NFC North", "NFC West"), c(team_name, wins, losses, conference_rank) ) # by expression: the playoff seeds gt(nfc) |> gt_spotlight(rows = conference_rank <= 7) # by position, with an accent bar gt(nfc) |> gt_spotlight(rows = 2, accent_color = "#0054AD", fill = "#EEF3FA") # narrowing the spotlight to some columns dims the rest of the row too gt(nfc) |> gt_spotlight(wins:losses, rows = 3, accent_color = "darkblue") # put the bar somewhere other than the first column gt(nfc) |> gt_spotlight(losses, rows = 3, accent_color = "darkblue", accent_column = losses) # across several tables: blocks without a 12-win team dim rather than stay lit chunks <- split(nfc, ceiling(seq_len(nrow(nfc)) / 4)) tbls <- lapply(chunks, function(x) { gt(x) |> gt_spotlight(rows = wins >= 12, if_none = "dim") }) gt_grid(tbls, ncol = 2)library(gt) nfc <- subset( sdv_example_standings, division %in% c("NFC North", "NFC West"), c(team_name, wins, losses, conference_rank) ) # by expression: the playoff seeds gt(nfc) |> gt_spotlight(rows = conference_rank <= 7) # by position, with an accent bar gt(nfc) |> gt_spotlight(rows = 2, accent_color = "#0054AD", fill = "#EEF3FA") # narrowing the spotlight to some columns dims the rest of the row too gt(nfc) |> gt_spotlight(wins:losses, rows = 3, accent_color = "darkblue") # put the bar somewhere other than the first column gt(nfc) |> gt_spotlight(losses, rows = 3, accent_color = "darkblue", accent_column = losses) # across several tables: blocks without a 12-win team dim rather than stay lit chunks <- split(nfc, ceiling(seq_len(nrow(nfc)) / 4)) tbls <- lapply(chunks, function(x) { gt(x) |> gt_spotlight(rows = wins >= 12, if_none = "dim") }) gt_grid(tbls, ncol = 2)
gt tables verticallyPlaces a list of tables one above another in a single block, with an optional
shared heading and footer. Each table keeps its own columns, widths, and
header. gt_snake() folds one table into blocks instead, and gt_grid()
arranges tables side by side.
gt_stack_tables( tables = NULL, gap = 16, align = c("center", "left", "right"), title = NULL, subtitle = NULL, caption = NULL, source_note = NULL, caption_rule = FALSE, title_style = list(), subtitle_style = list(), caption_style = list(), source_note_style = list(), file = NULL, bg = "white", whitespace = 50, zoom = 2 )gt_stack_tables( tables = NULL, gap = 16, align = c("center", "left", "right"), title = NULL, subtitle = NULL, caption = NULL, source_note = NULL, caption_rule = FALSE, title_style = list(), subtitle_style = list(), caption_style = list(), source_note_style = list(), file = NULL, bg = "white", whitespace = 50, zoom = 2 )
tables |
A list of |
gap |
Numeric. The space between tables in pixels. Defaults to |
align |
Character. How tables of differing width line up, one of
|
title |
Character. An optional heading above the stack. Defaults to
|
subtitle |
Character. An optional line below |
caption |
Character. An optional note below the stack. Defaults to |
source_note |
Character. An optional second line below |
caption_rule |
Logical. Should a hairline sit between |
title_style, subtitle_style, caption_style, source_note_style
|
Named lists of style options. See Styling. Each defaults to an empty list. |
file |
Optional. A path to write a PNG to. If |
bg |
Character. The background color, used when saving. Defaults to
|
whitespace |
Numeric. Padding left around the stack when saving, in
pixels. Defaults to |
zoom |
Numeric. The rendering zoom factor used when saving. Defaults to
|
The stack is assembled as HTML rather than a gt table, since each table keeps
its own columns and header. That makes it a last step, after every table is
themed and formatted, and it means the output cannot be passed back into
further gt calls. Saving happens here through webshot2 rather than through
gt_save_crop(), so a file write needs the webshot2 package.
A shared heading and footer sit outside the stack in a shrink-to-fit wrapper,
so they line up with the tables rather than the page. Google fonts named in a
style list are loaded through a stylesheet link, since the composed HTML does
not run through gt's own font machinery.
An htmltools::browsable() tag list of the stacked tables, which
prints in the viewer; with file, invisibly file after writing the PNG
to it.
title_style, subtitle_style, caption_style, and source_note_style are
named lists following the same convention as gt_grid() and
gt_title_header(). Recognized keys are font (a Google font name), size,
color, weight, italic, spacing (letter spacing), transform (such as
"uppercase"), and align, plus line_height, margin_top, margin_bottom,
padding_top, and padding_bottom. Any length takes a number, read as pixels,
or a CSS string. Any key left out keeps its default.
gt_grid() for a side-by-side grid and gt_snake() for folding one
long table into blocks.
library(gt) t1 <- gt(subset( sdv_example_standings, division == "AFC East", c(team_name, wins, losses) )) t2 <- gt(subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses) )) gt_stack_tables(list(t1, t2)) # one heading over the stack, saved straight to an image; saving needs a # headless Chrome (webshot2) gt_stack_tables( list(t1, t2), title = "Two leagues", subtitle = "Stacked into one block", title_style = list(font = "Oswald", size = 30, transform = "uppercase"), file = tempfile(fileext = ".png") )library(gt) t1 <- gt(subset( sdv_example_standings, division == "AFC East", c(team_name, wins, losses) )) t2 <- gt(subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses) )) gt_stack_tables(list(t1, t2)) # one heading over the stack, saved straight to an image; saving needs a # headless Chrome (webshot2) gt_stack_tables( list(t1, t2), title = "Two leagues", subtitle = "Stacked into one block", title_style = list(font = "Oswald", size = 30, transform = "uppercase"), file = tempfile(fileext = ".png") )
gt tablesThe look of a printed statistical abstract. A slab body, narrow condensed labels, tight rows, and row banding to walk the eye across a wide table.
gt_theme_almanac( gt_object, accent = "#8C2F1E", density = c("compact", "comfortable", "social"), stripe = "#F1F1EF", ... )gt_theme_almanac( gt_object, accent = "#8C2F1E", density = c("compact", "comfortable", "social"), stripe = "#F1F1EF", ... )
gt_object |
A |
accent |
Character. A hex color for the row-group labels and the rule
above the table. Defaults to |
density |
Character. The type and padding scale. One of |
stripe |
Character. A hex color for the banded rows. Pass |
... |
Additional arguments passed to |
It is the only theme in the package that bands its rows.
Returns a modified gt table with the theme applied.
density sets the type and padding scale together. "comfortable" uses a
14px body with roomy rows, "compact" a 12px body with tight rows, and
"social" a 17px body with generous rows and a larger title, at the scale
gt_save_crop() and gt_social_crop() export at.
library(gt) nfc <- subset( sdv_example_standings, conference == "NFC", c(team_name, wins:points_against) ) gt(head(nfc, 12)) |> gt_theme_almanac() # banding off, cooler accent east <- subset( sdv_example_standings, league == "nba" & conference == "Eastern", c(team_name, wins, losses, win_pct:points_against) ) gt(east) |> gt_theme_almanac(stripe = NA, accent = "#1F3A5F")library(gt) nfc <- subset( sdv_example_standings, conference == "NFC", c(team_name, wins:points_against) ) gt(head(nfc, 12)) |> gt_theme_almanac() # banding off, cooler accent east <- subset( sdv_example_standings, league == "nba" & conference == "Eastern", c(team_name, wins, losses, win_pct:points_against) ) gt(east) |> gt_theme_almanac(stripe = NA, accent = "#1F3A5F")
gt tablesModeled on The Athletic's tables. A monospaced Spline Sans Mono body, uppercase Work Sans labels and titles, dotted rules between rows, thin vertical rules separating the columns, and a solid black row-group band with knocked-out white labels. All columns are centered.
gt_theme_athletic( gt_object, density = c("comfortable", "compact", "social"), ... )gt_theme_athletic( gt_object, density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
The row rules are a dotted top border applied to every body row, and the
column separators are a thin left border on every column except the first, so
the stub reads without a leading rule. Both are drawn with gt::cell_borders()
rather than table options. A table id is resolved (or generated) up front so
the gt::opt_css() block can pin the closing row border and heading padding
to this table alone.
density rescales the finished table, since this theme sets its sizes
directly rather than deriving them from a scale.
Returns a modified gt table with the theme applied.
density scales the theme's type and row padding together. "comfortable"
leaves every size as the theme sets it, "compact" scales both down, and
"social" scales both up, to the scale gt_save_crop() and
gt_social_crop() export at.
library(gt) afc_north <- subset( sdv_example_standings, division == "AFC North", c(team_name, wins:points_against) ) gt(afc_north) |> gt_theme_athletic() gt(afc_north) |> gt_theme_athletic(density = "compact")library(gt) afc_north <- subset( sdv_example_standings, division == "AFC North", c(team_name, wins:points_against) ) gt(afc_north) |> gt_theme_athletic() gt(afc_north) |> gt_theme_athletic(density = "compact")
gt tablesThree horizontal rules and nothing else, the way LaTeX booktabs draws them. A heavy rule sits above the column labels, a lighter one below them, and a heavy rule closes the body. There are no vertical rules, no rules between data rows, and no fills. The type is a Times-compatible serif.
gt_theme_booktabs( gt_object, accent = "#111111", density = c("comfortable", "compact", "social"), ... )gt_theme_booktabs( gt_object, accent = "#111111", density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
accent |
Character. A hex color for the three rules and the row-group
labels. Defaults to |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
accent recolors the three rules and the row-group labels.
Returns a modified gt table with the theme applied.
density sets the type and padding scale together. "comfortable" uses a
14px body with roomy rows, "compact" a 12px body with tight rows, and
"social" a 17px body with generous rows and a larger title, at the scale
gt_save_crop() and gt_social_crop() export at.
gt_theme_tufte() for a lighter, minimal-ink relative, and
gt_significance() for significance notation.
library(gt) afc_west <- subset( sdv_example_standings, division == "AFC West", c(team_name, wins:points_against) ) gt(afc_west) |> gt_theme_booktabs() # a regression table, with significance stars and a colored rule nfl <- subset(sdv_example_standings, league == "nfl") fit <- lm(win_pct ~ points_for + points_against, data = nfl) data.frame( Term = names(coef(fit)), Estimate = coef(fit), p = summary(fit)$coefficients[, 4] ) |> gt() |> fmt_number(Estimate, decimals = 4) |> gt_significance(Estimate, p) |> gt_theme_booktabs(accent = "#1A3E6F")library(gt) afc_west <- subset( sdv_example_standings, division == "AFC West", c(team_name, wins:points_against) ) gt(afc_west) |> gt_theme_booktabs() # a regression table, with significance stars and a colored rule nfl <- subset(sdv_example_standings, league == "nfl") fit <- lm(win_pct ~ points_for + points_against, data = nfl) data.frame( Term = names(coef(fit)), Estimate = coef(fit), p = summary(fit)$coefficients[, 4] ) |> gt() |> fmt_number(Estimate, decimals = 4) |> gt_significance(Estimate, p) |> gt_theme_booktabs(accent = "#1A3E6F")
gt tablesSets a serif body under small letterspaced sans column labels, with hairline rules and no fills anywhere. Row groups are an uppercase label over a rule rather than a colored band.
gt_theme_broadsheet( gt_object, accent = "#A6081A", density = c("comfortable", "compact", "social"), paper = "white", ... )gt_theme_broadsheet( gt_object, accent = "#A6081A", density = c("comfortable", "compact", "social"), paper = "white", ... )
gt_object |
A |
accent |
Character. A hex color for the rule above the table and for the
row-group labels. Defaults to |
density |
Character. The type and padding scale. One of |
paper |
Character. The table background. Either |
... |
Additional arguments passed to |
accent recolors the rule above the table and the row-group labels.
Returns a modified gt table with the theme applied.
density sets the type and padding scale together. "comfortable" uses a
14px body with roomy rows, "compact" a 12px body with tight rows, and
"social" a 17px body with generous rows and a larger title, at the scale
gt_save_crop() and gt_social_crop() export at.
gt_title_header() for a richer header block, and gt_legend_continuous() for
explaining a colored column.
library(gt) nfc_east <- subset( sdv_example_standings, division == "NFC East", c(team_name, wins:points_against) ) gt(nfc_east) |> gt_theme_broadsheet() # financial-press pink, sized for an image export pacific <- subset( sdv_example_standings, division == "Pacific", c(team_name, wins, losses, win_pct:points_against) ) gt(pacific) |> gt_theme_broadsheet(paper = "salmon", accent = "#0F5257", density = "social")library(gt) nfc_east <- subset( sdv_example_standings, division == "NFC East", c(team_name, wins:points_against) ) gt(nfc_east) |> gt_theme_broadsheet() # financial-press pink, sized for an image export pacific <- subset( sdv_example_standings, division == "Pacific", c(team_name, wins, losses, win_pct:points_against) ) gt(pacific) |> gt_theme_broadsheet(paper = "salmon", accent = "#0F5257", density = "social")
gt tablesHeavy black rules, a solid label bar, and a display face at a large size.
gt_theme_brutalist( gt_object, accent = "#FF3B00", density = c("comfortable", "compact", "social"), ... )gt_theme_brutalist( gt_object, accent = "#FF3B00", density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
accent |
Character. The theme's single accent color, used on the
row-group labels. Defaults to |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
The accent color is used in exactly one place, on the row-group labels.
Returns a modified gt table with the theme applied.
density sets the type and padding scale together. "comfortable" uses a
14px body with roomy rows, "compact" a 12px body with tight rows, and
"social" a 17px body with generous rows and a larger title, at the scale
gt_save_crop() and gt_social_crop() export at.
library(gt) afc_south <- subset( sdv_example_standings, division == "AFC South", c(team_name, wins:points_against) ) gt(afc_south) |> gt_theme_brutalist() gt(afc_south) |> gt_theme_brutalist(accent = "#0033FF", density = "social")library(gt) afc_south <- subset( sdv_example_standings, division == "AFC South", c(team_name, wins:points_against) ) gt(afc_south) |> gt_theme_brutalist() gt(afc_south) |> gt_theme_brutalist(accent = "#0033FF", density = "social")
gt tablesColors the entire table surface instead of putting a colored detail on a neutral background, tying the table to a single brand or publication color.
gt_theme_drench( gt_object, color = "#123F5E", density = c("comfortable", "compact", "social"), ... )gt_theme_drench( gt_object, color = "#123F5E", density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
color |
Character. The hex color the table is drenched in. Anything from a
near-black to a mid-saturation brand color works, and very pale colors flip
the type to dark automatically. Defaults to |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
Text, rules, and secondary type are all derived from color. The type color is
whichever of black or white measures higher contrast against the background,
and the rules are built by shifting the background itself, since gray laid over
a saturated ground looks washed out.
Returns a modified gt table with the theme applied.
The secondary color used for column labels, the subtitle and source notes is
blended toward the type color until it clears a 4.5:1 contrast ratio against
the background, so it stays readable whatever color you pass.
density sets the type and padding scale together. "comfortable" uses a
14px body with roomy rows, "compact" a 12px body with tight rows, and
"social" a 17px body with generous rows and a larger title, at the scale
gt_save_crop() and gt_social_crop() export at.
gt_theme_midnight() for a restrained dark background instead.
library(gt) southwest <- subset( sdv_example_standings, division == "Southwest", c(team_name, wins, losses, win_pct:points_against) ) gt(southwest) |> gt_theme_drench() # a brand color, with a matching export canvas; saving needs a headless # Chrome (webshot2) gt(southwest) |> gt_theme_drench(color = "#4B1E78", density = "social") |> gt_social_crop(tempfile(fileext = ".png"), bg = "#4B1E78")library(gt) southwest <- subset( sdv_example_standings, division == "Southwest", c(team_name, wins, losses, win_pct:points_against) ) gt(southwest) |> gt_theme_drench() # a brand color, with a matching export canvas; saving needs a headless # Chrome (webshot2) gt(southwest) |> gt_theme_drench(color = "#4B1E78", density = "social") |> gt_social_crop(tempfile(fileext = ".png"), bg = "#4B1E78")
gt tablesThe package's house theme. A warm cream background, an Almarai body, Signika Negative titles, column labels and row groups, hairline separators between rows, and gray row-group bands carrying cream labels. All columns are centered.
gt_theme_gtutils( gt_object, density = c("comfortable", "compact", "social"), ... )gt_theme_gtutils( gt_object, density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
The row separators are a single bottom border in gray (#8A817C) applied to
every body row except the last, so the table closes on the background rather
than a rule. The background is a warm cream (#FFFDF5), and horizontal rules
are otherwise set transparent. A table id is resolved (or generated) up front
so the gt::opt_css() block can pin the closing row border and heading
padding to this table alone.
density rescales the finished table, since this theme sets its sizes
directly rather than deriving them from a scale.
Returns a modified gt table with the theme applied.
density scales the theme's type and row padding together. "comfortable"
leaves every size as the theme sets it, "compact" scales both down, and
"social" scales both up, to the scale gt_save_crop() and
gt_social_crop() export at.
library(gt) nfc_south <- subset( sdv_example_standings, division == "NFC South", c(team_name, wins:points_against) ) gt(nfc_south) |> gt_theme_gtutils() gt(nfc_south) |> gt_theme_gtutils(density = "compact")library(gt) nfc_south <- subset( sdv_example_standings, division == "NFC South", c(team_name, wins:points_against) ) gt(nfc_south) |> gt_theme_gtutils() gt(nfc_south) |> gt_theme_gtutils(density = "compact")
gt tablesModeled on KenPom's tables. Helvetica Neue type, blue zebra-striped rows, blue column labels and row-group bands set over a light-blue fill, and underlined spanners. The heading is centered.
gt_theme_kenpom( gt_object, density = c("comfortable", "compact", "social"), ... )gt_theme_kenpom( gt_object, density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
The striping is applied by row position, a pale blue (#F2FAFD) on odd rows
and a slightly deeper blue (#e5ecf9) on even rows, so it follows the order
the data is in. A thin black bottom border separates every body row except the
last. To force the spanner row to render so it can be underlined, the theme
adds a placeholder spanner and then hides it with display: none in the
gt::opt_css() block. A table id is resolved (or generated) up front so that
CSS binds to this table alone. density rescales the finished table, since
this theme sets its sizes directly rather than deriving them from a scale.
Returns a modified gt table with the theme applied.
density scales the theme's type and row padding together. "comfortable"
leaves every size as the theme sets it, "compact" scales both down, and
"social" scales both up, to the scale gt_save_crop() and
gt_social_crop() export at.
library(gt) central <- subset( sdv_example_standings, division == "Central", c(team_name, wins, losses, win_pct:points_against) ) gt(central) |> gt_theme_kenpom() gt(central) |> gt_theme_kenpom(density = "compact")library(gt) central <- subset( sdv_example_standings, division == "Central", c(team_name, wins, losses, win_pct:points_against) ) gt(central) |> gt_theme_kenpom() gt(central) |> gt_theme_kenpom(density = "compact")
gt tablesA restrained dark theme. The background is a near-black instead of pure black, which avoids the smearing pure black causes on OLED screens. Column labels sit on a slightly raised band, rules are hairlines, and the body has no fills.
gt_theme_midnight( gt_object, accent = "#5B8DEF", density = c("comfortable", "compact", "social"), ... )gt_theme_midnight( gt_object, accent = "#5B8DEF", density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
accent |
Character. A hex color for the row-group labels and the rule
above the table. Defaults to |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
Light text on a dark background reads as lighter weight than it is, so the theme opens up the line height to compensate.
Returns a modified gt table with the theme applied.
A green-to-red ramp built for white paper goes muddy on a near-black
background, as its mid-tones collapse toward the background. Use pal_midnight
with gt_color_ranks() instead.
density sets the type and padding scale together. "comfortable" uses a
14px body with roomy rows, "compact" a 12px body with tight rows, and
"social" a 17px body with generous rows and a larger title, at the scale
gt_save_crop() and gt_social_crop() export at.
pal_midnight for a color scale that survives a dark ground, and
gt_theme_terminal() for a denser dark look.
library(gt) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins:points_against) ) gt(nfc_west) |> gt_theme_midnight() # color scales need lifting on a dark ground; see pal_midnight west <- subset( sdv_example_standings, league == "nba" & conference == "Western", c(team_name, wins, losses, win_pct) ) gt(west) |> gt_theme_midnight() |> gt_color_ranks(win_pct, palette = pal_midnight)library(gt) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins:points_against) ) gt(nfc_west) |> gt_theme_midnight() # color scales need lifting on a dark ground; see pal_midnight west <- subset( sdv_example_standings, league == "nba" & conference == "Western", c(team_name, wins, losses, win_pct) ) gt(west) |> gt_theme_midnight() |> gt_color_ranks(win_pct, palette = pal_midnight)
gt tablesOpen Sans throughout, with uppercase white column labels on a solid black band and zebra-striped rows, after the NCAA. Row groups render as white labels on a dark gray fill, column spanners are underlined, and every column is left aligned with a 25px left indent on each row.
gt_theme_ncaa(gt_object, density = c("comfortable", "compact", "social"), ...)gt_theme_ncaa(gt_object, density = c("comfortable", "compact", "social"), ...)
gt_object |
A |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
Column labels sit in a solid black band in white uppercase Open Sans, while
source notes and footnotes switch to Almarai. Rows are zebra-striped through
gt::opt_row_striping(), horizontal rules are hidden, and each row and heading
carries a 25px left indent. The last body row's bottom border is painted white
so it does not double the rule that closes the table.
Returns a modified gt table with the theme applied.
density scales the theme's type and row padding together. "comfortable"
leaves every size as the theme sets it, "compact" scales both down, and
"social" scales both up, to the scale gt_save_crop() and
gt_social_crop() export at.
library(gt) atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses, win_pct:points_against) ) gt(atlantic) |> gt_theme_ncaa()library(gt) atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses, win_pct:points_against) ) gt(atlantic) |> gt_theme_ncaa()
gt tablesDM Sans throughout in the Premier League's deep purple (#37003c), with
muted-purple column labels and a purple rule bracketing the body. Row groups
render as white labels on a pale lilac fill, and column spanners are bold and
underlined.
gt_theme_pl(gt_object, density = c("comfortable", "compact", "social"), ...)gt_theme_pl(gt_object, density = c("comfortable", "compact", "social"), ...)
gt_object |
A |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
A purple rule closes the column labels and another opens the body, and each body row is separated by a purple bottom border. The last body row's bottom border is painted white so it does not double the rule that closes the table.
Returns a modified gt table with the theme applied.
density scales the theme's type and row padding together. "comfortable"
leaves every size as the theme sets it, "compact" scales both down, and
"social" scales both up, to the scale gt_save_crop() and
gt_social_crop() export at.
library(gt) southeast <- subset( sdv_example_standings, division == "Southeast", c(team_name, wins, losses, win_pct:points_against) ) gt(southeast) |> gt_theme_pl()library(gt) southeast <- subset( sdv_example_standings, division == "Southeast", c(team_name, wins, losses, win_pct:points_against) ) gt(southeast) |> gt_theme_pl()
Renders the same few rows through each gt_theme_* function in the package
and lays the results out in a grid, one panel per theme, labeled with its name.
gt_theme_preview( data, themes = NULL, n = 5, ncol = 3, density = "compact", file = NULL, ... )gt_theme_preview( data, themes = NULL, n = 5, ncol = 3, density = "compact", file = NULL, ... )
data |
A data frame. A |
themes |
Character. The theme functions to show, by name. If |
n |
Integer. How many rows of |
ncol |
Integer. The number of panels across. Defaults to |
density |
Character. A |
file |
Optional. A path to write a PNG to. If |
... |
Further arguments passed to |
Each panel is captioned with the theme's name in a neutral style, set outside the table. Using each theme's own heading instead would let a wide display title stretch its panel out of shape.
Themes that take extra arguments, such as style on gt_theme_sofa(), are
shown at their defaults.
What gt_grid() returns: an htmltools::browsable() tag list of
the previews, which prints in the viewer; with file, invisibly file
after writing the PNG to it.
gt_grid(), which does the layout.
nfl <- subset( sdv_example_standings, league == "nfl", c(team_name, wins, losses, win_pct) ) gt_theme_preview( nfl, themes = c("gt_theme_sdv", "gt_theme_kenpom", "gt_theme_athletic") ) # a subset, saved as one wide image; saving needs a headless Chrome (webshot2) nba <- subset( sdv_example_standings, league == "nba", c(team_name, wins, losses, win_pct) ) gt_theme_preview( nba, themes = c("gt_theme_broadsheet", "gt_theme_swiss", "gt_theme_midnight"), ncol = 3, file = tempfile(fileext = ".png") )nfl <- subset( sdv_example_standings, league == "nfl", c(team_name, wins, losses, win_pct) ) gt_theme_preview( nfl, themes = c("gt_theme_sdv", "gt_theme_kenpom", "gt_theme_athletic") ) # a subset, saved as one wide image; saving needs a headless Chrome (webshot2) nba <- subset( sdv_example_standings, league == "nba", c(team_name, wins, losses, win_pct) ) gt_theme_preview( nba, themes = c("gt_theme_broadsheet", "gt_theme_swiss", "gt_theme_midnight"), ncol = 3, file = tempfile(fileext = ".png") )
gt tablesRoboto Condensed throughout, with bold column labels and zebra-striped rows under a centered heading, after Baseball Savant. Row groups render as off-white labels on a black fill, and column spanners are bold and underlined.
gt_theme_savant( gt_object, density = c("comfortable", "compact", "social"), ... )gt_theme_savant( gt_object, density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
The heading is centered rather than left aligned. Rows are zebra-striped through
gt::opt_row_striping() and horizontal rules are hidden. The last body row's
bottom border is painted white so it does not double the rule that closes the
table.
Returns a modified gt table with the theme applied.
density scales the theme's type and row padding together. "comfortable"
leaves every size as the theme sets it, "compact" scales both down, and
"social" scales both up, to the scale gt_save_crop() and
gt_social_crop() export at.
library(gt) afc_east <- subset( sdv_example_standings, division == "AFC East", c(team_name, wins:points_against) ) gt(afc_east) |> gt_theme_savant()library(gt) afc_east <- subset( sdv_example_standings, division == "AFC East", c(team_name, wins:points_against) ) gt(afc_east) |> gt_theme_savant()
gt tablesA solid color band carrying condensed uppercase labels, over tight rows, after a television lower-third or a stadium scoreboard.
gt_theme_scoreboard( gt_object, accent = "#0E1621", density = c("compact", "comfortable", "social"), ... )gt_theme_scoreboard( gt_object, accent = "#0E1621", density = c("compact", "comfortable", "social"), ... )
gt_object |
A |
accent |
Character. A hex color for the header band. The label color
adapts to it. Defaults to |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
accent sets the band itself, so one argument restyles the whole table to a
brand color. The label color is checked against the band and flipped to dark
if the accent is pale.
Returns a modified gt table with the theme applied.
density sets the type and padding scale together. "comfortable" uses a
14px body with roomy rows, "compact" a 12px body with tight rows, and
"social" a 17px body with generous rows and a larger title, at the scale
gt_save_crop() and gt_social_crop() export at.
gt_spotlight() for picking out a row, and gt_fmt_rank() for ordinals.
library(gt) northwest <- subset( sdv_example_standings, division == "Northwest", c(team_name, wins, losses, win_pct:points_against) ) gt(northwest) |> gt_theme_scoreboard() # a brand color carries the whole table gt(northwest) |> gt_theme_scoreboard(accent = "#0F766E")library(gt) northwest <- subset( sdv_example_standings, division == "Northwest", c(team_name, wins, losses, win_pct:points_against) ) gt(northwest) |> gt_theme_scoreboard() # a brand color carries the whole table gt(northwest) |> gt_theme_scoreboard(accent = "#0F766E")
gt tablesThe SportsDataverse house table: Chivo titles and column labels, a Lato body
set in tabular figures, faint row dividers, and the SDV gradient
(#3346F0 to #7FE6DC) drawn as a single horizon line under the column
labels. style = "dark" sets the same table on the SportsDataverse navy,
matching the dark mode of the package websites.
gt_theme_sdv( gt_object, style = c("light", "dark"), density = c("comfortable", "compact", "social"), ... )gt_theme_sdv( gt_object, style = c("light", "dark"), density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
style |
Character. |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
The gradient line is the theme's one accent; everything else stays quiet so
logos from gt_sdv_logos() and team colors carry the table. Titles and the
heading are left-aligned. Column labels keep the case you give them rather
than being forced to capitals. For a table dressed in one team's colors, see
gt_theme_sdv_team().
The line under the column labels is a CSS ::after element. gt's CSS inliner
removes those, so gt::as_raw_html(inline_css = TRUE) output (as used for
email) shows the table without it; knitted documents, websites and images
saved with gt_save_crop() keep it.
Returns a modified gt table with the theme applied.
density scales the theme's type and row padding together. "comfortable"
leaves every size as the theme sets it, "compact" scales both down, and
"social" scales both up, to the scale gt_save_crop() and
gt_social_crop() export at.
gt_theme_sdv_team(), theme_bg for the background to pad a saved
image with.
library(gt) standings <- data.frame( team = c("KC", "LAC", "DEN", "LV"), w = c(15, 11, 10, 4), l = c(2, 6, 7, 13) ) gt(standings) |> gt_sdv_logos(columns = "team", league = "nfl") |> tab_header("AFC West standings", "Through week 18") |> gt_theme_sdv() gt(standings) |> gt_theme_sdv(style = "dark", density = "social")library(gt) standings <- data.frame( team = c("KC", "LAC", "DEN", "LV"), w = c(15, 11, 10, 4), l = c(2, 6, 7, 13) ) gt(standings) |> gt_sdv_logos(columns = "team", league = "nfl") |> tab_header("AFC West standings", "Through week 18") |> gt_theme_sdv() gt(standings) |> gt_theme_sdv(style = "dark", density = "social")
gt tablesgt_theme_sdv() dressed in one team's colors: the title block is filled
with the team's primary color, the horizon line under the column labels takes
the secondary color, and the column labels are set in the primary color. The
colors come from sdv_team_colors(), so any abbreviation, alias or name
sdv_resolve() resolves works here.
gt_theme_sdv_team( gt_object, team = NULL, league, density = c("comfortable", "compact", "social"), season = NULL, id_system = "auto", ... )gt_theme_sdv_team( gt_object, team = NULL, league, density = c("comfortable", "compact", "social"), season = NULL, id_system = "auto", ... )
gt_object |
A |
team |
Character. One team, as an abbreviation, alias or name for
|
league |
A league key from |
density |
Character. The type and padding scale. One of |
season |
|
id_system |
|
... |
Additional arguments passed to |
Text on the filled title block is black or white, whichever contrasts more
with the team's primary color, and the subtitle is blended toward it until it
still clears a 4.5:1 contrast ratio. When the secondary color would vanish
against the white table (a white or pale secondary), the horizon line uses the
primary color instead, and column labels fall back to the SportsDataverse
navy when the primary color is too light to read on white. With
team = NULL the table wears the SportsDataverse navy and cyan.
Returns a modified gt table with the theme applied.
density scales the theme's type and row padding together. "comfortable"
leaves every size as the theme sets it, "compact" scales both down, and
"social" scales both up, to the scale gt_save_crop() and
gt_social_crop() export at.
gt_theme_sdv(), sdv_team_colors().
library(gt) leaders <- data.frame( player = c("Patrick Mahomes", "Travis Kelce", "Isiah Pacheco"), yards = c(4183, 984, 935) ) gt(leaders) |> tab_header("Chiefs yardage leaders", "2023 regular season") |> gt_theme_sdv_team(team = "KC", league = "nfl")library(gt) leaders <- data.frame( player = c("Patrick Mahomes", "Travis Kelce", "Isiah Pacheco"), yards = c(4183, 984, 935) ) gt(leaders) |> tab_header("Chiefs yardage leaders", "2023 regular season") |> gt_theme_sdv_team(team = "KC", league = "nfl")
gt tablesSofia Sans Condensed throughout on a warm cream ("light") or dark navy
("dark") ground, after SofaScore, with bold column labels and bold row-group
labels. Column spanners are bold and underlined. Horizontal rules are hidden,
so the ground alone separates the rows.
gt_theme_sofa( gt_object, style = "light", density = c("comfortable", "compact", "social"), ... )gt_theme_sofa( gt_object, style = "light", density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
style |
Character. The color scheme, |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
The table background, its outer borders, and the last row's bottom border are all painted in the chosen ground color, so the rows read as separated by space rather than by rules. Row groups are closed with a black bottom border.
Returns a modified gt table with the theme applied.
density scales the theme's type and row padding together. "comfortable"
leaves every size as the theme sets it, "compact" scales both down, and
"social" scales both up, to the scale gt_save_crop() and
gt_social_crop() export at.
library(gt) nfc_north <- subset( sdv_example_standings, division == "NFC North", c(team_name, wins:points_against) ) gt(nfc_north) |> gt_theme_sofa() gt(nfc_north) |> gt_theme_sofa(style = "dark")library(gt) nfc_north <- subset( sdv_example_standings, division == "NFC North", c(team_name, wins:points_against) ) gt(nfc_north) |> gt_theme_sofa() gt(nfc_north) |> gt_theme_sofa(style = "dark")
gt tablesBuilds the table on whitespace. There are no fills, no banding, and exactly two rules in the whole table, one under the column labels and one closing the body. Everything else is done with space and alignment.
gt_theme_swiss( gt_object, accent = "#111111", density = c("comfortable", "social", "compact"), ... )gt_theme_swiss( gt_object, accent = "#111111", density = c("comfortable", "social", "compact"), ... )
gt_object |
A |
accent |
Character. A hex color, used once, on the rule beneath the
column labels. Defaults to |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
Alignment is strict. Text sits flush left, numbers flush right, and nothing is centered.
Returns a modified gt table with the theme applied.
density sets the type and padding scale together. "comfortable" uses a
14px body with roomy rows, "compact" a 12px body with tight rows, and
"social" a 17px body with generous rows and a larger title, at the scale
gt_save_crop() and gt_social_crop() export at.
library(gt) afc_west <- subset( sdv_example_standings, division == "AFC West", c(team_name, wins:points_against) ) gt(afc_west) |> gt_theme_swiss() pacific <- subset( sdv_example_standings, division == "Pacific", c(team_name, wins, losses, win_pct:points_against) ) gt(pacific) |> gt_theme_swiss(accent = "#D33A2C")library(gt) afc_west <- subset( sdv_example_standings, division == "AFC West", c(team_name, wins:points_against) ) gt(afc_west) |> gt_theme_swiss() pacific <- subset( sdv_example_standings, division == "Pacific", c(team_name, wins, losses, win_pct:points_against) ) gt(pacific) |> gt_theme_swiss(accent = "#D33A2C")
gt tablesA dense monospace theme in the register of a trading terminal. Dark background, amber labels, a rule on every row, and tight padding.
gt_theme_terminal( gt_object, accent = "#FFB86C", density = c("compact", "comfortable", "social"), ... )gt_theme_terminal( gt_object, accent = "#FFB86C", density = c("compact", "comfortable", "social"), ... )
gt_object |
A |
accent |
Character. A hex color for the column labels, row groups, and
the top rule. Defaults to amber |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
The monospace face has fixed-width digits already, so numeric columns line up without any extra formatting.
Returns a modified gt table with the theme applied.
density sets the type and padding scale together. "comfortable" uses a
14px body with roomy rows, "compact" a 12px body with tight rows, and
"social" a 17px body with generous rows and a larger title, at the scale
gt_save_crop() and gt_social_crop() export at.
pal_midnight for a color scale that survives a dark ground.
library(gt) afc <- subset( sdv_example_standings, conference == "AFC", c(team_name, wins:points_against) ) gt(head(afc, 12)) |> gt_theme_terminal() east <- subset( sdv_example_standings, league == "nba" & conference == "Eastern", c(team_name, wins, losses, win_pct:points_against) ) gt(east) |> gt_theme_terminal(accent = "#7EE787")library(gt) afc <- subset( sdv_example_standings, conference == "AFC", c(team_name, wins:points_against) ) gt(head(afc, 12)) |> gt_theme_terminal() east <- subset( sdv_example_standings, league == "nba" & conference == "Eastern", c(team_name, wins, losses, win_pct:points_against) ) gt(east) |> gt_theme_terminal(accent = "#7EE787")
gt tablesOswald throughout on a near-black ("dark") or white ("light") ground, with
a bold title and every column center aligned. Rows are separated by thin black
borders and horizontal rules are otherwise hidden.
gt_theme_tier( gt_object, style = "dark", density = c("comfortable", "compact", "social"), ... )gt_theme_tier( gt_object, style = "dark", density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
style |
Character. The color scheme, |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
Every body row except the last carries a black bottom border, and the last
row's border is painted in the ground color so it does not double the edge of
the table. Pairs with gt_tiers(), which builds the tier rows themselves.
Returns a modified gt table with the theme applied.
density scales the theme's type and row padding together. "comfortable"
leaves every size as the theme sets it, "compact" scales both down, and
"social" scales both up, to the scale gt_save_crop() and
gt_social_crop() export at.
library(gt) afc <- subset( sdv_example_standings, conference == "AFC" & conference_rank <= 7, c(team_name, wins:points_against) ) gt(afc) |> gt_theme_tier() gt(afc) |> gt_theme_tier(style = "light")library(gt) afc <- subset( sdv_example_standings, conference == "AFC" & conference_rank <= 7, c(team_name, wins:points_against) ) gt(afc) |> gt_theme_tier() gt(afc) |> gt_theme_tier(style = "light")
gt tablesA spare, Tufte-inspired look. An old-style serif on a warm white ground, italic column labels, and a single hairline under them. There are no vertical rules, no rules between rows, and no fills. A faint hairline closes the body.
gt_theme_tufte( gt_object, accent = "#111111", density = c("comfortable", "compact", "social"), ... )gt_theme_tufte( gt_object, accent = "#111111", density = c("comfortable", "compact", "social"), ... )
gt_object |
A |
accent |
Character. A hex color for the header hairline and the row-group
labels. Defaults to |
density |
Character. The type and padding scale. One of |
... |
Additional arguments passed to |
accent recolors the header hairline and the row-group labels.
Returns a modified gt table with the theme applied.
density sets the type and padding scale together. "comfortable" uses a
14px body with roomy rows, "compact" a 12px body with tight rows, and
"social" a 17px body with generous rows and a larger title, at the scale
gt_save_crop() and gt_social_crop() export at.
gt_theme_booktabs() for a firmer, academic relative.
library(gt) nfc_north <- subset( sdv_example_standings, division == "NFC North", c(team_name, wins:points_against) ) gt(nfc_north) |> gt_theme_tufte() # a muted rust accent on the hairline atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses, win_pct:points_against) ) gt(atlantic) |> gt_theme_tufte(accent = "#7B3F2B")library(gt) nfc_north <- subset( sdv_example_standings, division == "NFC North", c(team_name, wins:points_against) ) gt(nfc_north) |> gt_theme_tufte() # a muted rust accent on the hairline atlantic <- subset( sdv_example_standings, division == "Atlantic", c(team_name, wins, losses, win_pct:points_against) ) gt(atlantic) |> gt_theme_tufte(accent = "#7B3F2B")
gt tableFills the cells of a tier column by tier level and bolds them, pairing each
level with a color. The remaining columns are rendered as images, since the
intended layout is a tier list with logos or headshots ranked into colored
bands.
gt_tiers( gt_object, levels, colors = NULL, style = "dark", img_height = "55px", tier_column = "tier", image_columns = NULL, alt = NULL )gt_tiers( gt_object, levels, colors = NULL, style = "dark", img_height = "55px", tier_column = "tier", image_columns = NULL, alt = NULL )
gt_object |
A |
levels |
Character. The tier levels, matching the values in the table's
tier column. May instead be a single named vector of |
colors |
Character. Hex color codes paired with |
style |
Character. The color scheme, passed to |
img_height |
Character. The height of the images rendered in the image
columns, as a CSS size. Defaults to |
tier_column |
Character. The name of the column holding the tier levels.
Defaults to |
image_columns |
Optional. The columns to render as images. When |
alt |
Optional. A function that takes the image paths or URLs and
returns their alt text, one string per image, such as
|
The theme is applied once with gt_theme_tier(), the image columns are passed
through gt::fmt_image() at img_height, and all column labels are cleared,
so the input for those columns must be image paths or URLs. Each image gets
its own alt text from alt, so a screen reader can tell the entries
apart. The function then
reduces over levels, and for each level fills the matching tier_column
cells with the paired color and sets their text to black or white, whichever
measures higher contrast against that fill, so each band keeps a legible
label. Naming image_columns leaves the rest untouched, so a text column can
sit alongside the images.
Returns a modified gt table with the tier column colored and bolded.
library(gt) # the AFC's seven playoff seeds: the top seed's bye, then the wild-card round afc <- subset(sdv_example_standings, conference == "AFC" & conference_rank <= 7) afc <- afc[order(afc$conference_rank), ] seeds <- data.frame( tier = ifelse(afc$conference_rank == 1, "Bye", "Wild card"), logo = sdv_logo_url(afc$team, "nfl") ) # the logos are URLs, which the browser fetches when the table is shown gt(seeds) |> gt_tiers(levels = c("Bye", "Wild card"), colors = c("#1B7837", "#B2182B"))library(gt) # the AFC's seven playoff seeds: the top seed's bye, then the wild-card round afc <- subset(sdv_example_standings, conference == "AFC" & conference_rank <= 7) afc <- afc[order(afc$conference_rank), ] seeds <- data.frame( tier = ifelse(afc$conference_rank == 1, "Bye", "Wild card"), logo = sdv_logo_url(afc$team, "nfl") ) # the logos are URLs, which the browser fetches when the table is shown gt(seeds) |> gt_tiers(levels = c("Bye", "Wild card"), colors = c("#1B7837", "#B2182B"))
gt tableWraps gt::tab_header() to produce a fuller header: an optional kicker above
the title, the title, an optional subtitle, and an optional date. Each of the
four is styled independently through its own list, so the typography can be set
without writing the tab_style() calls yourself.
gt_title_header( gt_object, title, subtitle = NULL, kicker = NULL, date = NULL, kicker_style = list(), title_style = list(), subtitle_style = list(), date_style = list() )gt_title_header( gt_object, title, subtitle = NULL, kicker = NULL, date = NULL, kicker_style = list(), title_style = list(), subtitle_style = list(), date_style = list() )
gt_object |
A |
title |
Character. The title text. |
subtitle |
Optional. The subtitle text. Defaults to |
kicker |
Optional. A short line above the title. Defaults to |
date |
Optional. A date shown beneath the subtitle. A |
kicker_style |
A named list styling the kicker. See Styling. Defaults to an empty list. |
title_style |
A named list styling the title. Defaults to an empty list. |
subtitle_style |
A named list styling the subtitle. Defaults to an empty list. |
date_style |
A named list styling the date. Defaults to an empty list. |
Google fonts named in the style lists are loaded through gt's own machinery,
so they survive gtsave() as well as the HTML output.
gt_title_header() calls gt::tab_header(), which replaces the whole header.
Paired with gt_legend_continuous() at location = "top", call this one
first or it will overwrite the legend.
Returns a modified gt table with the header block applied.
Each *_style argument takes a named list. Recognized keys are font (a
Google font name), size, color, weight, italic, spacing (letter
spacing), transform (such as "uppercase"), and align, plus line_height,
margin_top, margin_bottom, padding_top, and padding_bottom for nudging
the blocks closer together or further apart. Any key you leave out keeps its
default. Lengths take a number, read as pixels, or a CSS string such as
"2rem". This is the same convention used by gt_grid(), gt_legend_continuous(),
and gt_legend_discrete().
gt_538_caption() for the footer equivalent.
library(gt) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins:points_against) ) gt(nfc_west) |> gt_title_header( title = "The NFC West", subtitle = "Final standings of the 2025 regular season", kicker = "NFL", date = as.Date("2026-07-21"), kicker_style = list( color = "#0054AD", size = "0.8em", transform = "uppercase", spacing = "0.1em" ), title_style = list(font = "Libre Franklin", weight = 800, size = "26px"), subtitle_style = list(color = "#666666", italic = TRUE), date_style = list(color = "#B8232F", weight = 600) )library(gt) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins:points_against) ) gt(nfc_west) |> gt_title_header( title = "The NFC West", subtitle = "Final standings of the 2025 regular season", kicker = "NFL", date = as.Date("2026-07-21"), kicker_style = list( color = "#0054AD", size = "0.8em", transform = "uppercase", spacing = "0.1em" ), title_style = list(font = "Libre Franklin", weight = 800, size = "26px"), subtitle_style = list(color = "#666666", italic = TRUE), date_style = list(color = "#B8232F", weight = 600) )
gt tableSets a wordmark or a logo behind the table body, faint enough to read through.
gt_watermark( gt_object, text = NULL, image = NULL, opacity = 0.06, size = "60%", position = "center", color = "#000000", angle = 0, font = "Helvetica, Arial, sans-serif" )gt_watermark( gt_object, text = NULL, image = NULL, opacity = 0.06, size = "60%", position = "center", color = "#000000", angle = 0, font = "Helvetica, Arial, sans-serif" )
gt_object |
A |
text |
Optional. Text to render as the watermark. Defaults to |
image |
Optional. A path to a PNG, JPEG, or SVG file to use instead of
|
opacity |
Numeric. How faint the watermark is, from 0 to 1. Defaults to
|
size |
Character. The width of the watermark relative to the table, as a
CSS background size such as |
position |
Character. Where it sits, as a CSS background position such as
|
color |
Character. The text color, used only with |
angle |
Numeric. Rotation in degrees, used only with |
font |
Character. The font family for |
A text watermark is drawn as an inline SVG rather than as HTML, because a
background image is the only way to sit behind the table body without taking
up a row. An SVG background cannot load the page's webfonts, so font has to
name a face installed on the machine rendering the table.
The watermark sits behind the body cells, so it will be hidden wherever a cell
has its own fill, from row striping or from gt::data_color().
Returns a modified gt table with a watermark behind the body.
gt_social_tag() for visible attribution in the source note.
library(gt) afc_south <- subset( sdv_example_standings, division == "AFC South", c(team_name, wins:points_against) ) gt(afc_south) |> gt_watermark(text = "DRAFT", angle = -30, opacity = 0.08) # any local png, jpeg, gif or svg; a small svg written on the spot here logo <- tempfile(fileext = ".svg") writeLines(paste0( '<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40">', '<circle cx="20" cy="20" r="18"/></svg>' ), logo) gt(afc_south) |> gt_watermark(image = logo, size = "40%", position = "right bottom")library(gt) afc_south <- subset( sdv_example_standings, division == "AFC South", c(team_name, wins:points_against) ) gt(afc_south) |> gt_watermark(text = "DRAFT", angle = -30, opacity = 0.08) # any local png, jpeg, gif or svg; a small svg written on the spot here logo <- tempfile(fileext = ".svg") writeLines(paste0( '<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40">', '<circle cx="20" cy="20" r="18"/></svg>' ), logo) gt(afc_south) |> gt_watermark(image = logo, size = "40%", position = "right bottom")
gt tableWraps a column label onto several short lines so a wide heading stops forcing a narrow column wider than its data needs. "Strength of Schedule" over a two-digit column becomes three stacked lines instead of one long one.
gt_wrap_labels( gt_object, columns = gt::everything(), width = 12, balance = TRUE )gt_wrap_labels( gt_object, columns = gt::everything(), width = 12, balance = TRUE )
gt_object |
A |
columns |
The columns whose labels should wrap. Defaults to
|
width |
Integer. The target line length in characters. Defaults to |
balance |
Logical. Should the lines be evened out rather than filled
greedily left to right? Defaults to |
The hand-rolled version is gt::cols_label(x = gt::html("A<br>B")), written
out per column. This wraps at a width for you, and by default balances the
lines so they come out close to even rather than a long first line over a
short last one.
A label of one word, or one already shorter than width, is left alone. The
wrap is on whitespace only, so a single long word is never split.
Returns a modified gt table with the selected labels wrapped.
library(gt) afc_east <- subset( sdv_example_standings, division == "AFC East", c(team_name, win_pct, conference_rank) ) gt(afc_east) |> cols_label( win_pct = "Winning Percentage", conference_rank = "Final Conference Rank" ) |> gt_wrap_labels(c(win_pct, conference_rank), width = 10)library(gt) afc_east <- subset( sdv_example_standings, division == "AFC East", c(team_name, win_pct, conference_rank) ) gt(afc_east) |> cols_label( win_pct = "Winning Percentage", conference_rank = "Final Conference Rank" ) |> gt_wrap_labels(c(win_pct, conference_rank), width = 10)
A five-color green-to-red ramp with its luminance range lifted so it still
reads on a near-black background. The default palette in gt_color_ranks() is
built for white paper, and its mid-tones collapse into a dark ground. Pass this
instead when using gt_theme_midnight() or gt_theme_terminal().
pal_midnightpal_midnight
A character vector of five hex colors, running best to worst.
west <- subset( sdv_example_standings, league == "nba" & conference == "Western", c(team_name, wins, losses, win_pct) ) gt::gt(west) |> gt_theme_midnight() |> gt_color_ranks(win_pct, palette = pal_midnight)west <- subset( sdv_example_standings, league == "nba" & conference == "Western", c(team_name, wins, losses, win_pct) ) gt::gt(west) |> gt_theme_midnight() |> gt_color_ranks(win_pct, palette = pal_midnight)
Builds a named list of reactable::colDef() objects whose
headers are team logos, for data frames whose column names are team
abbreviations. Columns that cannot be resolved are left out of the list so
reactable falls back to the plain column name.
reactable_sdv_cols_label( .data, ..., league, variant = "default", height = 30, season = NULL, id_system = "auto", strict = FALSE )reactable_sdv_cols_label( .data, ..., league, variant = "default", height = 30, season = NULL, id_system = "auto", strict = FALSE )
.data |
A data frame whose column names are team abbreviations. |
... |
Additional arguments passed to every |
league |
A league key from |
variant |
Character. |
height |
Numeric. Image height in pixels. |
season |
|
id_system |
|
strict |
If |
A named list of colDef objects for the columns argument of
reactable::reactable().
library(reactable) library(sdvplotR) df <- data.frame(KC = 1:3, BUF = 4:6, SF = 7:9) reactable(df, columns = reactable_sdv_cols_label(df, league = "nfl"))library(reactable) library(sdvplotR) df <- data.frame(KC = 1:3, BUF = 4:6, SF = 7:9) reactable(df, columns = reactable_sdv_cols_label(df, league = "nfl"))
Cell renderers for reactable::colDef() that translate team
abbreviations (or player IDs) into <img> tags. Values that cannot be
resolved are returned unchanged so the original text is shown. Logos and
wordmarks get the team's full name as alt text, headshots
"Player <id> headshot".
reactable_sdv_logos( league, variant = "default", height = 30, default_img = NULL, season = NULL, id_system = "auto", strict = FALSE ) reactable_sdv_wordmarks( league, variant = "default", height = 30, default_img = NULL, season = NULL, id_system = "auto", strict = FALSE ) reactable_sdv_headshots( league, height = 40, default_img = NULL, id_system = "espn" )reactable_sdv_logos( league, variant = "default", height = 30, default_img = NULL, season = NULL, id_system = "auto", strict = FALSE ) reactable_sdv_wordmarks( league, variant = "default", height = 30, default_img = NULL, season = NULL, id_system = "auto", strict = FALSE ) reactable_sdv_headshots( league, height = 40, default_img = NULL, id_system = "espn" )
league |
A league key from |
variant |
Character. |
height |
Numeric. Image height in pixels. |
default_img |
Character. Fallback image URL used when the value cannot
be resolved. If |
season |
|
id_system |
|
strict |
If |
A function with signature function(value, index) suitable for the
cell argument of reactable::colDef().
reactable_sdv_cols_label(), reactable_sdv_team_color_bar(),
gt_sdv_logos()
library(reactable) library(sdvplotR) df <- data.frame(team = c("KC", "BUF", "SF"), wins = c(13, 12, 11)) reactable( df, columns = list( team = colDef(cell = reactable_sdv_logos(league = "nfl"), html = TRUE) ) )library(reactable) library(sdvplotR) df <- data.frame(team = c("KC", "BUF", "SF"), wins = c(13, 12, 11)) reactable( df, columns = list( team = colDef(cell = reactable_sdv_logos(league = "nfl"), html = TRUE) ) )
Style functions for reactable::colDef() that color cells
with a team's primary or secondary color: a horizontal bar whose length
is proportional to the cell value, or a translucent background fill.
reactable_sdv_team_color_bar( data, team_col, league, which = c("primary", "secondary"), max_value = NULL, na_color = "grey70", season = NULL, id_system = "auto", strict = FALSE ) reactable_sdv_team_color_bg( data, team_col, league, which = c("primary", "secondary"), alpha = 0.15, na_color = "grey70", season = NULL, id_system = "auto", strict = FALSE )reactable_sdv_team_color_bar( data, team_col, league, which = c("primary", "secondary"), max_value = NULL, na_color = "grey70", season = NULL, id_system = "auto", strict = FALSE ) reactable_sdv_team_color_bg( data, team_col, league, which = c("primary", "secondary"), alpha = 0.15, na_color = "grey70", season = NULL, id_system = "auto", strict = FALSE )
data |
The data frame passed to |
team_col |
Character. Name of the column in |
league |
A league key from |
which |
Character. |
max_value |
Numeric. Reference value that fills the whole cell. If
|
na_color |
Color used when a team cannot be resolved. |
season |
|
id_system |
|
strict |
If |
alpha |
Numeric. Opacity of the background fill in |
A function with signature function(value, index, name) suitable
for the style argument of reactable::colDef().
library(reactable) library(sdvplotR) df <- data.frame(team = c("KC", "BUF", "SF"), wins = c(13, 12, 11)) reactable( df, columns = list( team = colDef(style = reactable_sdv_team_color_bg(df, "team", league = "nfl")), wins = colDef(style = reactable_sdv_team_color_bar(df, "team", league = "nfl")) ) )library(reactable) library(sdvplotR) df <- data.frame(team = c("KC", "BUF", "SF"), wins = c(13, 12, 11)) reactable( df, columns = list( team = colDef(style = reactable_sdv_team_color_bg(df, "team", league = "nfl")), wins = colDef(style = reactable_sdv_team_color_bar(df, "team", league = "nfl")) ) )
These scale functions replace axis labels with team logos or player headshots. They work by modifying the axis text theme element to render images.
scale_x_sdv( ..., league, expand = ggplot2::waiver(), guide = ggplot2::waiver(), position = "bottom", size = 12, season = NULL, id_system = "auto" ) scale_y_sdv( ..., league, expand = ggplot2::waiver(), guide = ggplot2::waiver(), position = "left", size = 12, season = NULL, id_system = "auto" ) scale_x_sdv_headshots( ..., league, expand = ggplot2::waiver(), guide = ggplot2::waiver(), position = "bottom", size = 20, id_system = "espn" ) scale_y_sdv_headshots( ..., league, expand = ggplot2::waiver(), guide = ggplot2::waiver(), position = "left", size = 30, id_system = "espn" )scale_x_sdv( ..., league, expand = ggplot2::waiver(), guide = ggplot2::waiver(), position = "bottom", size = 12, season = NULL, id_system = "auto" ) scale_y_sdv( ..., league, expand = ggplot2::waiver(), guide = ggplot2::waiver(), position = "left", size = 12, season = NULL, id_system = "auto" ) scale_x_sdv_headshots( ..., league, expand = ggplot2::waiver(), guide = ggplot2::waiver(), position = "bottom", size = 20, id_system = "espn" ) scale_y_sdv_headshots( ..., league, expand = ggplot2::waiver(), guide = ggplot2::waiver(), position = "left", size = 30, id_system = "espn" )
... |
Other arguments passed to |
league |
A league key from |
expand |
Expansion limits for the axis. |
guide |
Guide for the axis. |
position |
Position of the axis. |
size |
The logo size in pixels. It is applied as height for an x-scale and as width for a y-scale. |
season |
|
id_system |
|
The scale translates team names into raw image HTML and places the
HTML as axis labels. Because of the way ggplots are constructed, it is
necessary to adjust the theme after calling this scale. This can be done
by calling theme_x_sdv() or theme_y_sdv() after any complete theme such
as ggplot2::theme_minimal(), which replaces every theme element. To set
the theme by hand, change the relevant axis.text and its position
children (axis.text.x.bottom, ...) to ggtext::element_markdown():
complete themes in 'ggplot2' 4 set those children themselves.
A ggplot2 scale object.
library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:8] df <- data.frame( random_value = runif(length(team_abbr), 0, 1), teams = team_abbr ) if (requireNamespace("ggtext", quietly = TRUE)) { ggplot(df, aes(x = teams, y = random_value)) + geom_col(aes(fill = teams), width = 0.5) + scale_fill_sdv(league = "nfl", alpha = 0.4) + scale_x_sdv(league = "nfl") + theme_minimal() + theme_x_sdv() }library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:8] df <- data.frame( random_value = runif(length(team_abbr), 0, 1), teams = team_abbr ) if (requireNamespace("ggtext", quietly = TRUE)) { ggplot(df, aes(x = teams, y = random_value)) + geom_col(aes(fill = teams), width = 0.5) + scale_fill_sdv(league = "nfl", alpha = 0.4) + scale_x_sdv(league = "nfl") + theme_minimal() + theme_x_sdv() }
These functions map team names to their team colors in color and fill aesthetics.
scale_color_sdv( league, which = c("primary", "secondary"), values = NULL, ..., aesthetics = "colour", breaks = ggplot2::waiver(), na.value = "grey50", guide = NULL, alpha = NA ) scale_colour_sdv( league, which = c("primary", "secondary"), values = NULL, ..., aesthetics = "colour", breaks = ggplot2::waiver(), na.value = "grey50", guide = NULL, alpha = NA ) scale_fill_sdv( league, which = c("primary", "secondary"), values = NULL, ..., aesthetics = "fill", breaks = ggplot2::waiver(), na.value = "grey50", guide = NULL, alpha = NA )scale_color_sdv( league, which = c("primary", "secondary"), values = NULL, ..., aesthetics = "colour", breaks = ggplot2::waiver(), na.value = "grey50", guide = NULL, alpha = NA ) scale_colour_sdv( league, which = c("primary", "secondary"), values = NULL, ..., aesthetics = "colour", breaks = ggplot2::waiver(), na.value = "grey50", guide = NULL, alpha = NA ) scale_fill_sdv( league, which = c("primary", "secondary"), values = NULL, ..., aesthetics = "fill", breaks = ggplot2::waiver(), na.value = "grey50", guide = NULL, alpha = NA )
league |
A league key from |
which |
One of |
values |
If |
... |
Other arguments passed to |
aesthetics |
The aesthetic to apply the scale to ( |
breaks |
Breaks for the scale. |
na.value |
Color for NA values. |
guide |
Guide function or name. |
alpha |
Factor to modify color transparency via |
A ggplot2 scale object.
library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:16] df <- data.frame( random_value = runif(length(team_abbr), 0, 1), teams = team_abbr ) ggplot(df, aes(x = teams, y = random_value)) + geom_col(aes(color = teams, fill = teams), width = 0.5) + scale_color_sdv(league = "nfl", which = "secondary") + scale_fill_sdv(league = "nfl", alpha = 0.4) + theme_minimal() + theme(axis.text.x = element_text(angle = 45, hjust = 1))library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:16] df <- data.frame( random_value = runif(length(team_abbr), 0, 1), teams = team_abbr ) ggplot(df, aes(x = teams, y = random_value)) + geom_col(aes(color = teams, fill = teams), width = 0.5) + scale_color_sdv(league = "nfl", which = "secondary") + scale_fill_sdv(league = "nfl", alpha = 0.4) + theme_minimal() + theme(axis.text.x = element_text(angle = 45, hjust = 1))
Replaces a categorical axis's tick labels with team logos.
sdv_axis_logos( p, teams, league, axis = c("x", "y"), size = 0.08, season = NULL, variant = "default", id_system = "auto", strict = FALSE )sdv_axis_logos( p, teams, league, axis = c("x", "y"), size = 0.08, season = NULL, variant = "default", id_system = "auto", strict = FALSE )
p |
A plotly object. |
teams |
The axis categories, in the chart's order (the team values the chart plots on that axis). |
league |
A league key from |
axis |
|
size |
Image size as a fraction of the plot area on the other axis. |
season |
|
variant |
|
id_system |
For headshots, as in |
strict |
If |
The plotly object (an htmlwidget).
if (requireNamespace("plotly", quietly = TRUE)) { teams <- c("KC", "BUF", "BAL") plotly::plot_ly(x = teams, y = c(11, 13, 12), type = "bar") |> sdv_axis_logos(teams, "nfl") }if (requireNamespace("plotly", quietly = TRUE)) { teams <- c("KC", "BUF", "BAL") plotly::plot_ly(x = teams, y = c(11, 13, 12), type = "bar") |> sdv_axis_logos(teams, "nfl") }
sdvplotR keeps the team index, the logo manifest and the NFL
headshot map in memory for the session, keeps the index and manifest on
disk (in tools::R_user_dir("sdvplotR", "cache")) for a day. This clears
them, and the image cache of 'ggpath' when 'ggpath' provides a way to, so
the next call reads the CDN again.
sdv_clear_cache()sdv_clear_cache()
Invisibly NULL, called for its side effect.
sdv_versions() for what is loaded now.
sdv_clear_cache()sdv_clear_cache()
A named colour vector for ggplot2::scale_colour_manual()
and friends. The R counterpart of sdvplot's palette().
sdv_color_palette( league, teams = NULL, which = c("primary", "secondary"), season = NULL, id_system = "auto", strict = FALSE )sdv_color_palette( league, teams = NULL, which = c("primary", "secondary"), season = NULL, id_system = "auto", strict = FALSE )
league |
A league key from |
teams |
Team identifiers, or |
which |
|
season |
|
id_system |
|
strict |
If |
A named character vector of hex colours, unresolved teams dropped.
sdv_color_palette("nfl", c("KC", "BUF", "SF"))sdv_color_palette("nfl", c("KC", "BUF", "SF"))
Sets the chart's trace colours to the teams' colours, in order.
sdv_colorway( p, league, teams = NULL, which = c("primary", "secondary"), season = NULL, id_system = "auto" )sdv_colorway( p, league, teams = NULL, which = c("primary", "secondary"), season = NULL, id_system = "auto" )
p |
A plotly object. |
league |
A league key from |
teams |
Team identifiers, or |
which |
|
season |
|
id_system |
For headshots, as in |
The plotly object (an htmlwidget).
if (requireNamespace("plotly", quietly = TRUE)) { plotly::plot_ly(type = "bar") |> sdv_colorway("nfl", c("KC", "BUF")) }if (requireNamespace("plotly", quietly = TRUE)) { plotly::plot_ly(type = "bar") |> sdv_colorway("nfl", c("KC", "BUF")) }
stats.nba.com / stats.wnba.com shot-chart data reports shot
locations in the NBA's legacy frame: tenths of a foot, origin at the
hoop, relative to the shooter's basket. hoopR's/wehoop's
load_nba_stats_shots() / load_wnba_stats_shots() ship these columns
as x_legacy/y_legacy (snake_case); the Shot_Chart_Detail element of
hoopR's nba_shotchartdetail() uses the same frame, in the
LOC_X/LOC_Y columns stats.nba.com returns (upper snake case). This
converts them (feet, not tenths) into the frame
sportyR::geom_basketball("nba") draws: origin at center court, baseline
at x = -47, basket on the left at x = -41.75.
provider = "euroleague" converts the Euroleague shot frame of hoopR's
euroleague_game_points() (coord_x/coord_y) instead, onto the FIBA
court sdv_surface("fiba") draws, in meters.
sdv_court_coords( data, x_column = "x_legacy", y_column = "y_legacy", provider = "nba" )sdv_court_coords( data, x_column = "x_legacy", y_column = "y_legacy", provider = "nba" )
data |
A data frame with shot-location columns, e.g. from
|
x_column |
String naming the column holding the stats-API |
y_column |
String naming the column holding the stats-API |
provider |
The frame of |
The NBA legacy shot-location frame (LOC_X/LOC_Y, or
x_legacy/y_legacy; tenths of a foot, hoop at the origin, relative to
the shooter's basket) maps with negative x as the shooter's left corner:
court_y is x_column / 10 with no sign flip, so a left-corner three
lands at negative court_y (the TV-bottom sideline), which is the
shooter's left when facing the TV-left basket. Verified on real 2022-23
shotchartdetail data (Left Corner 3 LOC_X -249..-221, Right Corner 3
+221..+248).
Shots land on sportyR's TV-left half, so draw half-court charts with
sportyR::geom_basketball("nba", display_range = "defense") or the full
court; display_range = "offense" shows the TV-right half and none of
the shots.
The converted points also fit sportyR's "wnba" and "ncaa" courts,
which share the "nba" court's 94-foot floor and 5.25-foot basket
offset. The input must still be in the NBA legacy frame (tenths of a
foot, hoop at the origin: x_legacy/y_legacy or LOC_X/LOC_Y).
Don't pass ESPN coordinate_x/coordinate_y from hoopR/wehoop
play-by-play: they are already in feet on a center-court frame.
The Euroleague frame (provider = "euroleague"; measured on real games,
2026-10-06) is integer centimeters with the hoop at the origin, both
teams mapped onto one basket, coord_y growing away from the baseline
toward the court, and free throws encoded as coord_x = coord_y = -1
(a sentinel, not a location), which become NA. The FIBA court is
28 x 15 m with its basket 1.575 m from the baseline, so
court_x = -12.425 + coord_y / 100 and court_y = coord_x / 100. Which
sideline is positive coord_x is unverified, so a chart may be
left-right mirrored; the court is symmetric, so distances and zones are
unaffected.
Coordinate columns must be numeric, or character holding numbers, which
is coerced (nba_shotchartdetail() returns every column as character).
Factors, TRUE/FALSE and strings that aren't numbers (such as "" or
"NA") raise an error. Missing values stay NA, and an all-NA column
(even a logical one) gives NA coordinates.
data with court_x and court_y added (existing columns of
those names are replaced); every other input column is kept as-is:
| col_name | type | description |
| court_x | numeric | Along the court: the basket at -41.75 ft (nba) or -12.425 m (euroleague), half court at 0 |
| court_y | numeric | Across the court: -25 to 25 ft (nba; negative = shooter's left) or -7.5 to 7.5 m (euroleague) |
shots <- data.frame(x_legacy = c(-224, 240), y_legacy = c(39, 29)) sdv_court_coords(shots) # Euroleague shots (hoopR::euroleague_game_points() columns) onto the FIBA court euro <- data.frame(coord_x = c(0, 12, 650, -1), coord_y = c(0, 422, 50, -1)) sdv_court_coords(euro, "coord_x", "coord_y", provider = "euroleague") if (requireNamespace("sportyR", quietly = TRUE)) { library(ggplot2) euro <- sdv_court_coords(euro, "coord_x", "coord_y", provider = "euroleague") sdv_surface("fiba", display_range = "defense") + geom_point(aes(court_x, court_y), data = euro, colour = "red", size = 3, na.rm = TRUE) }shots <- data.frame(x_legacy = c(-224, 240), y_legacy = c(39, 29)) sdv_court_coords(shots) # Euroleague shots (hoopR::euroleague_game_points() columns) onto the FIBA court euro <- data.frame(coord_x = c(0, 12, 650, -1), coord_y = c(0, 422, 50, -1)) sdv_court_coords(euro, "coord_x", "coord_y", provider = "euroleague") if (requireNamespace("sportyR", quietly = TRUE)) { library(ggplot2) euro <- sdv_court_coords(euro, "coord_x", "coord_y", provider = "euroleague") sdv_surface("fiba", display_range = "defense") + geom_point(aes(court_x, court_y), data = euro, colour = "red", size = 3, na.rm = TRUE) }
Real standings for one completed season in two leagues, one row per team:
the 2025 NFL season and the 2025-26 NBA season. The reference examples run on
it, so the table and plot helpers are shown on sports data. Each team is
the abbreviation sdv_teams() lists, so it works as the team input of
every logo, color and headshot helper as it is.
sdv_example_standingssdv_example_standings
A tibble with 62 rows (32 NFL teams, then 30 NBA teams), ordered by league, conference, division and division finish, and 16 columns:
"nfl" or "nba", the league value the helpers take.
2025 for the NFL; 2026 for the NBA, whose 2025-26
season goes by its ending year as in 'hoopR'.
Team abbreviation.
ESPN team id.
Full team name.
"AFC" or "NFC"; "Eastern" or "Western".
Division, as "AFC East" or "Atlantic".
The regular-season record. NBA games can't end
tied, so ties is 0 there.
Winning percentage, a tie counting as half a win, rounded to three decimals.
Regular-season points scored and allowed.
Final place in the conference with the league's tiebreakers applied: the NFL's playoff seeds are 1 to 7, the NBA's playoff places 1 to 6 and its play-in places 7 to 10.
Postseason wins, not counting the NBA's play-in;
NA for a team that missed the playoffs.
Regular-season wins the season before: the NFL's 2024 and the NBA's 2024-25.
Built by
data-raw/sdv_examples.R.
NFL: the nflverse schedules release, nflreadr::load_schedules(2025), with the standings and
conference ranks from nflseedR::nfl_standings(). NBA: the
sportsdataverse-data team box release, hoopR::load_nba_team_box(2026),
counting standings games only (not the NBA Cup final or the All-Star
games), with divisions and conference ranks from ESPN's standings (the
endpoint hoopR::espn_nba_standings() reads), whose records the script
checks against the box scores. last_season_wins comes from the same
loaders one season back. Team names and ESPN ids come from
sdvplotR's team reference.
# one division, in finishing order subset(sdv_example_standings, division == "NFC West", c(team, wins:win_pct)) # the teams that reached the playoffs playoffs <- subset(sdv_example_standings, !is.na(playoff_wins)) table(playoffs$league) # with logos, which are downloaded subset(sdv_example_standings, division == "Atlantic", c(team, wins, losses)) |> gt::gt() |> gt_sdv_logos(columns = "team", league = "nba")# one division, in finishing order subset(sdv_example_standings, division == "NFC West", c(team, wins:win_pct)) # the teams that reached the playoffs playoffs <- subset(sdv_example_standings, !is.na(playoff_wins)) table(playoffs$league) # with logos, which are downloaded subset(sdv_example_standings, division == "Atlantic", c(team, wins, losses)) |> gt::gt() |> gt_sdv_logos(columns = "team", league = "nba")
The headshot image URL for player ids, as every sdvplotR
headshot helper draws it. The R counterpart of sdvplot's headshot_url().
sdv_headshot_url(player_id, league, id_system = "espn")sdv_headshot_url(player_id, league, id_system = "espn")
player_id |
A vector of player ids. |
league |
A league key from |
id_system |
|
A character vector the length of player_id: the URL, or NA for
a missing or malformed id or (gsis) one not in the map.
sdv_headshot_url(3139477, "nfl") sdv_headshot_url("2544", "nba", id_system = "league") # nflverse gsis ids read the published headshot map sdv_headshot_url("00-0033873", "nfl", id_system = "gsis")sdv_headshot_url(3139477, "nfl") sdv_headshot_url("2544", "nba", id_system = "league") # nflverse gsis ids read the published headshot map sdv_headshot_url("00-0033873", "nfl", id_system = "gsis")
The SportsDataverse league keys every league argument takes:
the leagues of the shared team index sdvplot (Python) and sdvplot-js use.
sdv_leagues()sdv_leagues()
A sorted character vector.
sdv_teams() for each league's teams.
sdv_leagues()sdv_leagues()
The image URL behind every sdvplotR geom, theme element and
table helper: the SportsDataverse archive's copy of the team's mark
(content-addressed and immutable), chosen for the season. The R
counterpart of sdvplot's logo_url().
sdv_logo_url( team, league, season = NULL, variant = "default", mark_type = "logo", id_system = "auto", strict = FALSE )sdv_logo_url( team, league, season = NULL, variant = "default", mark_type = "logo", id_system = "auto", strict = FALSE )
team |
A vector of team identifiers, or conference / league keys
( |
league |
A league key from |
season |
|
variant |
|
mark_type |
|
id_system |
|
strict |
If |
A character vector the length of team: the URL, or NA (with a
warning) where the team does not resolve or has no such mark.
sdv_headshot_url(), sdv_marks().
sdv_logo_url(c("KC", "Buffalo Bills", "OAK"), "nfl") sdv_logo_url("NYJ", "nfl", variant = "scoreboard") sdv_logo_url("QUE", "nhl", season = 1990) sdv_logo_url("KC", "nfl", mark_type = "wordmark") sdv_logo_url("SEC", "cfb")sdv_logo_url(c("KC", "Buffalo Bills", "OAK"), "nfl") sdv_logo_url("NYJ", "nfl", variant = "scoreboard") sdv_logo_url("QUE", "nhl", season = 1990) sdv_logo_url("KC", "nfl", mark_type = "wordmark") sdv_logo_url("SEC", "cfb")
The logo manifest's rows for one team (logos and wordmarks,
every variant, source and era), best first: the rows the logo helpers
choose from. The R counterpart of sdvplot's marks().
sdv_marks(team, league, season = NULL, id_system = "auto")sdv_marks(team, league, season = NULL, id_system = "auto")
team |
One team identifier, or a conference or league key ( |
league |
A league key from |
season |
|
id_system |
|
A data frame of manifest rows with team_id, variant,
mark_type, valid_from, valid_to (the effective season range),
source, source_rank and archive_url.
m <- sdv_marks("KC", "nfl") table(m$variant)m <- sdv_marks("KC", "nfl") table(m$variant)
Every soccer data provider uses its own coordinate frame. Opta
and Wyscout run 0-100 on both axes and are not to scale, StatsBomb uses
120 x 80, tracking providers use meters or centimeters from the center
spot, and ESPN reports the distance from the attacked goal as a fraction
of half the pitch. sdv_pitch_coords() converts any of them to one frame:
meters, origin at the center spot, a regulation 105 x 68 m pitch,
attacking toward +x, with +y on the attacker's left. That is the pitch
sdv_surface() draws for "soccer".
sdv_pitch_coords( data, provider, x_column = NULL, y_column = NULL, flip = NULL, pitch_length = NULL, pitch_width = NULL )sdv_pitch_coords( data, provider, x_column = NULL, y_column = NULL, flip = NULL, pitch_length = NULL, pitch_width = NULL )
data |
A data frame of events. |
provider |
The coordinate frame of |
x_column, y_column
|
Strings naming the coordinate columns. |
flip |
|
pitch_length, pitch_width
|
The venue's size in meters, for tracking providers only (the Laws of the Game allow 90-120 by 45-90). |
The conversion is piecewise-linear between pitch landmarks: goal
line, six-yard line, penalty spot, box edge and halfway line along the
pitch; touchline, box side, six-yard side and post across it. A shot on
the edge of an Opta box therefore lands on the edge of the regulation box,
not 1.35 m outside it as a linear rescale would put it. Points beyond the
outermost landmark are extrapolated from the nearest segment, not clamped.
The landmark values come from 'mplsoccer' and ship in
system.file("extdata", "pitch_landmarks.csv", package = "sdvplotR").
Tracking providers ("tracab", "skillcorner", "secondspectrum",
"metrica") are measured on the venue's real pitch, so they need
pitch_length and pitch_width. ESPN frames are derived from the Opta frame:
opta_x = 100 - 50 * x and opta_y = 100 * (1 - y). ESPN marks an event
with no location as (0, 0), which becomes NA.
Event providers record every action as if the team attacked left to
right. To draw two teams (or two halves of tracking data) attacking
opposite ends, flip them: a flipped row is turned half a turn, so its
x and y both change sign and each wing stays on its own side.
data with pitch_x and pitch_y added (existing columns of those
names are replaced); every other input column is kept as-is:
| col_name | type | description |
| pitch_x | numeric | Meters along the pitch: -52.5 is the defended goal line, 52.5 the attacked one, 0 the halfway line |
| pitch_y | numeric | Meters across the pitch: -34 to 34; positive = the attacker's left |
sdv_surface() draws the pitch; ggsoccer::rescale_coordinates()
converts between provider frames without the regulation-pitch output.
shots <- data.frame(x = c(88.5, 83, 50), y = c(50, 21.1, 100)) sdv_pitch_coords(shots, "opta") # two teams attacking opposite ends shots$away <- c(FALSE, TRUE, FALSE) sdv_pitch_coords(shots, "opta", flip = "away") # tracking data, measured on the venue's pitch tracking <- data.frame(x = c(-4150, 3600), y = c(0, -2016)) sdv_pitch_coords(tracking, "tracab", pitch_length = 105, pitch_width = 68)shots <- data.frame(x = c(88.5, 83, 50), y = c(50, 21.1, 100)) sdv_pitch_coords(shots, "opta") # two teams attacking opposite ends shots$away <- c(FALSE, TRUE, FALSE) sdv_pitch_coords(shots, "opta", flip = "away") # tracking data, measured on the venue's pitch tracking <- data.frame(x = c(-4150, 3600), y = c(0, -2016)) sdv_pitch_coords(tracking, "tracab", pitch_length = 105, pitch_width = 68)
Turns whatever team identifiers you have (abbreviations, full
names, ESPN, nflverse, MLB Stats, nba_api, HockeyTech, CFBD, Sports
Reference and other ids) into the index's canonical team_id, never
guessing. Every sdvplotR helper that takes a team resolves it this way.
The R counterpart of sdvplot's resolve(), and it gives the same answers.
sdv_resolve(x, league, season = NULL, id_system = "auto", strict = FALSE)sdv_resolve(x, league, season = NULL, id_system = "auto", strict = FALSE)
x |
A vector of team identifiers (character, numeric or factor). |
league |
A league key from |
season |
|
id_system |
|
strict |
If |
A character vector of team_ids, the length of x.
sdv_suggest() for a value that did not resolve, sdv_teams().
sdv_resolve(c("KC", "Kansas City Chiefs", "OAK"), "nfl") sdv_resolve("QUE", "nhl", season = 1990) sdv_resolve(c("Iowa St.", "Miami (OH)"), "mbb")sdv_resolve(c("KC", "Kansas City Chiefs", "OAK"), "nfl") sdv_resolve("QUE", "nhl", season = 1990) sdv_resolve(c("Iowa St.", "Miami (OH)"), "mbb")
Up to n candidate teams for a misspelled or unknown value,
best first. It never picks one for you: similar names can be different
teams. The R counterpart of sdvplot's suggest().
sdv_suggest(x, league, n = 5)sdv_suggest(x, league, n = 5)
x |
One team value. |
league |
A league key from |
n |
The most candidates to return. |
A data frame with team_id and name, empty when nothing is close.
sdv_suggest("Kansas Cty Chiefs", "nfl", n = 2)sdv_suggest("Kansas Cty Chiefs", "nfl", n = 2)
Draws a regulation court, field or rink with 'sportyR' and,
given a team, paints a few of its features in that team's colors from
sdv_team_colors(). The result is a ggplot, so data layers go on top.
These are stylized surfaces built from team colors, not the team's real court, field or rink design: no dataset of real team surface designs (paint colors, center logos, end zone art, special-event floors) exists yet.
sdv_surface(league, team = NULL, season = NULL, center_logo = FALSE, ...)sdv_surface(league, team = NULL, season = NULL, center_logo = FALSE, ...)
league |
A league with a playing surface: one of
Python's |
||||||||||||||||||||||||||||||
team |
|
||||||||||||||||||||||||||||||
season |
A season for the team's colors and center logo (see
|
||||||||||||||||||||||||||||||
center_logo |
If |
||||||||||||||||||||||||||||||
... |
Passed to the 'sportyR' geom: |
With a team, these features change; everything else keeps
'sportyR”s regulation colors, so the court stays wood, the field green
and the ice white:
Basketball: the painted area and the court apron take the primary color. The lines drawn inside the paint (restricted arc, free-throw circle dashes, lower defensive boxes) turn black or white, whichever contrasts more with it.
Football: both end zones take the primary color.
Hockey: the center line, center faceoff circle and center faceoff spot take the primary color, or the secondary where the primary is too pale to read on white ice (under 3:1 contrast); the boards take the primary.
Baseball: nothing. No part of a regulation infield is team-colored (the green background is the outfield grass), so the team is checked and the surface stays 'sportyR”s.
Soccer and FIBA surfaces are drawn in meters. "soccer" defaults to a
regulation 105 x 68 m pitch, the frame sdv_pitch_coords() converts to;
'sportyR”s own "fifa" default is FIFA's 120 x 90 m maximum. Soccer takes a
team for its center logo (18.3 m, the center circle); the pitch keeps its
regulation colors. FIBA takes no team yet.
Surfaces use 'sportyR”s coordinates: the origin at the center, in feet
(yards for football, meters for soccer and FIBA). The center logo is sized
in those units (12 feet on a court, 10 yards on a field, 24 feet on a
rink, 18.3 m on a pitch) and follows
x_trans, y_trans, rotation and the unit arguments.
A ggplot object (ggplot2::ggplot()) with coord_fixed(); add
layers with +.
if (requireNamespace("sportyR", quietly = TRUE)) { library(ggplot2) # in a team's colors, with its logo at center court, and shots on top shots <- data.frame(x = c(-40, -35, 30), y = c(5, -12, 0)) sdv_surface("nba", "BOS", center_logo = TRUE) + geom_point(aes(x, y), data = shots, color = "red", size = 3) }if (requireNamespace("sportyR", quietly = TRUE)) { library(ggplot2) # in a team's colors, with its logo at center court, and shots on top shots <- data.frame(x = c(-40, -35, 30), y = c(5, -12, 0)) sdv_surface("nba", "BOS", center_logo = TRUE) + geom_point(aes(x, y), data = shots, color = "red", size = 3) }
Primary and secondary colours (hex) for teams, resolved from
any identifier sdv_resolve() accepts. The R counterpart of sdvplot's
team_colors().
sdv_team_colors( league, team = NULL, which = c("primary", "secondary", "all"), season = NULL, id_system = "auto", strict = FALSE, include_conferences = FALSE )sdv_team_colors( league, team = NULL, which = c("primary", "secondary", "all"), season = NULL, id_system = "auto", strict = FALSE, include_conferences = FALSE )
league |
A league key from |
team |
Team identifiers, or |
which |
|
season |
|
id_system |
|
strict |
If |
include_conferences |
With |
With team given, a character vector named by team (NA where a
team does not resolve); for which = "all", "primary, secondary"
strings. With team = NULL, a vector named by abbreviation (the
team_id where a team has none), or for which = "all" a data frame:
| col_name | type | description |
| team_id | character | Canonical team id |
| abbr | character | Abbreviation (NA where the league has none) |
| name | character | Full name |
| primary | character | Primary colour (hex) |
| secondary | character | Secondary colour (hex; NA where none)
|
sdv_team_colors("nfl", "KC") sdv_team_colors("nfl", c("KC", "Buffalo Bills"), which = "all") sdv_team_colors("ahl", which = "primary")sdv_team_colors("nfl", "KC") sdv_team_colors("nfl", c("KC", "Buffalo Bills"), which = "all") sdv_team_colors("ahl", which = "primary")
A factor of teams as given, levels ordered by each team's
abbreviation; values that do not resolve are NA (with the resolver's
warning), so downstream ggplot2 scales drop them.
sdv_team_factor(teams, league, season = NULL, id_system = "auto")sdv_team_factor(teams, league, season = NULL, id_system = "auto")
teams |
Character vector of team names. |
league |
A league key from |
season, id_system
|
Passed to |
A factor of teams.
suppressWarnings(sdv_team_factor(c("KC", "BUF", "invalid"), league = "nfl"))suppressWarnings(sdv_team_factor(c("KC", "BUF", "invalid"), league = "nfl"))
This function sets up a ggplot to visualize team tiers across any league supported by sdvplotR. Teams are organized by performance or other metrics into labeled tiers.
sdv_team_tiers( data, league, title = glue::glue("{toupper(league)} Team Tiers"), subtitle = glue::glue("created with the #sdvplotR Tiermaker"), caption = NULL, tier_desc = c(`1` = "Elite", `2` = "Very Good", `3` = "Medium", `4` = "Bad", `5` = "What are they doing?", `6` = "", `7` = ""), presort = FALSE, alpha = 0.8, width = 0.075, no_line_below_tier = NULL, devel = FALSE, theme = c("dark", "light"), variant = "auto", season = NULL, id_system = "auto", strict = FALSE )sdv_team_tiers( data, league, title = glue::glue("{toupper(league)} Team Tiers"), subtitle = glue::glue("created with the #sdvplotR Tiermaker"), caption = NULL, tier_desc = c(`1` = "Elite", `2` = "Very Good", `3` = "Medium", `4` = "Bad", `5` = "What are they doing?", `6` = "", `7` = ""), presort = FALSE, alpha = 0.8, width = 0.075, no_line_below_tier = NULL, devel = FALSE, theme = c("dark", "light"), variant = "auto", season = NULL, id_system = "auto", strict = FALSE )
data |
A data frame that must include the variables |
league |
A league key from |
title |
The title of the plot. If |
subtitle |
The subtitle of the plot. If |
caption |
The caption of the plot. If |
tier_desc |
A named vector of tier descriptions. Names must equal the
tier numbers from |
presort |
If |
alpha |
The alpha channel of the logos (transparency level). |
width |
The desired width of the logo in |
no_line_below_tier |
Vector of tier numbers. The function won't draw tier separation lines below these tiers. |
devel |
Determines if logos shall be rendered. If |
theme |
|
variant |
The logo variant to draw. |
season, id_system, strict
|
Passed to |
A ggplot object.
library(sdvplotR) library(ggplot2) # Build the team tiers data df <- data.frame( tier_no = c(1, 1, 2, 2, 3, 3), team = c("KC", "DET", "BAL", "PHI", "BUF", "GB") ) # Plot team tiers, each team's primary logo on white sdv_team_tiers(df, league = "nfl", theme = "light")library(sdvplotR) library(ggplot2) # Build the team tiers data df <- data.frame( tier_no = c(1, 1, 2, 2, 3, 3), team = c("KC", "DET", "BAL", "PHI", "BUF", "GB") ) # Plot team tiers, each team's primary logo on white sdv_team_tiers(df, league = "nfl", theme = "light")
One row per team: its canonical team_id (the key every
helper resolves to), names, abbreviation, conference and colours. The R
counterpart of sdvplot's teams().
sdv_teams(league = NULL, include_conferences = FALSE)sdv_teams(league = NULL, include_conferences = FALSE)
league |
A league key from |
include_conferences |
Also list the conference and league rows (the
college conferences, and the AFC, NFC and NFL). Their |
A data frame:
| col_name | type | description |
| league | character | League key |
| team_id | character | Canonical team id (the ESPN id where ESPN has the team) |
| abbr | character | Abbreviation (NA where the league has none) |
| name | character | Full name |
| short_name | character | Short display name |
| location | character | City or school |
| program | character | NA for a team; "conference" or "league" for those rows |
| conference_id | character | The team's conference row team_id |
| conference | character | Conference name |
| color_primary | character | Primary colour (hex) |
| color_secondary | character | Secondary colour (hex) |
| color_source | character | "nflverse", "espn", "logo", "cbbplotR" or "fallback"
|
sdv_teams("nfl") sdv_teams("cfb", include_conferences = TRUE)sdv_teams("nfl") sdv_teams("cfb", include_conferences = TRUE)
Which team index and logo manifest the session has loaded and
where they came from: "live" (the SportsDataverse CDN, or the disk cache
within a day of it), "cache" (an older disk copy, after a failed
refresh) or "snapshot" (the copy bundled with the package: offline,
with options(sdvplotR.offline = TRUE), or during a CRAN check). The R
counterpart of sdvplot's versions().
sdv_versions()sdv_versions()
A list with package, index_version, index_source,
manifest_rows and manifest_source.
sdv_versions()sdv_versions()
gt_theme_*() table themesA lookup of the background color each gt_theme_* function sets, used to match
a saved image's canvas to the table sitting on it. gt_save_crop() and
gt_social_crop() pad the image using their own bg argument, and a mismatch
shows up as a border around the table.
theme_bgtheme_bg
A tibble with one row per theme, and one per style for the themes
that take a style argument:
The theme function name.
The style value the row applies to ("light" or
"dark") for gt_theme_sdv(), gt_theme_sofa() and gt_theme_tier(), or "" for themes
without one.
The background color the theme applies, as a hex code.
Read back from each theme's table.background.color by
data-raw/theme_bg.R.
gt_theme_drench() takes its background from its color argument and
gt_theme_broadsheet() from its paper argument; their rows hold the
default.
gt_save_crop(), gt_social_crop().
# look up the background a theme uses, then match the canvas to it bg <- theme_bg$bg[theme_bg$theme == "gt_theme_gtutils"] bg # saving needs a headless Chrome (webshot2) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins:points_against) ) gt::gt(nfc_west) |> gt_theme_gtutils() |> gt_save_crop(tempfile(fileext = ".png"), bg = bg)# look up the background a theme uses, then match the canvas to it bg <- theme_bg$bg[theme_bg$theme == "gt_theme_gtutils"] bg # saving needs a headless Chrome (webshot2) nfc_west <- subset( sdv_example_standings, division == "NFC West", c(team_name, wins:points_against) ) gt::gt(nfc_west) |> gt_theme_gtutils() |> gt_save_crop(tempfile(fileext = ".png"), bg = bg)
These functions are convenience wrappers around a theme call
that activates markdown in x-axis and y-axis labels using
ggtext::element_markdown().
theme_x_sdv() theme_y_sdv()theme_x_sdv() theme_y_sdv()
These functions set ggtext::element_markdown() on axis.text.x
and its position children axis.text.x.bottom / axis.text.x.top
(theme_x_sdv()), or on axis.text.y, axis.text.y.left and
axis.text.y.right (theme_y_sdv()). Complete themes in 'ggplot2' 4
(theme_minimal(), ...) set those children themselves, and a markdown
parent alone would not replace them. Add these after any complete theme,
which replaces every element. They are made to be used in conjunction
with scale_x_sdv() and scale_y_sdv() respectively.
A ggplot2 theme object.
library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:8] df <- data.frame( random_value = runif(length(team_abbr), 0, 1), teams = team_abbr ) if (requireNamespace("ggtext", quietly = TRUE)) { ggplot(df, aes(x = teams, y = random_value)) + geom_col(width = 0.5) + scale_x_sdv(league = "nfl") + theme_minimal() + theme_x_sdv() }library(sdvplotR) library(ggplot2) team_abbr <- sdv_teams("nfl")$abbr[1:8] df <- data.frame( random_value = runif(length(team_abbr), 0, 1), teams = team_abbr ) if (requireNamespace("ggtext", quietly = TRUE)) { ggplot(df, aes(x = teams, y = random_value)) + geom_col(width = 0.5) + scale_x_sdv(league = "nfl") + theme_minimal() + theme_x_sdv() }