sdvplot 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. sdvplot/__init__.py +68 -0
  2. sdvplot/_cache.py +484 -0
  3. sdvplot/_colors.py +206 -0
  4. sdvplot/_contrast.py +60 -0
  5. sdvplot/_court.py +110 -0
  6. sdvplot/_deprecate.py +39 -0
  7. sdvplot/_dispatch.py +342 -0
  8. sdvplot/_errors.py +93 -0
  9. sdvplot/_headshots.py +131 -0
  10. sdvplot/_images.py +292 -0
  11. sdvplot/_index.py +178 -0
  12. sdvplot/_lazy.py +15 -0
  13. sdvplot/_manifest.py +73 -0
  14. sdvplot/_marks.py +296 -0
  15. sdvplot/_normalize.py +82 -0
  16. sdvplot/_placement.py +168 -0
  17. sdvplot/_resolve.py +363 -0
  18. sdvplot/_surface.py +220 -0
  19. sdvplot/_tables.py +87 -0
  20. sdvplot/_tiers.py +135 -0
  21. sdvplot/_types.py +38 -0
  22. sdvplot/_versions.py +30 -0
  23. sdvplot/_web.py +61 -0
  24. sdvplot/altair.py +652 -0
  25. sdvplot/bokeh.py +323 -0
  26. sdvplot/data/INDEX_VERSION +1 -0
  27. sdvplot/data/aliases.parquet +0 -0
  28. sdvplot/data/teams.parquet +0 -0
  29. sdvplot/folium.py +316 -0
  30. sdvplot/great_tables/__init__.py +267 -0
  31. sdvplot/great_tables/_cells.py +1814 -0
  32. sdvplot/great_tables/_export.py +844 -0
  33. sdvplot/great_tables/_layout.py +1802 -0
  34. sdvplot/great_tables/_marks.py +798 -0
  35. sdvplot/great_tables/_themes.py +2134 -0
  36. sdvplot/holoviews.py +303 -0
  37. sdvplot/matplotlib.py +934 -0
  38. sdvplot/plotly.py +595 -0
  39. sdvplot/plotnine.py +1104 -0
  40. sdvplot/plottable.py +141 -0
  41. sdvplot/py.typed +0 -0
  42. sdvplot/pygal.py +416 -0
  43. sdvplot/reactable.py +488 -0
  44. sdvplot/testing.py +579 -0
  45. sdvplot/typing.py +21 -0
  46. sdvplot-0.1.0.dist-info/METADATA +188 -0
  47. sdvplot-0.1.0.dist-info/RECORD +49 -0
  48. sdvplot-0.1.0.dist-info/WHEEL +4 -0
  49. sdvplot-0.1.0.dist-info/licenses/LICENSE +21 -0
sdvplot/reactable.py ADDED
@@ -0,0 +1,488 @@
1
+ """reactable-py columns (``pip install sdvplot[reactable]``), ported from sdvplotR's ``reactable_sdv_*`` functions.
2
+
3
+ Each function returns ``reactable.Column`` objects for ``Reactable(columns=[...])``; pass the column's ``id`` (and any
4
+ other ``Column`` argument) as keywords. reactable-py runs the cell functions when the ``Reactable`` is built, so an
5
+ unknown value warns then, once per distinct value per column.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import html
11
+ import math
12
+ import numbers
13
+ from typing import Any
14
+
15
+ from sdvplot._errors import InputError, requires_extra
16
+
17
+ with requires_extra("reactable"):
18
+ import narwhals as nw
19
+ from reactable import Column
20
+ from reactable.models import CellInfo
21
+
22
+ from sdvplot._colors import team_colors
23
+ from sdvplot._contrast import hex6
24
+ from sdvplot._normalize import norm_season
25
+ from sdvplot._placement import KINDS, _missing, check_alpha
26
+ from sdvplot._tables import check_px, img_tag, mark_html
27
+ from sdvplot._types import IdSystem, Which
28
+
29
+ __all__ = [
30
+ "reactable_sdv_cols_label",
31
+ "reactable_sdv_headshots",
32
+ "reactable_sdv_logos",
33
+ "reactable_sdv_team_color_bar",
34
+ "reactable_sdv_team_color_bg",
35
+ "reactable_sdv_wordmarks",
36
+ ]
37
+
38
+
39
+ def __dir__() -> list[str]: # dir() and tab completion show the public API only
40
+ return list(__all__)
41
+
42
+
43
+ def _image_column(
44
+ kind: str,
45
+ league: str,
46
+ height: Any,
47
+ *,
48
+ season: Any = None,
49
+ variant: str = "default",
50
+ include_name: bool = False,
51
+ default_img: str | None = None,
52
+ id_system: str = "auto",
53
+ strict: bool = False,
54
+ column_kwargs: dict[str, Any],
55
+ ) -> Column:
56
+ h = check_px(height)
57
+ norm_season(season, league=league) # one season for the column: fail now, not inside reactable
58
+ rendered: dict[str, str] = {}
59
+
60
+ def cell(info: CellInfo) -> str:
61
+ value = info.value
62
+ if _missing(value):
63
+ return ""
64
+ key = str(value)
65
+ if key not in rendered: # resolve each distinct value once: one warning per unknown value
66
+ (img,) = mark_html([value], league=league, kind=kind, height=h, season=season, variant=variant,
67
+ id_system=id_system, strict=strict, include_name=include_name) # fmt: skip
68
+ text = html.escape(key)
69
+ if img is None and default_img is not None:
70
+ img = img_tag(default_img, h, key, margin=include_name)
71
+ rendered[key] = text if img is None else img + (text if include_name else "")
72
+ return rendered[key]
73
+
74
+ return Column(**{"html": True, **column_kwargs, "cell": cell})
75
+
76
+
77
+ def reactable_sdv_logos(
78
+ *,
79
+ league: str,
80
+ variant: str = "default",
81
+ height: Any = 30,
82
+ default_img: str | None = None,
83
+ season: Any = None,
84
+ include_name: bool = False,
85
+ id_system: IdSystem = "auto",
86
+ strict: bool = False,
87
+ **column_kwargs: Any,
88
+ ) -> Column:
89
+ """A reactable column that shows each cell's team as its logo.
90
+
91
+ Args:
92
+ league: The SDV league key, e.g. "nfl".
93
+ variant: "default", "dark", or a named variant from ``marks()``.
94
+ height: The image height in pixels.
95
+ default_img: An image URL for values that do not resolve; None keeps their text.
96
+ season: One season whose marks every cell shows; None for today's.
97
+ include_name: Keep the cell's text after the logo.
98
+ id_system: The id system of the column's values, as in ``resolve``: "auto" tries each in order; NHL stats
99
+ ids need "nhl_id".
100
+ strict: Raise UnresolvedTeamError (when the ``Reactable`` is built) instead of warning when a value does not
101
+ resolve.
102
+ **column_kwargs: Passed to ``reactable.Column``: ``id`` (the data column, required by reactable), ``name``,
103
+ ``width``, ...
104
+
105
+ Returns:
106
+ reactable.Column: The column, with ``html=True`` and a cell renderer.
107
+
108
+ Raises:
109
+ InputError: (a ValueError) If ``height`` is not a number of pixels of at least 1, or ``season`` is not one year
110
+ or is outside the seasons sdvplot knows for the league; when the ``Reactable`` is built, if ``league``,
111
+ ``id_system`` or ``variant`` is unknown.
112
+ UnresolvedTeamError: (a ValueError) If ``strict=True`` and a value does not resolve, when the ``Reactable`` is
113
+ built.
114
+ OfflineError: When the ``Reactable`` is built, if the logo manifest cannot be downloaded and no cached copy
115
+ exists (a DownloadError, also an OSError, when the CDN answers with an error status).
116
+ UnsafeDownloadError: (an OSError) When the ``Reactable`` is built, if the manifest download is refused: larger
117
+ than the byte cap, past the deadline, or redirected away from https.
118
+
119
+ Example:
120
+ ::
121
+
122
+ from reactable import Reactable
123
+ from sdvplot.reactable import reactable_sdv_logos
124
+ import pandas as pd
125
+
126
+ df = pd.DataFrame(
127
+ {
128
+ "team": ["KC", "BUF", "BAL"],
129
+ "espn_id": ["3139477", "3918298", "3916387"],
130
+ "wins": [12, 10, 9],
131
+ }
132
+ )
133
+
134
+ Reactable(df, columns=[reactable_sdv_logos(league="nfl", id="team", name="")])
135
+
136
+ See Also:
137
+ Ported from sdvplotR ``reactable_sdv_logos()``:
138
+ https://sdvplotR.sportsdataverse.org/reference/reactable_sdv_images.html
139
+ """
140
+ return _image_column("logo", league, height, season=season, variant=variant, include_name=include_name,
141
+ default_img=default_img, id_system=id_system, strict=strict,
142
+ column_kwargs=column_kwargs) # fmt: skip
143
+
144
+
145
+ def reactable_sdv_wordmarks(
146
+ *,
147
+ league: str,
148
+ variant: str = "default",
149
+ height: Any = 30,
150
+ default_img: str | None = None,
151
+ season: Any = None,
152
+ include_name: bool = False,
153
+ id_system: IdSystem = "auto",
154
+ strict: bool = False,
155
+ **column_kwargs: Any,
156
+ ) -> Column:
157
+ """A reactable column that shows each cell's team as its wordmark.
158
+
159
+ Args:
160
+ league: The SDV league key, e.g. "nfl".
161
+ variant: "default", "dark", or a named variant from ``marks()``.
162
+ height: The image height in pixels.
163
+ default_img: An image URL for values that do not resolve; None keeps their text.
164
+ season: One season whose marks every cell shows; None for today's.
165
+ include_name: Keep the cell's text after the wordmark.
166
+ id_system: The id system of the column's values, as in ``resolve``: "auto" tries each in order; NHL stats
167
+ ids need "nhl_id".
168
+ strict: Raise UnresolvedTeamError (when the ``Reactable`` is built) instead of warning when a value does not
169
+ resolve.
170
+ **column_kwargs: Passed to ``reactable.Column`` (``id`` is required by reactable).
171
+
172
+ Returns:
173
+ reactable.Column: The column, with ``html=True`` and a cell renderer.
174
+
175
+ Raises:
176
+ InputError: (a ValueError) If ``height`` is not a number of pixels of at least 1, or ``season`` is not one year
177
+ or is outside the seasons sdvplot knows for the league; when the ``Reactable`` is built, if ``league``,
178
+ ``id_system`` or ``variant`` is unknown.
179
+ UnresolvedTeamError: (a ValueError) If ``strict=True`` and a value does not resolve, when the ``Reactable`` is
180
+ built.
181
+ OfflineError: When the ``Reactable`` is built, if the logo manifest cannot be downloaded and no cached copy
182
+ exists (a DownloadError, also an OSError, when the CDN answers with an error status).
183
+ UnsafeDownloadError: (an OSError) When the ``Reactable`` is built, if the manifest download is refused: larger
184
+ than the byte cap, past the deadline, or redirected away from https.
185
+
186
+ Example:
187
+ ::
188
+
189
+ import pandas as pd
190
+ from reactable import Reactable
191
+ from sdvplot.reactable import reactable_sdv_wordmarks
192
+
193
+ df = pd.DataFrame(
194
+ {
195
+ "team": ["KC", "BUF", "BAL"],
196
+ "espn_id": ["3139477", "3918298", "3916387"],
197
+ "wins": [12, 10, 9],
198
+ }
199
+ )
200
+
201
+ Reactable(df, columns=[reactable_sdv_wordmarks(league="nfl", id="team")])
202
+
203
+ See Also:
204
+ Ported from sdvplotR ``reactable_sdv_wordmarks()``:
205
+ https://sdvplotR.sportsdataverse.org/reference/reactable_sdv_images.html
206
+ """
207
+ return _image_column("wordmark", league, height, season=season, variant=variant, include_name=include_name,
208
+ default_img=default_img, id_system=id_system, strict=strict,
209
+ column_kwargs=column_kwargs) # fmt: skip
210
+
211
+
212
+ def reactable_sdv_headshots(
213
+ *,
214
+ league: str,
215
+ height: Any = 40,
216
+ default_img: str | None = None,
217
+ id_system: str = "espn",
218
+ **column_kwargs: Any,
219
+ ) -> Column:
220
+ """A reactable column that shows each cell's player id as the player's headshot.
221
+
222
+ Args:
223
+ league: The SDV league key, e.g. "nfl".
224
+ height: The image height in pixels.
225
+ default_img: An image URL for ids without a headshot; None keeps their text.
226
+ id_system: "espn" (ESPN athlete ids) or "gsis" (NFL), as in ``headshot_url``.
227
+ **column_kwargs: Passed to ``reactable.Column`` (``id`` is required by reactable).
228
+
229
+ Returns:
230
+ reactable.Column: The column, with ``html=True`` and a cell renderer.
231
+
232
+ Raises:
233
+ InputError: (a ValueError) If ``height`` is not a number of pixels of at least 1; when the ``Reactable`` is
234
+ built, if ``league`` has no ESPN headshots or ``id_system`` is not valid for ``league``.
235
+ OfflineError: When the ``Reactable`` is built, if ``id_system`` is "gsis" and the nflverse player table cannot
236
+ be downloaded and no cached copy exists (a DownloadError, also an OSError, for an HTTP error status).
237
+ UnsafeDownloadError: (an OSError) When the ``Reactable`` is built, if ``id_system`` is "gsis" and the player
238
+ table download is refused: larger than the byte cap, past the deadline, or redirected away from https.
239
+
240
+ Example:
241
+ ::
242
+
243
+ import pandas as pd
244
+ from reactable import Reactable
245
+ from sdvplot.reactable import reactable_sdv_headshots
246
+
247
+ df = pd.DataFrame(
248
+ {
249
+ "team": ["KC", "BUF", "BAL"],
250
+ "espn_id": ["3139477", "3918298", "3916387"],
251
+ "wins": [12, 10, 9],
252
+ }
253
+ )
254
+
255
+ Reactable(df, columns=[reactable_sdv_headshots(league="nfl", id="espn_id", name="")])
256
+
257
+ See Also:
258
+ Ported from sdvplotR ``reactable_sdv_headshots()``:
259
+ https://sdvplotR.sportsdataverse.org/reference/reactable_sdv_images.html
260
+ """
261
+ return _image_column("headshot", league, height, default_img=default_img, id_system=id_system,
262
+ column_kwargs=column_kwargs) # fmt: skip
263
+
264
+
265
+ def reactable_sdv_cols_label(
266
+ data: Any,
267
+ *,
268
+ league: str,
269
+ variant: str = "default",
270
+ height: Any = 30,
271
+ season: Any = None,
272
+ mark_type: str = "logo",
273
+ id_system: IdSystem = "auto",
274
+ strict: bool = False,
275
+ **column_kwargs: Any,
276
+ ) -> list[Column]:
277
+ """One reactable column per team-named column of ``data`` (a ``KC`` column, a ``BUF`` column, ...), its header
278
+ the team's mark.
279
+
280
+ Args:
281
+ data: The pandas or polars DataFrame passed to ``Reactable``. Pass only the team-named columns
282
+ (``df[["KC", "BUF"]]``) to avoid a warning for the others.
283
+ league: The SDV league key, e.g. "nfl".
284
+ variant: "default", "dark", or a named variant from ``marks()``.
285
+ height: The image height in pixels.
286
+ season: One season whose marks to show; None for today's.
287
+ mark_type: "logo" or "wordmark".
288
+ id_system: The id system of the column names, as in ``resolve``: "auto" tries each in order; NHL stats ids
289
+ need "nhl_id".
290
+ strict: Raise UnresolvedTeamError instead of warning when a column name does not resolve.
291
+ **column_kwargs: Passed to every ``reactable.Column``.
292
+
293
+ Returns:
294
+ list[reactable.Column]: A column (``id`` = the column name, an empty ``name``, the mark as ``header``) for each
295
+ column whose name resolves; the others are left out, with one SdvplotWarning.
296
+
297
+ Raises:
298
+ InputError: (a ValueError) If ``mark_type`` is not "logo"/"wordmark", ``height`` is not a number of pixels of at
299
+ least 1, ``league``, ``id_system`` or ``variant`` is unknown, or ``season`` is not one year or is outside
300
+ the seasons sdvplot knows for the league.
301
+ UnresolvedTeamError: (a ValueError) If ``strict=True`` and a column name does not resolve.
302
+ OfflineError: If the logo manifest cannot be downloaded and no cached copy exists (a DownloadError, also an
303
+ OSError, when the CDN answers with an error status).
304
+ UnsafeDownloadError: (an OSError) If the manifest download is refused: larger than the byte cap, past the
305
+ deadline, or redirected away from https.
306
+
307
+ Example:
308
+ ::
309
+
310
+ import pandas as pd
311
+ from reactable import Reactable
312
+ from sdvplot.reactable import reactable_sdv_cols_label
313
+
314
+ df = pd.DataFrame(
315
+ {
316
+ "team": ["KC", "BUF", "BAL"],
317
+ "espn_id": ["3139477", "3918298", "3916387"],
318
+ "wins": [12, 10, 9],
319
+ }
320
+ )
321
+
322
+ Reactable(df, columns=reactable_sdv_cols_label(df, league="nfl"))
323
+
324
+ See Also:
325
+ Ported from sdvplotR ``reactable_sdv_cols_label()``:
326
+ https://sdvplotR.sportsdataverse.org/reference/reactable_sdv_cols_label.html
327
+ """
328
+ h = check_px(height)
329
+ if mark_type not in KINDS[:2]:
330
+ raise InputError(f"mark_type must be 'logo' or 'wordmark', got {mark_type!r}")
331
+ names = list(nw.from_native(data, eager_only=True).columns)
332
+ imgs = mark_html(names, league=league, kind=mark_type, height=h, season=season, variant=variant,
333
+ id_system=id_system, strict=strict) # fmt: skip
334
+ return [
335
+ Column(**{"name": "", "html": True, **column_kwargs, "id": name, "header": img})
336
+ for name, img in zip(names, imgs, strict=True)
337
+ if img is not None
338
+ ]
339
+
340
+
341
+ def _row_colors(
342
+ data: Any, team_col: str, league: str, which: Which, na_color: str, id_system: IdSystem, strict: bool
343
+ ) -> tuple[Any, list[str]]:
344
+ frame = nw.from_native(data, eager_only=True)
345
+ if team_col not in frame.columns:
346
+ raise ValueError(f"column {team_col!r} not found in data; columns are {frame.columns}")
347
+ colors = team_colors(league, frame[team_col].to_list(), which=which, id_system=id_system, strict=strict)
348
+ return frame, [c or na_color for c in colors]
349
+
350
+
351
+ def reactable_sdv_team_color_bar(
352
+ data: Any,
353
+ team_col: str,
354
+ *,
355
+ league: str,
356
+ which: Which = "primary",
357
+ max_value: float | None = None,
358
+ na_color: str = "#b3b3b3",
359
+ id_system: IdSystem = "auto",
360
+ strict: bool = False,
361
+ **column_kwargs: Any,
362
+ ) -> Column:
363
+ """A reactable column whose cells hold a bar in the row's team color, as long as the value's share of the maximum.
364
+
365
+ Args:
366
+ data: The pandas or polars DataFrame passed to ``Reactable`` (each row's team is read from it).
367
+ team_col: The column of ``data`` holding the teams.
368
+ league: The SDV league key, e.g. "nfl".
369
+ which: "primary" or "secondary" team color.
370
+ max_value: The value that fills the whole cell; None for the column's maximum.
371
+ na_color: The CSS color for teams that do not resolve or have no color.
372
+ id_system: The id system of ``team_col``, as in ``resolve``: "auto" tries each in order; NHL stats ids need
373
+ "nhl_id".
374
+ strict: Raise UnresolvedTeamError instead of warning when a team does not resolve.
375
+ **column_kwargs: Passed to ``reactable.Column``; ``id`` names the styled column.
376
+
377
+ Returns:
378
+ reactable.Column: The column, with a ``style`` function.
379
+
380
+ Raises:
381
+ InputError: (a ValueError) If ``league`` or ``id_system`` is unknown, or ``which`` is not "primary"/"secondary".
382
+ ValueError: If ``team_col`` is not a column of ``data``.
383
+ UnresolvedTeamError: (a ValueError) If ``strict=True`` and a team does not resolve.
384
+
385
+ Example:
386
+ ::
387
+
388
+ import pandas as pd
389
+ from reactable import Reactable
390
+ from sdvplot.reactable import reactable_sdv_team_color_bar
391
+
392
+ df = pd.DataFrame(
393
+ {
394
+ "team": ["KC", "BUF", "BAL"],
395
+ "espn_id": ["3139477", "3918298", "3916387"],
396
+ "wins": [12, 10, 9],
397
+ }
398
+ )
399
+
400
+ Reactable(df, columns=[reactable_sdv_team_color_bar(df, "team", league="nfl", id="wins")])
401
+
402
+ See Also:
403
+ Ported from sdvplotR ``reactable_sdv_team_color_bar()``:
404
+ https://sdvplotR.sportsdataverse.org/reference/reactable_sdv_team_color.html
405
+ """
406
+ frame, colors = _row_colors(data, team_col, league, which, na_color, id_system, strict)
407
+ tops: dict[str, float] = {}
408
+
409
+ def top(column: str) -> float:
410
+ if column not in tops:
411
+ values = [float(v) for v in frame[column].to_list() if isinstance(v, numbers.Real) and not _missing(v)]
412
+ tops[column] = max_value if max_value is not None else max(values, default=math.nan)
413
+ return tops[column]
414
+
415
+ def bar(info: CellInfo) -> dict[str, str]:
416
+ value, t = info.value, top(info.column_name)
417
+ ok = isinstance(value, numbers.Real) and not _missing(value) and math.isfinite(t) and t != 0
418
+ pct = round(100 * value / t, 1) if ok else 0
419
+ c = colors[info.row_index]
420
+ return {"background-image": f"linear-gradient(90deg, {c} {pct:g}%, transparent {pct:g}%)"}
421
+
422
+ return Column(**{**column_kwargs, "style": bar})
423
+
424
+
425
+ def reactable_sdv_team_color_bg(
426
+ data: Any,
427
+ team_col: str,
428
+ *,
429
+ league: str,
430
+ which: Which = "primary",
431
+ alpha: float = 0.15,
432
+ na_color: str = "#b3b3b3",
433
+ id_system: IdSystem = "auto",
434
+ strict: bool = False,
435
+ **column_kwargs: Any,
436
+ ) -> Column:
437
+ """A reactable column whose cells are filled with the row's team color, mostly transparent.
438
+
439
+ Args:
440
+ data: The pandas or polars DataFrame passed to ``Reactable`` (each row's team is read from it).
441
+ team_col: The column of ``data`` holding the teams.
442
+ league: The SDV league key, e.g. "nfl".
443
+ which: "primary" or "secondary" team color.
444
+ alpha: The fill's opacity, 0 to 1.
445
+ na_color: The hex color for teams that do not resolve or have no color.
446
+ id_system: The id system of ``team_col``, as in ``resolve``: "auto" tries each in order; NHL stats ids need
447
+ "nhl_id".
448
+ strict: Raise UnresolvedTeamError instead of warning when a team does not resolve.
449
+ **column_kwargs: Passed to ``reactable.Column``; ``id`` names the styled column.
450
+
451
+ Returns:
452
+ reactable.Column: The column, with a ``style`` function.
453
+
454
+ Raises:
455
+ InputError: (a ValueError) If ``alpha`` is outside [0, 1], ``league`` or ``id_system`` is unknown, or ``which``
456
+ is not "primary"/"secondary".
457
+ ValueError: If ``team_col`` is not a column of ``data``, or ``na_color`` is not a hex color.
458
+ UnresolvedTeamError: (a ValueError) If ``strict=True`` and a team does not resolve.
459
+
460
+ Example:
461
+ ::
462
+
463
+ import pandas as pd
464
+ from reactable import Reactable
465
+ from sdvplot.reactable import reactable_sdv_team_color_bg
466
+
467
+ df = pd.DataFrame(
468
+ {
469
+ "team": ["KC", "BUF", "BAL"],
470
+ "espn_id": ["3139477", "3918298", "3916387"],
471
+ "wins": [12, 10, 9],
472
+ }
473
+ )
474
+
475
+ Reactable(df, columns=[reactable_sdv_team_color_bg(df, "team", league="nfl", id="team")])
476
+
477
+ See Also:
478
+ Ported from sdvplotR ``reactable_sdv_team_color_bg()``:
479
+ https://sdvplotR.sportsdataverse.org/reference/reactable_sdv_team_color.html
480
+ """
481
+ a = check_alpha(alpha)
482
+ _, colors = _row_colors(data, team_col, league, which, na_color, id_system, strict)
483
+ fills = [f"{hex6(c, drop_alpha=True)}{round(a * 255):02x}" for c in colors] # alpha replaces any in na_color
484
+
485
+ def fill(info: CellInfo) -> dict[str, str]:
486
+ return {"background-color": fills[info.row_index]}
487
+
488
+ return Column(**{**column_kwargs, "style": fill})