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/holoviews.py ADDED
@@ -0,0 +1,303 @@
1
+ """The HoloViews adapter: a Bokeh plot hook that draws the marks through the Bokeh adapter when the element renders.
2
+
3
+ The marks are resolved (and any warning raised) when ``add_logos`` is called; the hook only draws them on
4
+ ``plot.state``, the Bokeh figure. Only the Bokeh backend is supported.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+
11
+ from sdvplot._errors import UnsupportedTargetError, requires_extra
12
+
13
+ with requires_extra("holoviews"):
14
+ import holoviews as hv
15
+
16
+ from sdvplot import bokeh as _bokeh
17
+ from sdvplot._placement import check_alpha, check_height, place
18
+ from sdvplot._web import image_sources
19
+
20
+ _SUPPORTS_AXIS_LOGOS = False
21
+
22
+ __all__ = ["add_headshots", "add_logos", "add_wordmarks", "axis_logos"]
23
+
24
+
25
+ def __dir__() -> list[str]: # dir() and tab completion show the public API only
26
+ return list(__all__)
27
+
28
+
29
+ def _require_bokeh() -> None:
30
+ import holoviews.plotting.bokeh # noqa: F401 registers the Bokeh backend; it becomes current if none was loaded
31
+
32
+ if hv.Store.current_backend != "bokeh":
33
+ raise TypeError(
34
+ f"sdvplot.holoviews draws through the Bokeh backend, but the current backend is "
35
+ f"{hv.Store.current_backend!r}; call hv.extension('bokeh') or hv.output(backend='bokeh') first"
36
+ )
37
+
38
+
39
+ def _add(
40
+ element: Any,
41
+ x: Any,
42
+ y: Any,
43
+ teams: Any,
44
+ *,
45
+ kind: str,
46
+ league: str,
47
+ season: Any,
48
+ height: float,
49
+ alpha: float,
50
+ variant: str,
51
+ embed: bool,
52
+ id_system: str,
53
+ ) -> Any:
54
+ h, a = check_height(height), check_alpha(alpha)
55
+ if not isinstance(element, hv.core.Dimensioned):
56
+ raise UnsupportedTargetError(
57
+ f"sdvplot.holoviews draws on a HoloViews element or overlay, got {type(element).__name__}"
58
+ )
59
+ _require_bokeh()
60
+ placements = place(x, y, teams, league=league, season=season, kind=kind, variant=variant, id_system=id_system)
61
+ sources = image_sources(placements, embed=embed)
62
+
63
+ def hook(plot: Any, _element: Any) -> None:
64
+ _bokeh._draw(plot.state, placements, sources, kind=kind, height=h, alpha=a)
65
+
66
+ hooks = hv.Store.lookup_options("bokeh", element, "plot").kwargs.get("hooks", [])
67
+ return element.opts(hooks=[*hooks, hook], clone=True, backend="bokeh")
68
+
69
+
70
+ def add_logos(
71
+ element: Any,
72
+ x: Any,
73
+ y: Any,
74
+ teams: Any,
75
+ *,
76
+ league: str,
77
+ season: Any = None,
78
+ height: float = 0.1,
79
+ alpha: float = 1,
80
+ variant: str = "default",
81
+ embed: bool = False,
82
+ id_system: str = "auto",
83
+ ) -> Any:
84
+ """Draw each team's logo centred on its (x, y) point of a HoloViews element (Bokeh backend).
85
+
86
+ Returns a copy of the element with a Bokeh plot hook; the logos appear when it renders (``hv.render``, a notebook,
87
+ ``hv.save``). Sizing is the Bokeh adapter's: a fraction of the plot's ``frame_height`` when set, else its height;
88
+ a responsive plot has neither, so give it a ``frame_height`` (without one, HoloViews logs the hook's ValueError and
89
+ draws no marks).
90
+
91
+ Args:
92
+ element: A HoloViews element or overlay (``hv.Scatter``, ``hv.Points * hv.Curve``, ...).
93
+ x: The points' x positions, in the element's x values.
94
+ y: The points' y positions, the same length as ``x``.
95
+ teams: The team for each point, in any id system ``resolve()`` understands.
96
+ league: The SDV league key, e.g. "nfl".
97
+ season: One season, or one per point, to pick each team's mark for that era.
98
+ height: The logo height as a fraction of the plot's reference height, in (0, 1].
99
+ alpha: Opacity, 0 to 1.
100
+ variant: "default", "dark", or a named variant from ``marks()``.
101
+ embed: Inline each image as a data URI instead of linking its URL.
102
+ id_system: The id system of ``teams``; "auto" tries each in order.
103
+
104
+ Returns:
105
+ object: A copy of ``element`` with the drawing hook added to its existing hooks.
106
+
107
+ Raises:
108
+ InputError: (a ValueError) If ``height`` or ``alpha`` is out of range, ``league``, ``id_system`` or ``variant``
109
+ is unknown, or ``season`` is not a year or is outside the seasons sdvplot knows for the league.
110
+ ValueError: If the inputs differ in length; when the plot renders, if its figure has no pixel height (no
111
+ ``frame_height`` or ``height`` option).
112
+ TypeError: If the current HoloViews backend is not Bokeh.
113
+ UnsupportedTargetError: (a TypeError) If ``element`` is not a HoloViews element or overlay.
114
+ OfflineError: If the logo manifest, or with ``embed=True`` a mark's image, is neither cached nor downloadable (a
115
+ DownloadError, also an OSError, when the CDN answers with an error status; an IntegrityError when it sends a
116
+ file that does not match the manifest's sha256).
117
+ UnsafeDownloadError: (an OSError) If a download is refused: larger than the byte cap, past the deadline, or
118
+ redirected away from https.
119
+ UnsafeCachePathError: (a ValueError) If ``embed=True`` and the manifest's sha256 or extension for a mark would
120
+ put the file outside the cache directory.
121
+
122
+ Example:
123
+ ::
124
+
125
+ import holoviews as hv
126
+ import sdvplot
127
+
128
+ hv.extension("bokeh")
129
+ points = hv.Scatter([(10, -3), (20, -7)]).opts(frame_height=300)
130
+ points = sdvplot.add_logos(points, [10, 20], [-3, -7], ["KC", "BUF"], league="nfl", height=0.15)
131
+
132
+ See Also:
133
+ sdvplotR geom_nfl_logos(): https://sdvplotR.sportsdataverse.org/ ;
134
+ HoloViews plot hooks: https://holoviews.org/user_guide/Customizing_Plots.html
135
+ """
136
+ return _add(
137
+ element, x, y, teams, kind="logo", league=league, season=season, height=height, alpha=alpha,
138
+ variant=variant, embed=embed, id_system=id_system,
139
+ ) # fmt: skip
140
+
141
+
142
+ def add_wordmarks(
143
+ element: Any,
144
+ x: Any,
145
+ y: Any,
146
+ teams: Any,
147
+ *,
148
+ league: str,
149
+ season: Any = None,
150
+ height: float = 0.1,
151
+ alpha: float = 1,
152
+ variant: str = "default",
153
+ embed: bool = False,
154
+ id_system: str = "auto",
155
+ ) -> Any:
156
+ """Draw each team's wordmark centred on its (x, y) point of a HoloViews element (Bokeh backend).
157
+
158
+ Args:
159
+ element: A HoloViews element or overlay.
160
+ x: The points' x positions, in the element's x values.
161
+ y: The points' y positions, the same length as ``x``.
162
+ teams: The team for each point, in any id system ``resolve()`` understands.
163
+ league: The SDV league key, e.g. "nfl".
164
+ season: One season, or one per point.
165
+ height: The wordmark height as a fraction of the plot's reference height, in (0, 1].
166
+ alpha: Opacity, 0 to 1.
167
+ variant: "default", "dark", or a named variant from ``marks()``.
168
+ embed: Inline each image as a data URI instead of linking its URL.
169
+ id_system: The id system of ``teams``; "auto" tries each in order.
170
+
171
+ Returns:
172
+ object: A copy of ``element`` with the drawing hook added.
173
+
174
+ Raises:
175
+ InputError: (a ValueError) If ``height`` or ``alpha`` is out of range, ``league``, ``id_system`` or ``variant``
176
+ is unknown, or ``season`` is not a year or is outside the seasons sdvplot knows for the league.
177
+ ValueError: If the inputs differ in length; when the plot renders, if its figure has no pixel height (no
178
+ ``frame_height`` or ``height`` option).
179
+ TypeError: If the current HoloViews backend is not Bokeh.
180
+ UnsupportedTargetError: (a TypeError) If ``element`` is not a HoloViews element or overlay.
181
+ OfflineError: If the logo manifest, or with ``embed=True`` a mark's image, is neither cached nor downloadable (a
182
+ DownloadError, also an OSError, when the CDN answers with an error status; an IntegrityError when it sends a
183
+ file that does not match the manifest's sha256).
184
+ UnsafeDownloadError: (an OSError) If a download is refused: larger than the byte cap, past the deadline, or
185
+ redirected away from https.
186
+ UnsafeCachePathError: (a ValueError) If ``embed=True`` and the manifest's sha256 or extension for a mark would
187
+ put the file outside the cache directory.
188
+
189
+ Example:
190
+ ::
191
+
192
+ import holoviews as hv
193
+ import sdvplot
194
+
195
+ hv.extension("bokeh")
196
+ bars = hv.Bars([("KC", 12), ("BUF", 10)])
197
+ bars = sdvplot.add_wordmarks(bars, ["KC", "BUF"], [12, 10], ["KC", "BUF"], league="nfl", height=0.06)
198
+
199
+ See Also:
200
+ sdvplotR geom_nfl_wordmarks(): https://sdvplotR.sportsdataverse.org/
201
+ """
202
+ return _add(
203
+ element, x, y, teams, kind="wordmark", league=league, season=season, height=height, alpha=alpha,
204
+ variant=variant, embed=embed, id_system=id_system,
205
+ ) # fmt: skip
206
+
207
+
208
+ def add_headshots(
209
+ element: Any,
210
+ x: Any,
211
+ y: Any,
212
+ players: Any,
213
+ *,
214
+ league: str,
215
+ height: float = 0.1,
216
+ alpha: float = 1,
217
+ embed: bool = False,
218
+ id_system: str = "espn",
219
+ ) -> Any:
220
+ """Draw each player's headshot centred on its (x, y) point of a HoloViews element (Bokeh backend).
221
+
222
+ Args:
223
+ element: A HoloViews element or overlay.
224
+ x: The points' x positions, in the element's x values.
225
+ y: The points' y positions, the same length as ``x``.
226
+ players: The player id for each point.
227
+ league: The SDV league key, e.g. "nfl".
228
+ height: The headshot height as a fraction of the plot's reference height, in (0, 1].
229
+ alpha: Opacity, 0 to 1.
230
+ embed: Inline each image as a data URI instead of linking its URL.
231
+ id_system: "espn" (ESPN athlete ids) or "gsis" (NFL), as in ``headshot_url``.
232
+
233
+ Returns:
234
+ object: A copy of ``element`` with the drawing hook added.
235
+
236
+ Raises:
237
+ InputError: (a ValueError) If ``height`` or ``alpha`` is out of range, ``league`` has no ESPN headshots, or
238
+ ``id_system`` is not valid for ``league``.
239
+ ValueError: If the inputs differ in length; when the plot renders, if its figure has no pixel height (no
240
+ ``frame_height`` or ``height`` option).
241
+ TypeError: If the current HoloViews backend is not Bokeh.
242
+ UnsupportedTargetError: (a TypeError) If ``element`` is not a HoloViews element or overlay.
243
+ OfflineError: If the nflverse player table (``id_system="gsis"``), or with ``embed=True`` a headshot, is neither
244
+ cached nor downloadable (a DownloadError, also an OSError, for an HTTP error status).
245
+ UnsafeDownloadError: (an OSError) If a download is refused: larger than the byte cap, past the deadline, or
246
+ redirected away from https.
247
+
248
+ Example:
249
+ ::
250
+
251
+ import holoviews as hv
252
+ import sdvplot
253
+
254
+ hv.extension("bokeh")
255
+ sdvplot.add_headshots(hv.Scatter([(0.5, 0.5)]), [0.5], [0.5], ["3139477"], league="nfl", height=0.2)
256
+
257
+ See Also:
258
+ sdvplotR geom_nfl_headshots(): https://sdvplotR.sportsdataverse.org/
259
+ """
260
+ return _add(
261
+ element, x, y, players, kind="headshot", league=league, season=None, height=height, alpha=alpha,
262
+ variant="default", embed=embed, id_system=id_system,
263
+ ) # fmt: skip
264
+
265
+
266
+ def axis_logos(target: Any, axis: str, **kwargs: Any) -> Any:
267
+ """Not supported on HoloViews (it draws through Bokeh, which has no axis logos yet).
268
+
269
+ Args:
270
+ target: A HoloViews element.
271
+ axis: "x" or "y".
272
+ **kwargs: Ignored.
273
+
274
+ Returns:
275
+ object: Never returns.
276
+
277
+ Raises:
278
+ UnsupportedTargetError: (a TypeError) Always. Draw the logos inside the plot with ``add_logos``, or use the
279
+ matplotlib, Plotly or Altair adapter for axis logos.
280
+
281
+ Example:
282
+ ::
283
+
284
+ import holoviews as hv
285
+ import sdvplot
286
+
287
+ try:
288
+ sdvplot.axis_logos(hv.Bars([("KC", 12)]), "x", league="nfl")
289
+ except TypeError:
290
+ pass # raised: HoloViews has no axis logos yet
291
+
292
+ See Also:
293
+ sdvplotR element_sdv_logo(): https://sdvplotR.sportsdataverse.org/
294
+ """
295
+ raise UnsupportedTargetError(
296
+ "HoloViews has no axis logos yet (its Bokeh plots cannot hold them): draw them inside the plot with "
297
+ "add_logos, or use matplotlib, Plotly or Altair for axis logos"
298
+ )
299
+
300
+
301
+ def _drawn_marks(target: Any) -> list[tuple[Any, ...]]:
302
+ """Test hook: render the element with Bokeh and read the marks the hook drew."""
303
+ return _bokeh._drawn_marks(hv.render(target, backend="bokeh"))