Skip to main content

From sdvplot (Python), sdvplotR, sportyR

sdvplot-js is a port: the team data and lookups of sdvplot (Python) and sdvplotR, the table helpers of sdvplotR and gtUtils, and the surfaces of sportyR. The answers match theirs (the test suite checks them against the Python and R outputs); the names follow JavaScript conventions, and the ggplot and gt functions become marks, adapters and builder methods. This page maps the old names to the new.

Lookups​

The Python names become camelCase; sdvplotR's sdv_ prefix goes.

Python sdvplotsdvplotRsdvplot-js
resolve, suggest, teamsclean_team_abbrs, resolve_historical_abbr, team_referenceresolve / resolveSync, suggest, teams
team_colors, palettesdv_team_colors, sdv_color_paletteteamColors / teamColorsSync, palette
logo_url, markssdv_logo_urllogoUrl / logoUrlSync, marks, selectMark
headshot_urlsdv_headshot_urlheadshotUrl
versionsversions, VERSION, INDEX_VERSION

A season resolves a relocated franchise the same way in all three:

{
  "OAK 2019": "13",
  "LV 2024": "13",
  "QUE 1994": "17",
  "COL 2024": "17"
}
import { loadLeague, resolveSync } from "@sportsdataverse/sdvplot";

await loadLeague("nfl");
await loadLeague("nhl");

{
"OAK 2019": resolveSync("OAK", "nfl", { season: 2019 }),
"LV 2024": resolveSync("LV", "nfl", { season: 2024 }),
"QUE 1994": resolveSync("QUE", "nhl", { season: 1994 }),
"COL 2024": resolveSync("COL", "nhl", { season: 2024 }),
};

Plot layers​

ggplot's geoms and scales become Observable Plot marks and scale options (@sportsdataverse/sdvplot/plot); Python's add_* functions are the same marks. For other libraries the verbs are with* (Plotly, Vega-Lite, ECharts) and append* (D3).

Python sdvplotsdvplotRsdvplot-js (Plot)
add_logos, add_wordmarks, add_headshotsgeom_sdv_logos, geom_sdv_wordmarks, geom_sdv_headshotslogos, wordmarks, headshots
axis_logostheme_x_sdv, element_sdv_logoaxisLogos
scale_color_sdv, scale_fill_sdvteamColor, teamFill
geom_mean_lines, geom_median_linesmeanLines, medianLines
ggtitle_imagetitleImage
sdv_team_tiersteamTiers
surfacesdv_surfacesurface

Coordinates and surfaces​

sportyR's geom_baseball, geom_basketball and the other seven become surface(sport, league) or the typed entry per sport (basketballCourt("nba")). Python's court_coords and sdvplotR's sdv_court_coords / sdv_pitch_coords become toSurfaceFrame(rows, { from }) with a frame from FRAMES; the stats.nba.com shot frame is "nba-legacy".

import * as Plot from "@observablehq/plot";
import { NBA_SHOTS } from "@sportsdataverse/examples/data";
import { loadLeague } from "@sportsdataverse/sdvplot";
import { logos, surface, teamColor } from "@sportsdataverse/sdvplot/plot";
import { toSurfaceFrame } from "@sportsdataverse/sporty";

await loadLeague("nba");

// stats.nba.com shots: columns x_legacy/y_legacy (the frame's defaults), tenths of a foot from the hoop.
// Every shot lands on the -x half, so draw the defensive half only: displayRange "defense".
const shots = toSurfaceFrame(NBA_SHOTS, { from: "nba-legacy" });
const court = surface("nba", { team: "DEN", displayRange: "defense" });
const at = { x: "surface_x", y: "surface_y", r: 5 } as const;
Plot.plot({
...court.scales,
width: 940,
color: teamColor("nba", { values: shots.map((s) => s.team), legend: true }),
marks: [
...court.marks,
// made shots filled in the shooting team's colour, misses white with a ring in it: both read on the paint
Plot.dot(
shots.filter((s) => s.made),
{ ...at, fill: "team", stroke: "white" },
),
Plot.dot(
shots.filter((s) => !s.made),
{ ...at, fill: "white", stroke: "team", strokeWidth: 2 },
),
logos(
shots.filter((s) => s.made && s.shot_type === "3PT Field Goal"),
{ league: "nba", x: "surface_x", y: "surface_y", team: "team", height: 0.08 },
),
],
});

Tables​

Every gt_* helper of sdvplotR and gtUtils has a home in sdvtables: a column kind (c.<kind>), a builder method, a theme or a function of @sportsdataverse/sdvtables/html. GT_ALIASES is that table, and aliasFor looks a name up.

GT_ALIASES74 names; aliasFor("gt_color_pills").target is "c.colorPills"
sdvplotR / gtUtilssdvtablesStatusNote
gt_sdv_logosc.logoported
gt_sdv_wordmarksc.wordmarkported
gt_sdv_headshotsc.headshotported
gt_sdv_cols_labellabelHtmlnot-portedlabels are text in Phase 4; use .titleHeader() or subheader
gt_merge_stack_team_colorc.mergeStackTeamColorported
gt_theme_sdvtheme.sdvported
gt_theme_sdv_teamtheme.sdvTeamported
gt_theme_almanactheme.almanacported
gt_theme_athletictheme.athleticported
gt_theme_booktabstheme.booktabsported
gt_theme_broadsheettheme.broadsheetported
gt_theme_brutalisttheme.brutalistported
gt_theme_drenchtheme.drenchported
gt_theme_gtutilstheme.gtutilsported
gt_theme_kenpomtheme.kenpomported
gt_theme_midnighttheme.midnightported
gt_theme_ncaatheme.ncaaported
gt_theme_pltheme.plported
gt_theme_savanttheme.savantported
gt_theme_scoreboardtheme.scoreboardported
gt_theme_sofatheme.sofaported
gt_theme_swisstheme.swissported
gt_theme_terminaltheme.terminalported
gt_theme_tiertheme.tierported
gt_theme_tuftetheme.tufteported
gt_theme_previewhtml.themePreviewporteda Record<name, html>, not a grid
pal_midnightPAL_MIDNIGHTported
gt_538_captionbuilder.caption538ported
gt_bold_rowsbuilder.boldRowsported
gt_border_bars_topbuilder.borderBarsported
gt_border_bars_bottombuilder.borderBarsported
gt_border_gridbuilder.borderGridported
gt_color_pillsc.colorPillsported
gt_color_ranksc.colorRanksported
gt_color_resultsc.colorResultsporteda column kind (spec §6.1) that fills its row
gt_column_subheadersbuilder.columnsportedthe per-column subheader option of every c.* kind
gt_cutlinebuilder.cutlineported
gt_deltac.deltaported
gt_fmt_rankc.rankported
gt_fmt_tallyc.tallyported
gt_group_stripesbuilder.groupStripesported
gt_highlight_cellsc.highlightporteddata predicate, not a formula
gt_highlight_nac.highlightNaported
gt_indicator_boxesc.indicatorBoxportedvalue list, not a rule
gt_legend_continuousbuilder.legendContinuousported
gt_legend_discretebuilder.legendDiscreteported
gt_color_legendbuilder.legendContinuousporteddeprecated gtUtils name (sdvplotR deprecated.R:20)
gt_centered_legendbuilder.legendDiscreteporteddeprecated gtUtils name (sdvplotR deprecated.R:27)
gt_marginaliabuilder.marginaliaported
gt_outliersbuilder.outliersported
gt_percentile_barc.percentileBarported
gt_row_accentbuilder.rowAccentported
gt_scale_notebuilder.scaleNoteported
gt_set_fontbuilder.fontported
gt_significancebuilder.significanceported
gt_snakebuilder.snakeported
gt_snake_alignsnakeAlignported
gt_social_tagbuilder.socialTagported
gt_spotlightbuilder.spotlightported
gt_tiersbuilder.tiersported
gt_title_headerbuilder.titleHeaderported
gt_watermarkbuilder.watermarkported
gt_wrap_labelsbuilder.wrapLabelsported
gt_save_croptableToPNGphase-5
gt_save_batchtableToPNGphase-5
gt_social_cropsocialCropphase-5
gt_gridgridTablesphase-5
gt_stack_tablesstackTablesphase-5
reactable_sdv_logosc.logoported
reactable_sdv_wordmarksc.wordmarkported
reactable_sdv_headshotsc.headshotported
reactable_sdv_cols_labellabelHtmlnot-portedas gt_sdv_cols_label
reactable_sdv_team_color_barc.teamColorBarported
reactable_sdv_team_color_bgc.teamColorBgported
import { GT_ALIASES, aliasFor, defineTable } from "@sportsdataverse/sdvtables";
import { renderHTMLAsync } from "@sportsdataverse/sdvtables/html";

// c.<kind> is a column kind, builder.<method> a decoration, theme.<name> a theme, html.<name> the ./html subpath.
const rows = Object.entries(GT_ALIASES).map(([name, a]) => ({
name,
target: a.target,
status: a.status,
note: a.note ?? "",
}));
const spec = defineTable<(typeof rows)[number]>()
.columns((c) => [
c.text("name", { label: "sdvplotR / gtUtils" }),
c.text("target", { label: "sdvtables" }),
c.highlight("status", { key: "status", op: "!=", value: "ported" }),
c.text("note"),
])
.title("GT_ALIASES")
.subtitle(
`${rows.length} names; aliasFor("gt_color_pills").target is "${aliasFor("gt_color_pills")?.target}"`,
)
.build();
await renderHTMLAsync(spec, rows);

In the gallery: every example, by package.