plot-io 0.12.0__py3-none-win_amd64.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 (130) hide show
  1. plot_io/__init__.py +73 -0
  2. plot_io/_methods.py +1691 -0
  3. plot_io/_native/__init__.py +199 -0
  4. plot_io/_native/__main__.py +197 -0
  5. plot_io/_native/_api.py +457 -0
  6. plot_io/_native/bin/windows-x86_64.dll +0 -0
  7. plot_io/_native/kernels.py +335 -0
  8. plot_io/_native/manifest.json +49 -0
  9. plot_io/axis.py +1347 -0
  10. plot_io/boxes.py +1156 -0
  11. plot_io/canvas.py +389 -0
  12. plot_io/color/__init__.py +3 -0
  13. plot_io/color/data.py +1646 -0
  14. plot_io/color/maps.py +922 -0
  15. plot_io/color/values.py +295 -0
  16. plot_io/color/variants.py +1246 -0
  17. plot_io/colorbar.py +1426 -0
  18. plot_io/columns.py +614 -0
  19. plot_io/decorations.py +920 -0
  20. plot_io/defaults.py +809 -0
  21. plot_io/density.py +113 -0
  22. plot_io/ext.py +68 -0
  23. plot_io/facets.py +240 -0
  24. plot_io/figure.py +788 -0
  25. plot_io/formatters.py +97 -0
  26. plot_io/genome/__init__.py +17 -0
  27. plot_io/genome/adapters.py +356 -0
  28. plot_io/genome/combine.py +123 -0
  29. plot_io/genome/contacts.py +508 -0
  30. plot_io/genome/intervals.py +750 -0
  31. plot_io/genome/lanes.py +191 -0
  32. plot_io/genome/layout.py +184 -0
  33. plot_io/genome/links.py +364 -0
  34. plot_io/genome/pack.py +27 -0
  35. plot_io/genome/readers.py +145 -0
  36. plot_io/genome/regions.py +228 -0
  37. plot_io/genome/scale.py +349 -0
  38. plot_io/genome/series.py +344 -0
  39. plot_io/genome/signal.py +621 -0
  40. plot_io/genome/sites.py +782 -0
  41. plot_io/genome/sources.py +459 -0
  42. plot_io/genome/testing.py +161 -0
  43. plot_io/geometry.py +289 -0
  44. plot_io/groups.py +308 -0
  45. plot_io/guides.py +503 -0
  46. plot_io/helpers/__init__.py +17 -0
  47. plot_io/helpers/clustermap.py +202 -0
  48. plot_io/helpers/dendrogram.py +172 -0
  49. plot_io/helpers/grids.py +304 -0
  50. plot_io/helpers/qq.py +334 -0
  51. plot_io/helpers/raincloud.py +249 -0
  52. plot_io/helpers/tree.py +214 -0
  53. plot_io/helpers/volcano.py +505 -0
  54. plot_io/hints.py +125 -0
  55. plot_io/kernels.py +740 -0
  56. plot_io/labels.py +566 -0
  57. plot_io/layers/__init__.py +100 -0
  58. plot_io/layers/base.py +630 -0
  59. plot_io/layers/context.py +87 -0
  60. plot_io/layers/core.py +446 -0
  61. plot_io/layers/geoms.py +1362 -0
  62. plot_io/layers/grammar.py +586 -0
  63. plot_io/layers/paint.py +614 -0
  64. plot_io/layers/pipeline.py +170 -0
  65. plot_io/layers/positions.py +431 -0
  66. plot_io/layers/stats.py +1088 -0
  67. plot_io/layout.py +1381 -0
  68. plot_io/legend.py +605 -0
  69. plot_io/levels.py +509 -0
  70. plot_io/limits.py +124 -0
  71. plot_io/lines.py +42 -0
  72. plot_io/mapped.py +522 -0
  73. plot_io/markers.py +110 -0
  74. plot_io/markup.py +128 -0
  75. plot_io/numbers.py +354 -0
  76. plot_io/occupancy.py +295 -0
  77. plot_io/plot.py +597 -0
  78. plot_io/presets/__init__.py +51 -0
  79. plot_io/presets/_util.py +153 -0
  80. plot_io/presets/area.py +145 -0
  81. plot_io/presets/bar.py +261 -0
  82. plot_io/presets/box.py +400 -0
  83. plot_io/presets/catpoints.py +177 -0
  84. plot_io/presets/contour.py +353 -0
  85. plot_io/presets/curves.py +30 -0
  86. plot_io/presets/dots.py +355 -0
  87. plot_io/presets/ecdf.py +97 -0
  88. plot_io/presets/errorbar.py +106 -0
  89. plot_io/presets/errors.py +296 -0
  90. plot_io/presets/fill.py +74 -0
  91. plot_io/presets/heatmap.py +322 -0
  92. plot_io/presets/hexbin.py +198 -0
  93. plot_io/presets/hist.py +391 -0
  94. plot_io/presets/hist2d.py +87 -0
  95. plot_io/presets/kde.py +162 -0
  96. plot_io/presets/kde2d.py +147 -0
  97. plot_io/presets/line.py +143 -0
  98. plot_io/presets/pie.py +502 -0
  99. plot_io/presets/regression.py +115 -0
  100. plot_io/presets/scatter.py +194 -0
  101. plot_io/presets/stem.py +100 -0
  102. plot_io/presets/violin.py +323 -0
  103. plot_io/py.typed +0 -0
  104. plot_io/registry.py +82 -0
  105. plot_io/render.py +480 -0
  106. plot_io/rows.py +491 -0
  107. plot_io/scales.py +103 -0
  108. plot_io/seams.py +138 -0
  109. plot_io/settings.py +807 -0
  110. plot_io/shapes.py +66 -0
  111. plot_io/sharing.py +232 -0
  112. plot_io/sizemaps.py +97 -0
  113. plot_io/spec.py +240 -0
  114. plot_io/states.py +216 -0
  115. plot_io/styles/__init__.py +307 -0
  116. plot_io/styles/library.py +397 -0
  117. plot_io/tables.py +138 -0
  118. plot_io/text.py +412 -0
  119. plot_io/ticks.py +400 -0
  120. plot_io/times.py +287 -0
  121. plot_io/titles.py +225 -0
  122. plot_io/transform.py +114 -0
  123. plot_io/types.py +13604 -0
  124. plot_io/units.py +768 -0
  125. plot_io/validators.py +1029 -0
  126. plot_io/values.py +190 -0
  127. plot_io-0.12.0.dist-info/METADATA +215 -0
  128. plot_io-0.12.0.dist-info/RECORD +130 -0
  129. plot_io-0.12.0.dist-info/WHEEL +4 -0
  130. plot_io-0.12.0.dist-info/licenses/LICENSE +28 -0
plot_io/canvas.py ADDED
@@ -0,0 +1,389 @@
1
+ """The canvas plot_io draws on, and a canvas that records the drawing.
2
+
3
+ :class:`Canvas` is the protocol of what plot_io calls: drawing state attributes, the
4
+ transform, clips, groups and vec_io's drawing calls, typed as ``vec_io.Page``'s; a vec_io
5
+ page is one. ``document`` gives the font database text is shaped with and the points per
6
+ unit (:class:`CanvasDocument`).
7
+
8
+ :class:`Recording` is a canvas that draws nothing: it records each call and each state
9
+ assignment, in order, as plain data (``items``, ``dump()``, ``digest()``), so a figure's
10
+ drawing can be compared under any vec_io version. Text is still measured with vec_io's
11
+ fonts (the recording's ``font_db``).
12
+ """
13
+
14
+ import contextlib
15
+ import hashlib
16
+ import json
17
+ import math
18
+ from collections.abc import Generator, Sequence
19
+ from contextlib import AbstractContextManager
20
+ from typing import Any, Protocol, Unpack, overload
21
+
22
+ import vec_io
23
+ from vec_io.types import ArrayLike, Dashes, ItemStyle, LineStyle, PaintLike, SegmentStyle
24
+
25
+ __all__ = ["Canvas", "CanvasDocument", "Recording"]
26
+
27
+
28
+ class CanvasDocument(Protocol):
29
+ """What plot_io reads of a canvas' document: the font database text is shaped with and
30
+ the points per canvas unit (``0.75`` for px)."""
31
+
32
+ @property
33
+ def font_db(self) -> Any: ...
34
+
35
+ @property
36
+ def points_per_unit(self) -> float: ...
37
+
38
+
39
+ class Canvas(Protocol):
40
+ """The drawing surface plot_io draws on (a ``vec_io.Page`` is one): drawing state
41
+ attributes, the transform and clip, groups and vec_io's drawing calls, with
42
+ ``vec_io.Page``'s signatures."""
43
+
44
+ fill: vec_io.Paint
45
+ stroke: vec_io.Paint
46
+ stroke_width: float
47
+ stroke_linecap: str
48
+ stroke_linejoin: str
49
+ stroke_dasharray: Any
50
+ opacity: float
51
+ text_anchor: str
52
+
53
+ @property
54
+ def document(self) -> CanvasDocument: ...
55
+
56
+ def state(self, **style: Unpack[vec_io.Style]) -> AbstractContextManager[Any]: ...
57
+
58
+ def translate(self, tx: float, ty: float) -> None: ...
59
+
60
+ def scale(self, sx: float, sy: float | None = None) -> None: ...
61
+
62
+ def rotate(self, degrees: float, cx: float = 0.0, cy: float = 0.0) -> None: ...
63
+
64
+ @overload
65
+ def transform(self, a: vec_io.Matrix) -> None: ...
66
+
67
+ @overload
68
+ def transform(self, a: float, b: float, c: float, d: float, e: float, f: float) -> None: ...
69
+
70
+ def clip(self, path: vec_io.Path | str, *, clip_rule: str | None = None) -> None: ...
71
+
72
+ def group(self, *, opacity: float = 1.0, rasterize: bool = False,
73
+ dpi: float | None = None) -> AbstractContextManager[Any]: ...
74
+
75
+ def draw_rect(self, x: float, y: float, width: float, height: float, *, rx: float = 0.0,
76
+ ry: float | None = None, **style: Unpack[vec_io.Style]) -> None: ...
77
+
78
+ def draw_path(self, path: vec_io.Path | str, **style: Unpack[vec_io.Style]) -> None: ...
79
+
80
+ def draw_text(self, text: "str | vec_io.Content | vec_io.GlyphRun", x: float, y: float,
81
+ **style: Unpack[vec_io.Style]) -> None: ...
82
+
83
+ def draw_markers(self, x: ArrayLike, y: ArrayLike, *,
84
+ marker: "vec_io.Path | str | vec_io.Marker | Sequence[vec_io.Path | str]"
85
+ " | None" = None,
86
+ size: float | ArrayLike = 6.0, fill: PaintLike = ...,
87
+ stroke: PaintLike = ..., stroke_width: float | ArrayLike | None = None,
88
+ opacity: float | ArrayLike = 1.0,
89
+ simplify: bool | float | str | None = None,
90
+ **style: Unpack[ItemStyle]) -> None: ...
91
+
92
+ def draw_lines(self, x: ArrayLike | Sequence[ArrayLike],
93
+ y: ArrayLike | Sequence[ArrayLike], *, stroke: PaintLike = ...,
94
+ stroke_width: float | ArrayLike | None = None,
95
+ stroke_dasharray: Dashes | Sequence[Dashes] = None,
96
+ opacity: float | ArrayLike = 1.0,
97
+ stroke_linecap: str | None = None, stroke_linejoin: str | None = None,
98
+ simplify: bool | float | str | None = None,
99
+ interpolation: str | Sequence[str] = "linear", missing: str = "break",
100
+ **style: Unpack[LineStyle]) -> None: ...
101
+
102
+ def draw_segments(self, x0: float | ArrayLike, y0: float | ArrayLike,
103
+ x1: float | ArrayLike, y1: float | ArrayLike, *,
104
+ stroke: PaintLike = ..., stroke_width: float | ArrayLike | None = None,
105
+ opacity: float | ArrayLike = 1.0, stroke_linecap: str | None = None,
106
+ simplify: bool | float | str | None = None,
107
+ **style: Unpack[SegmentStyle]) -> None: ...
108
+
109
+ def draw_rects(self, x: float | ArrayLike, y: float | ArrayLike,
110
+ width: float | ArrayLike, height: float | ArrayLike, *,
111
+ fill: PaintLike = ..., stroke: PaintLike = ...,
112
+ stroke_width: float | ArrayLike | None = None,
113
+ opacity: float | ArrayLike = 1.0,
114
+ simplify: bool | float | str | None = None,
115
+ **style: Unpack[ItemStyle]) -> None: ...
116
+
117
+ def draw_polygons(self, paths: "Sequence[vec_io.Path | str] | tuple[ArrayLike, ...]", *,
118
+ fill: PaintLike = ..., stroke: PaintLike = None,
119
+ stroke_width: float | ArrayLike | None = None,
120
+ opacity: float | ArrayLike = 1.0,
121
+ simplify: bool | float | str | None = None,
122
+ **style: Unpack[ItemStyle]) -> None: ...
123
+
124
+ def draw_area(self, x: ArrayLike, y1: ArrayLike, y2: float | ArrayLike = 0.0, *,
125
+ fill: vec_io.Paint = ..., stroke: vec_io.Paint = None,
126
+ stroke_width: float | None = None, opacity: float = 1.0,
127
+ simplify: bool | float | str | None = None,
128
+ interpolation: str = "linear", missing: str = "break",
129
+ **style: Unpack[ItemStyle]) -> None: ...
130
+
131
+ def draw_cells(self, x_edges: ArrayLike, y_edges: ArrayLike, fill: Any, *,
132
+ palette: Sequence[vec_io.ColorLike] | None = None,
133
+ bounds: ArrayLike | None = None, bad: vec_io.ColorLike | None = None,
134
+ mode: str = "image", opacity: float = 1.0) -> None: ...
135
+
136
+ def draw_paragraphs(self, paragraphs: "vec_io.text.Paragraphs", x: float, y: float,
137
+ **style: Unpack[vec_io.Style]) -> None: ...
138
+
139
+
140
+ #: The drawing state attributes of :class:`Canvas` and their values on a new canvas.
141
+ _STATE = {"fill": "black", "stroke": None, "stroke_width": 1.0, "stroke_linecap": "butt",
142
+ "stroke_linejoin": "miter", "stroke_dasharray": None, "opacity": 1.0,
143
+ "text_anchor": "start"}
144
+
145
+ #: The names of the positional arguments of each call (to read each value in its unit).
146
+ _POSITIONAL = {
147
+ "state": (), "group": (), "translate": ("tx", "ty"), "scale": ("sx", "sy"),
148
+ "rotate": ("degrees", "cx", "cy"), "transform": ("a", "b", "c", "d", "e", "f"),
149
+ "clip": ("path",), "draw_rect": ("x", "y", "width", "height"), "draw_path": ("path",),
150
+ "draw_text": ("text", "x", "y"), "draw_markers": ("x", "y"), "draw_lines": ("x", "y"),
151
+ "draw_segments": ("x0", "y0", "x1", "y1"), "draw_rects": ("x", "y", "width", "height"),
152
+ "draw_polygons": ("paths",), "draw_area": ("x", "y1", "y2"),
153
+ "draw_cells": ("x_edges", "y_edges", "fill"),
154
+ "draw_paragraphs": ("paragraphs", "x", "y"),
155
+ }
156
+
157
+ #: Arguments in px, rounded to 1/64 px (:data:`plot_io.geometry.GRID`); colours are kept
158
+ #: as given; other numbers keep 12 significant digits.
159
+ _PX = frozenset({"tx", "ty", "cx", "cy", "e", "f", "path", "paths", "x", "y", "x0", "y0",
160
+ "x1", "y1", "y2", "width", "height", "rx", "ry", "size", "stroke_width",
161
+ "stroke_dasharray", "x_edges", "y_edges", "text", "paragraphs"})
162
+ _COLORS = frozenset({"fill", "stroke", "palette", "bad"})
163
+ _GRID = 64
164
+
165
+
166
+ def _number(v: float, px: bool) -> float:
167
+ if not math.isfinite(v):
168
+ return v
169
+ r = round(v * _GRID) / _GRID if px else float(f"{v:.12g}")
170
+ return 0.0 if r == 0 else r
171
+
172
+
173
+ def _run(run: Any) -> dict[str, Any]:
174
+ """A glyph run as its text and its segments (see :func:`_glyphs`)."""
175
+ return {"text": run.text, "segments": _glyphs(run.glyphs)}
176
+
177
+
178
+ def _glyphs(glyphs: Any) -> list[list[Any]]:
179
+ """Glyphs as segments ``[text, font, size, advance, colour, synthetic]``: consecutive
180
+ glyphs of one face, size, colour and synthetic bold and italic."""
181
+ out: list[list[Any]] = []
182
+ key = None
183
+ for g in glyphs:
184
+ k = (g.face.postscript_name, g.style.size, g.style.color, list(g.synth))
185
+ if k != key:
186
+ out.append(["", k[0], k[1], 0.0, k[2], k[3]])
187
+ key = k
188
+ out[-1][0] += g.text
189
+ out[-1][3] += g.advance + g.adjust
190
+ for seg in out:
191
+ seg[2:5] = _number(seg[2], False), _number(seg[3], True), _plain(seg[4], "color")
192
+ return out
193
+
194
+
195
+ def _lines(paragraphs: Any) -> list[Any]:
196
+ """Placed paragraph lines: x offset, baseline and segments."""
197
+ return [[_number(ln.offset, True), _number(ln.baseline, True), _glyphs(ln.glyphs)]
198
+ for ln in paragraphs.line_cells() if ln.glyphs]
199
+
200
+
201
+ def _plain(value: Any, kind: str = "px") -> Any:
202
+ """``value`` as JSON data: numbers rounded by ``kind`` (``"px"``: to 1/64 px;
203
+ ``"color"``: as given; else 12 significant digits), paths as their segments, glyph
204
+ runs as their text and segments, sequences and buffers as lists, objects as their
205
+ class name and fields."""
206
+ if value is None or isinstance(value, (bool, str)):
207
+ return value
208
+ if isinstance(value, int):
209
+ return value
210
+ if isinstance(value, float):
211
+ return value if kind == "color" else _number(value, kind == "px")
212
+ if isinstance(value, vec_io.Path):
213
+ return [[s[0], *(_plain(v, kind) for v in s[1:])] for s in value]
214
+ if isinstance(value, vec_io.GlyphRun):
215
+ return _run(value)
216
+ if isinstance(value, vec_io.Matrix):
217
+ return ["Matrix", *(_plain(float(v), "") for v in (value.a, value.b, value.c, value.d)),
218
+ _plain(float(value.e), kind), _plain(float(value.f), kind)]
219
+ if hasattr(value, "line_cells"):
220
+ return _lines(value)
221
+ if hasattr(value, "tolist") and not isinstance(value, type):
222
+ return _plain(value.tolist(), kind)
223
+ if isinstance(value, dict):
224
+ return {str(k): _plain(v, kind) for k, v in value.items()}
225
+ if isinstance(value, (list, tuple)):
226
+ return [_plain(v, kind) for v in value]
227
+ if isinstance(value, (bytes, bytearray)):
228
+ return value.hex()
229
+ fields = getattr(type(value), "__slots__", None) or getattr(value, "__dict__", None)
230
+ if fields:
231
+ names = [fields] if isinstance(fields, str) else list(fields)
232
+ return {"type": type(value).__name__,
233
+ **{n: _plain(getattr(value, n), kind) for n in names
234
+ if not n.startswith("_") and hasattr(value, n)}}
235
+ text = repr(value)
236
+ if " at 0x" in text:
237
+ raise TypeError(f"a recording cannot record {type(value).__name__} values")
238
+ return text
239
+
240
+
241
+ def _kind(name: str) -> str:
242
+ return "px" if name in _PX else "color" if name in _COLORS else ""
243
+
244
+
245
+ class _Document:
246
+ """The document of a :class:`Recording`: px (``points_per_unit`` 0.75) and its font
247
+ database."""
248
+
249
+ points_per_unit = 0.75
250
+
251
+ def __init__(self, font_db: Any) -> None:
252
+ self.font_db = font_db
253
+
254
+
255
+ class Recording:
256
+ """A :class:`Canvas` ``width`` × ``height`` px that draws nothing and records what is
257
+ drawn on it: each call and each state assignment is one item ``(member, args,
258
+ keywords)``, in order, as plain data (numbers in px rounded to 1/64 px, paths as their
259
+ segments, glyph runs as their text, font, size and advance, colours as given). A
260
+ ``with`` block of ``state()`` or ``group()`` ends with the item ``("end",
261
+ (member,), {})``. Text is shaped with ``font_db`` (default: the font database plot_io
262
+ writes with).
263
+
264
+ ``items``: the items; ``dump()``: one JSON line per item; ``digest()``: the SHA-256 of
265
+ the dump. :meth:`add` records an item: a subclass extends it to see the values as
266
+ given."""
267
+
268
+ fill: vec_io.Paint
269
+ stroke: vec_io.Paint
270
+ stroke_width: float
271
+ stroke_linecap: str
272
+ stroke_linejoin: str
273
+ stroke_dasharray: Any
274
+ opacity: float
275
+ text_anchor: str
276
+ width: float
277
+ height: float
278
+ items: list[tuple[str, tuple[Any, ...], dict[str, Any]]]
279
+ _document: _Document
280
+ _saved: list[dict[str, Any]]
281
+
282
+ def __init__(self, width: float, height: float, font_db: Any = None) -> None:
283
+ if font_db is None:
284
+ from .render import font_db_of, fonts_of
285
+ font_db = font_db_of(fonts_of(None, {}))
286
+ object.__setattr__(self, "width", float(width))
287
+ object.__setattr__(self, "height", float(height))
288
+ object.__setattr__(self, "items", [])
289
+ object.__setattr__(self, "_document", _Document(font_db))
290
+ object.__setattr__(self, "_saved", [])
291
+ for name, value in _STATE.items():
292
+ object.__setattr__(self, name, value)
293
+
294
+ @property
295
+ def document(self) -> CanvasDocument:
296
+ return self._document
297
+
298
+ def __setattr__(self, name: str, value: Any) -> None:
299
+ if name in _STATE:
300
+ self.add(name, (value,), {})
301
+ object.__setattr__(self, name, value)
302
+
303
+ def add(self, member: str, args: tuple[Any, ...], keywords: dict[str, Any]) -> None:
304
+ """Record call ``member(*args, **keywords)`` (or, for a state attribute, its
305
+ assignment: ``args`` is the value)."""
306
+ names = (member,) if member in _STATE else _POSITIONAL.get(member, ())
307
+ plain_args = tuple(_plain(v, _kind(names[k]) if k < len(names) else "")
308
+ for k, v in enumerate(args))
309
+ plain_kw = {k: _plain(v, _kind(k)) for k, v in keywords.items()}
310
+ self.items.append((member, plain_args, plain_kw))
311
+
312
+ def dump(self) -> str:
313
+ """The items, one JSON line each (``[member, args, keywords]``)."""
314
+ return "".join(json.dumps([m, list(a), k], sort_keys=True, separators=(",", ":"))
315
+ + "\n" for m, a, k in self.items)
316
+
317
+ def digest(self) -> str:
318
+ """The SHA-256 (hex) of :meth:`dump`."""
319
+ return hashlib.sha256(self.dump().encode()).hexdigest()
320
+
321
+ @contextlib.contextmanager
322
+ def _scope(self, member: str, keywords: dict[str, Any]) -> Generator["Recording"]:
323
+ self.add(member, (), keywords)
324
+ self._saved.append({k: getattr(self, k) for k in _STATE})
325
+ for k, v in keywords.items():
326
+ if k in _STATE:
327
+ object.__setattr__(self, k, v)
328
+ try:
329
+ yield self
330
+ finally:
331
+ for k, v in self._saved.pop().items():
332
+ object.__setattr__(self, k, v)
333
+ self.add("end", (member,), {})
334
+
335
+ def state(self, **style: Any) -> AbstractContextManager["Recording"]:
336
+ return self._scope("state", style)
337
+
338
+ def group(self, **options: Any) -> AbstractContextManager["Recording"]:
339
+ return self._scope("group", options)
340
+
341
+ def translate(self, *args: Any, **kw: Any) -> None:
342
+ self.add("translate", args, kw)
343
+
344
+ def scale(self, *args: Any, **kw: Any) -> None:
345
+ self.add("scale", args, kw)
346
+
347
+ def rotate(self, *args: Any, **kw: Any) -> None:
348
+ self.add("rotate", args, kw)
349
+
350
+ def transform(self, *args: Any, **kw: Any) -> None:
351
+ self.add("transform", args, kw)
352
+
353
+ def clip(self, *args: Any, **kw: Any) -> None:
354
+ self.add("clip", args, kw)
355
+
356
+ def draw_rect(self, *args: Any, **kw: Any) -> None:
357
+ self.add("draw_rect", args, kw)
358
+
359
+ def draw_path(self, *args: Any, **kw: Any) -> None:
360
+ self.add("draw_path", args, kw)
361
+
362
+ def draw_text(self, *args: Any, **kw: Any) -> None:
363
+ self.add("draw_text", args, kw)
364
+
365
+ def draw_markers(self, *args: Any, **kw: Any) -> None:
366
+ self.add("draw_markers", args, kw)
367
+
368
+ def draw_lines(self, *args: Any, **kw: Any) -> None:
369
+ self.add("draw_lines", args, kw)
370
+
371
+ def draw_segments(self, *args: Any, **kw: Any) -> None:
372
+ self.add("draw_segments", args, kw)
373
+
374
+ def draw_rects(self, *args: Any, **kw: Any) -> None:
375
+ self.add("draw_rects", args, kw)
376
+
377
+ def draw_polygons(self, *args: Any, **kw: Any) -> None:
378
+ self.add("draw_polygons", args, kw)
379
+
380
+ def draw_area(self, *args: Any, **kw: Any) -> None:
381
+ self.add("draw_area", args, kw)
382
+
383
+ def draw_cells(self, *args: Any, **kw: Any) -> None:
384
+ self.add("draw_cells", args, kw)
385
+
386
+ def draw_paragraphs(self, *args: Any, **kw: Any) -> None:
387
+ """Paragraphs (``vec_io.text`` ``Paragraphs``) with the top-left corner of their box
388
+ at ``(x, y)``: recorded as their placed lines (x offset, baseline, segments)."""
389
+ self.add("draw_paragraphs", args, kw)
@@ -0,0 +1,3 @@
1
+ """Colors: values and named scales (:mod:`.values`), color maps, every set of colors with
2
+ its kind: qualitative, sequential, diverging, cyclic (:mod:`.maps`), and the bundled data
3
+ (:mod:`.data`). Color space conversions are vec_io's (:mod:`vec_io.paint`)."""