Skip to main content

Cell kinds

A column's kind decides what its cells show: the value as written, a formatted number, a colour, a logo. sdvtables has 21 kinds, one c.<kind>(key, options) call each, with sdvplotR's defaults; all of them render on the same eight AFC teams, so you can compare them directly. Kinds that look a team up (logo, wordmark, the team colours) need the league loaded, which prepare and renderHTMLAsync do.

Text and numbers​

text shows the value as written; int and num format numbers (digits, a forced sign, a prefix or suffix), and a missing value stays blank.

AFC, 2024
TeamQuarterbackDivision
KCPatrick MahomesWest
LACJustin HerbertWest
DENBo NixWest
LVGardner MinshewWest
BUFJosh AllenEast
MIATua TagovailoaEast
NYJAaron RodgersEast
NEDrake MayeEast
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

const spec = defineTable<Standing>()
.columns((c) => [
c.text("team"),
c.text("qb", { label: "Quarterback" }),
c.text("division", { align: "center" }),
])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024
TeamWLPFPA
KC152385326
LAC116402301
DEN107425311
LV413309434
BUF134525368
MIA89345364
NYJ512338404
NE413289417
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

const spec = defineTable<Standing>()
.columns((c) => [
c.text("team"),
c.int("wins", { label: "W" }),
c.int("losses", { label: "L" }),
c.int("pf", { label: "PF" }),
c.int("pa", { label: "PA" }),
])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024
TeamNet EPA/playPoints for
KC+0.063385 pts
LAC+0.101402 pts
DEN+0.108425 pts
LV−0.146309 pts
BUF+0.190525 pts
MIA−0.019345 pts
NYJ−0.045338 pts
NE289 pts
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// New England has no net EPA on file (null): the cell stays blank.
const spec = defineTable<Standing>()
.columns((c) => [
c.text("team"),
c.num("net_epa", { label: "Net EPA/play", digits: 3, forceSign: true }),
c.num("pf", { label: "Points for", digits: 0, suffix: " pts" }),
])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);

pct multiplies a share by 100, rank writes ordinals, delta(from, to) shows to - from with an arrow, and tally writes a record from several columns, optionally with one part's share.

AFC, 2024
TeamWinsLossesWin %
KC15288.2%
LAC11664.7%
DEN10758.8%
LV41323.5%
BUF13476.5%
MIA8947.1%
NYJ51229.4%
NE41323.5%
import { STANDINGS } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// pct multiplies by 100 (scale: true, the default): pass shares, not percentages.
const rows = STANDINGS.map((r) => ({ ...r, win_share: r.wins / (r.wins + r.losses + r.ties) }));
const spec = defineTable<(typeof rows)[number]>()
.columns((c) => [c.text("team"), c.int("wins"), c.int("losses"), c.pct("win_share", { label: "Win %" })])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, rows);
AFC, 2024: league-wide SRS rank
TeamSRS rank
KC10th
LAC9th
DEN8th
LV26th
BUF4th
MIA21st
NYJ24th
NE29th
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

const spec = defineTable<Standing>()
.columns((c) => [c.text("team"), c.rank("srs_rank", { label: "SRS rank" })])
.title("AFC, 2024: league-wide SRS rank")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024
TeamPFPoint diff.
KC385▲ 59
LAC402▲ 101
DEN425▲ 114
LV309▼ 125
BUF525▲ 157
MIA345▼ 19
NYJ338▼ 66
NE289▼ 128
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// delta(from, to) shows to - from: here points for minus points against, green up and red down.
const spec = defineTable<Standing>()
.columns((c) => [
c.text("team"),
c.int("pf", { label: "PF" }),
c.delta("pa", "pf", { label: "Point diff.", decimals: 0, arrows: true }),
])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024: W-L-T (win share)
TeamRecord
KC15-2-0 (88.2%)
LAC11-6-0 (64.7%)
DEN10-7-0 (58.8%)
LV4-13-0 (23.5%)
BUF13-4-0 (76.5%)
MIA8-9-0 (47.1%)
NYJ5-12-0 (29.4%)
NE4-13-0 (23.5%)
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

const spec = defineTable<Standing>()
.columns((c) => [
c.text("team"),
c.tally(["wins", "losses", "ties"], { label: "Record", share: true, shareOf: 0 }),
])
.title("AFC, 2024: W-L-T (win share)")
.build();
await renderHTMLAsync(spec, STANDINGS);

Colour on a scale​

colorPills puts each value in a pill coloured on a scale and colorRanks fills the cell, green to red (RANK_PALETTE; reverse when lower is better). Pass a domain so two tables share a scale.

AFC, 2024
TeamNet EPA/play
KC0.063
LAC0.101
DEN0.108
LV-0.146
BUF0.190
MIA-0.019
NYJ-0.045
NE
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// A domain fixes the scale so tables can be compared; without one the pills span the observed range and warn.
const spec = defineTable<Standing>()
.columns((c) => [
c.text("team"),
c.colorPills("net_epa", { label: "Net EPA/play", digits: 3, domain: [-0.2, 0.2] }),
])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024
TeamPoints forPoints against
KC385326
LAC402301
DEN425311
LV309434
BUF525368
MIA345364
NYJ338404
NE289417
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// The default palette is RANK_PALETTE (green to red); reverse it when lower is better.
const spec = defineTable<Standing>()
.columns((c) => [
c.text("team"),
c.colorRanks("pf", { label: "Points for", domain: [280, 530], reverse: true }),
c.colorRanks("pa", { label: "Points against", domain: [280, 530] }),
])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);

percentileBar places a marker on a track; colorResults fills a whole row by its W or L.

AFC, 2024
TeamWin %
KC
88
LAC
65
DEN
59
LV
24
BUF
76
MIA
47
NYJ
29
NE
24
import { STANDINGS } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// With scale "auto" (the default), values that are all in [0, 1] are read as shares of the domain.
const rows = STANDINGS.map((r) => ({ ...r, win_share: r.wins / (r.wins + r.losses + r.ties) }));
const spec = defineTable<(typeof rows)[number]>()
.columns((c) => [c.text("team"), c.percentileBar("win_share", { label: "Win %", domain: [0, 100] })])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, rows);
AFC, 2024: final regular-season game
TeamQbLast game
KCPatrick MahomesL
LACJustin HerbertW
DENBo NixW
LVGardner MinshewL
BUFJosh AllenL
MIATua TagovailoaL
NYJAaron RodgersW
NEDrake MayeW
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// The cell holds W or L; the whole row takes the win or loss fill.
const spec = defineTable<Standing>()
.columns((c) => [c.text("team"), c.text("qb"), c.colorResults("result_last", { label: "Last game" })])
.title("AFC, 2024: final regular-season game")
.build();
await renderHTMLAsync(spec, STANDINGS);

Flags​

highlight marks the cells that match a predicate, highlightNa marks missing values, and indicatorBox fills a box for the values listed as truthy.

AFC, 2024: 11 or more wins
TeamWinsLosses
KC152
LAC116
DEN107
LV413
BUF134
MIA89
NYJ512
NE413
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// The rule is data (a predicate), not a function, so the spec stays serializable.
const spec = defineTable<Standing>()
.columns((c) => [
c.text("team"),
c.highlight("wins", { key: "wins", op: ">=", value: 11 }, { label: "Wins", bold: true }),
c.int("losses"),
])
.title("AFC, 2024: 11 or more wins")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024
TeamNet EPA/play
KC0.063
LAC0.101
DEN0.108
LV-0.146
BUF0.19
MIA-0.019
NYJ-0.045
NEn/a
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// New England's net EPA is null in the sample data.
const spec = defineTable<Standing>()
.columns((c) => [
c.text("team"),
c.highlightNa("net_epa", { label: "Net EPA/play", missingText: "n/a", italic: true }),
])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024
TeamWon week 18
KC
LAC
DEN
LV
BUF
MIA
NYJ
NE
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// truthy lists the values that fill the box; everything else gets the neutral box.
const spec = defineTable<Standing>()
.columns((c) => [c.text("team"), c.indicatorBox("result_last", { label: "Won week 18", truthy: ["W"] })])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);

Teams and players​

logo and wordmark look the team up in the league data and show its archived mark; headshot builds an ESPN headshot from the player id alone, and image shows any URL a row holds.

AFC, 2024
TeamDivision
West
West
West
West
East
East
East
East
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// renderHTMLAsync loads the NFL shard first; the cell holds the archive URL, nothing is fetched to render it.
const spec = defineTable<Standing>()
.columns((c) => [c.logo("team", { league: "nfl", includeName: true }), c.text("division")])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024
TeamWinsLosses
Kansas City Chiefs152
Los Angeles Chargers116
Denver Broncos107
Las Vegas Raiders413
Buffalo Bills134
Miami Dolphins89
New York Jets512
New England Patriots413
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

const spec = defineTable<Standing>()
.columns((c) => [
c.wordmark("team", { league: "nfl", label: "Team", height: 24 }),
c.int("wins"),
c.int("losses"),
])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC starting quarterbacks, 2024
QuarterbackTeam
3139477Patrick MahomesKC
4038941Justin HerbertLAC
4426338Bo NixDEN
4038524Gardner MinshewLV
3918298Josh AllenBUF
4241479Tua TagovailoaMIA
8439Aaron RodgersNYJ
4431452Drake MayeNE
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// ESPN headshot URLs are built from the id alone: no shard to load.
const spec = defineTable<Standing>()
.columns((c) => [
c.headshot("qb_espn_id", { league: "nfl", label: "" }),
c.text("qb", { label: "Quarterback" }),
c.text("team"),
])
.title("AFC starting quarterbacks, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024
TeamQb
KCKCPatrick Mahomes
LACLACJustin Herbert
DENDENBo Nix
LVLVGardner Minshew
BUFBUFJosh Allen
MIAMIATua Tagovailoa
NYJNYJAaron Rodgers
NENEDrake Maye
import { STANDINGS } from "@sportsdataverse/examples/data";
import { loadLeague, logoUrlSync } from "@sportsdataverse/sdvplot";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// image draws the URL the row holds; here sdvplot's archive logo URL, added to each row.
await loadLeague("nfl");
const rows = STANDINGS.map((r) => ({ ...r, logo_url: logoUrlSync(r.team, "nfl") ?? null }));
const spec = defineTable<(typeof rows)[number]>()
.columns((c) => [
c.image("logo_url", { label: "", height: "40px", alt: "team" }),
c.text("team"),
c.text("qb"),
])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, rows);

teamColorBar draws a bar in the team colour, teamColorBg tints the cell, and mergeStackTeamColor stacks two values with the lower one in the team colour.

AFC, 2024
TeamQbWins
KCPatrick Mahomes15
LACJustin Herbert11
DENBo Nix10
LVGardner Minshew4
BUFJosh Allen13
MIATua Tagovailoa8
NYJAaron Rodgers5
NEDrake Maye4
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

const spec = defineTable<Standing>()
.columns((c) => [c.teamColorBar("team", { league: "nfl", barWidth: 6 }), c.text("qb"), c.int("wins")])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024: secondary colours at 50%
TeamQbWins
KCPatrick Mahomes15
LACJustin Herbert11
DENBo Nix10
LVGardner Minshew4
BUFJosh Allen13
MIATua Tagovailoa8
NYJAaron Rodgers5
NEDrake Maye4
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

const spec = defineTable<Standing>()
.columns((c) => [
c.teamColorBg("team", { league: "nfl", which: "secondary", alpha: 0.5 }),
c.text("qb"),
c.int("wins"),
])
.title("AFC, 2024: secondary colours at 50%")
.build();
await renderHTMLAsync(spec, STANDINGS);
AFC, 2024
QuarterbackWins
Patrick Mahomes
KC
15
Justin Herbert
LAC
11
Bo Nix
DEN
10
Gardner Minshew
LV
4
Josh Allen
BUF
13
Tua Tagovailoa
MIA
8
Aaron Rodgers
NYJ
5
Drake Maye
NE
4
import { STANDINGS, type Standing } from "@sportsdataverse/examples/data";
import { defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// key on top, stack below; team picks the colour (made readable against the table background).
const spec = defineTable<Standing>()
.columns((c) => [
c.mergeStackTeamColor("qb", "team", "team", { league: "nfl", label: "Quarterback" }),
c.int("wins"),
])
.title("AFC, 2024")
.build();
await renderHTMLAsync(spec, STANDINGS);

In the gallery: Every cell kind.