anyplotlib 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 (42) hide show
  1. anyplotlib/__init__.py +53 -0
  2. anyplotlib/_base_plot.py +229 -0
  3. anyplotlib/_electron.py +74 -0
  4. anyplotlib/_repr_utils.py +345 -0
  5. anyplotlib/_utils.py +194 -0
  6. anyplotlib/axes/__init__.py +6 -0
  7. anyplotlib/axes/_axes.py +510 -0
  8. anyplotlib/axes/_inset_axes.py +126 -0
  9. anyplotlib/callbacks.py +328 -0
  10. anyplotlib/embed.py +194 -0
  11. anyplotlib/figure/__init__.py +7 -0
  12. anyplotlib/figure/_figure.py +633 -0
  13. anyplotlib/figure/_gridspec.py +99 -0
  14. anyplotlib/figure/_subplots.py +100 -0
  15. anyplotlib/figure_esm.js +6011 -0
  16. anyplotlib/markers.py +704 -0
  17. anyplotlib/plot1d/__init__.py +6 -0
  18. anyplotlib/plot1d/_plot1d.py +1376 -0
  19. anyplotlib/plot1d/_plotbar.py +436 -0
  20. anyplotlib/plot2d/__init__.py +5 -0
  21. anyplotlib/plot2d/_plot2d.py +726 -0
  22. anyplotlib/plot2d/_plotmesh.py +116 -0
  23. anyplotlib/plot3d/__init__.py +4 -0
  24. anyplotlib/plot3d/_plot3d.py +524 -0
  25. anyplotlib/plotxy/__init__.py +4 -0
  26. anyplotlib/plotxy/_plotxy.py +273 -0
  27. anyplotlib/sphinx_anywidget/__init__.py +177 -0
  28. anyplotlib/sphinx_anywidget/_directive.py +245 -0
  29. anyplotlib/sphinx_anywidget/_repr_utils.py +298 -0
  30. anyplotlib/sphinx_anywidget/_scraper.py +390 -0
  31. anyplotlib/sphinx_anywidget/_wheel_builder.py +84 -0
  32. anyplotlib/sphinx_anywidget/static/anywidget_bridge.js +1099 -0
  33. anyplotlib/sphinx_anywidget/static/anywidget_overlay.css +100 -0
  34. anyplotlib/widgets/__init__.py +18 -0
  35. anyplotlib/widgets/_base.py +218 -0
  36. anyplotlib/widgets/_widgets1d.py +109 -0
  37. anyplotlib/widgets/_widgets2d.py +141 -0
  38. anyplotlib/widgets/_widgets3d.py +50 -0
  39. anyplotlib-0.1.0.dist-info/METADATA +160 -0
  40. anyplotlib-0.1.0.dist-info/RECORD +42 -0
  41. anyplotlib-0.1.0.dist-info/WHEEL +4 -0
  42. anyplotlib-0.1.0.dist-info/licenses/LICENSE +21 -0
anyplotlib/_utils.py ADDED
@@ -0,0 +1,194 @@
1
+ """
2
+ _utils.py
3
+ =========
4
+ Shared low-level utilities used across plot subpackages.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import numpy as np
10
+
11
+ _LINESTYLE_ALIASES: dict[str, str] = {
12
+ "-": "solid",
13
+ "--": "dashed",
14
+ ":": "dotted",
15
+ "-.": "dashdot",
16
+ "solid": "solid",
17
+ "dashed": "dashed",
18
+ "dotted": "dotted",
19
+ "dashdot": "dashdot",
20
+ "step-mid": "step-mid",
21
+ "steps-mid": "step-mid",
22
+ }
23
+
24
+
25
+ def _arr_to_b64(arr: np.ndarray, dtype) -> str:
26
+ """Encode a NumPy array as base-64 (little-endian raw bytes).
27
+
28
+ Uses little-endian byte order so the result is compatible with
29
+ JavaScript's ``Float64Array`` / ``Float32Array`` / ``Int32Array``
30
+ on all modern platforms (x86, ARM).
31
+ """
32
+ import base64
33
+ le_dtype = np.dtype(dtype).newbyteorder("<")
34
+ return base64.b64encode(np.asarray(arr).astype(le_dtype).tobytes()).decode("ascii")
35
+
36
+
37
+ def _norm_linestyle(ls: str) -> str:
38
+ """Normalise a linestyle name or shorthand to its canonical form.
39
+
40
+ Accepted values
41
+ ---------------
42
+ ``"solid"`` / ``"-"``, ``"dashed"`` / ``"--"``,
43
+ ``"dotted"`` / ``":"``, ``"dashdot"`` / ``"-."``.
44
+
45
+ Raises
46
+ ------
47
+ ValueError
48
+ If *ls* is not a recognised name or shorthand.
49
+ """
50
+ canonical = _LINESTYLE_ALIASES.get(ls)
51
+ if canonical is None:
52
+ raise ValueError(
53
+ f"Unknown linestyle {ls!r}. Expected one of: "
54
+ "'solid', 'dashed', 'dotted', 'dashdot', 'step-mid' (alias: 'steps-mid') "
55
+ "or shorthands '-', '--', ':', '-.'."
56
+ )
57
+ return canonical
58
+
59
+
60
+ def _to_rgba_u8(data: np.ndarray) -> np.ndarray:
61
+ """Convert an (H, W, 3|4) colour array to uint8 RGBA.
62
+
63
+ Floats are interpreted as 0–1 (scaled ×255) when the max is ≤ 1,
64
+ otherwise as 0–255 and clipped. A missing alpha channel becomes 255.
65
+ """
66
+ data = np.asarray(data)
67
+ if data.ndim != 3 or data.shape[2] not in (3, 4):
68
+ raise ValueError(f"expected (H, W, 3|4) colour array, got {data.shape}")
69
+ if data.dtype != np.uint8:
70
+ arr = data.astype(np.float64)
71
+ if arr.max() <= 1.0:
72
+ arr = arr * 255.0
73
+ data = np.clip(arr, 0, 255).astype(np.uint8)
74
+ if data.shape[2] == 3:
75
+ rgba = np.empty((*data.shape[:2], 4), dtype=np.uint8)
76
+ rgba[..., :3] = data
77
+ rgba[..., 3] = 255
78
+ return rgba
79
+ return np.ascontiguousarray(data)
80
+
81
+
82
+ def _normalize_image(data: np.ndarray):
83
+ """Normalise data to uint8, returning (img_u8, vmin, vmax)."""
84
+ img = data.astype(np.float64, copy=False)
85
+ vmin = float(np.nanmin(img))
86
+ vmax = float(np.nanmax(img))
87
+ if vmax > vmin:
88
+ buf = np.empty_like(img)
89
+ np.subtract(img, vmin, out=buf)
90
+ np.divide(buf, vmax - vmin, out=buf)
91
+ np.multiply(buf, 255.0, out=buf)
92
+ img_u8 = buf.astype(np.uint8)
93
+ else:
94
+ img_u8 = np.zeros(data.shape, dtype=np.uint8)
95
+ return img_u8, vmin, vmax
96
+
97
+
98
+ # Mapping from common matplotlib colormap names to their nearest colorcet
99
+ # equivalents so callers can keep using familiar names without any matplotlib
100
+ # dependency.
101
+ _CMAP_ALIASES: dict[str, str] = {
102
+ "viridis": "bmy", # blue→magenta→yellow, perceptually uniform
103
+ "plasma": "fire", # warm sequential (dark→bright)
104
+ "inferno": "kb", # dark→blue→white
105
+ "magma": "kbc", # dark→blue→cyan sequential
106
+ "cividis": "bgy", # accessible, blue→green→yellow sequential
107
+ "hot": "fire",
108
+ "afmhot": "fire",
109
+ "jet": "rainbow4",
110
+ "hsv": "rainbow4",
111
+ "nipy_spectral": "rainbow4",
112
+ "RdBu": "coolwarm",
113
+ "bwr": "cwr", # blue→white→red diverging
114
+ "seismic": "coolwarm",
115
+ }
116
+
117
+
118
+ def _build_colormap_lut(name: str) -> list:
119
+ """Return a 256-entry ``[[r, g, b], ...]`` LUT for the named colormap.
120
+
121
+ Priority order:
122
+
123
+ 1. **colorcet** — preferred; common matplotlib names are remapped via
124
+ :data:`_CMAP_ALIASES` so callers can use ``"viridis"`` etc.
125
+ 2. **matplotlib** — fallback when colorcet is not installed (e.g. in
126
+ Pyodide before micropip finishes, or in minimal test environments).
127
+ 3. **Built-in gray ramp** — final fallback for unknown names.
128
+ """
129
+ # ── 1. Try colorcet ───────────────────────────────────────────────────
130
+ try:
131
+ import colorcet as cc
132
+ resolved = _CMAP_ALIASES.get(name, name)
133
+ palette = cc.palette.get(resolved)
134
+ if palette is not None:
135
+ n = len(palette)
136
+ lut: list = []
137
+ for i in range(256):
138
+ h = palette[int(round(i * (n - 1) / 255))].lstrip("#")
139
+ lut.append([int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)])
140
+ return lut
141
+ except Exception:
142
+ pass
143
+
144
+ # ── 2. Try matplotlib ─────────────────────────────────────────────────
145
+ try:
146
+ import matplotlib
147
+ import numpy as _np
148
+ cmap = matplotlib.colormaps[name]
149
+ rgba = cmap(_np.linspace(0, 1, 256))
150
+ return [[int(r * 255), int(g * 255), int(b * 255)]
151
+ for r, g, b, _ in rgba]
152
+ except Exception:
153
+ pass
154
+
155
+ # ── 3. Gray ramp fallback ─────────────────────────────────────────────
156
+ return [[v, v, v] for v in range(256)]
157
+
158
+
159
+ def _resample_mesh(data: np.ndarray, x_edges, y_edges) -> np.ndarray:
160
+ """Resample a mesh to a regular pixel grid via nearest-neighbour lookup.
161
+
162
+ For uniform edges this is an identity operation. For non-uniform edges
163
+ (e.g. log-spaced) it maps each uniform output pixel to the nearest input
164
+ cell, producing a visually correct linear-axis image.
165
+
166
+ Parameters
167
+ ----------
168
+ data : ndarray, shape (M, N) — one value per mesh cell.
169
+ x_edges : array-like, length N+1 — column edge coordinates.
170
+ y_edges : array-like, length M+1 — row edge coordinates.
171
+
172
+ Returns
173
+ -------
174
+ ndarray, shape (M, N)
175
+ """
176
+ rows, cols = data.shape
177
+ x_edges = np.asarray(x_edges, dtype=float)
178
+ y_edges = np.asarray(y_edges, dtype=float)
179
+
180
+ # Cell centres
181
+ x_c = (x_edges[:-1] + x_edges[1:]) / 2.0
182
+ y_c = (y_edges[:-1] + y_edges[1:]) / 2.0
183
+
184
+ # Uniform sample points (same count as original cells)
185
+ x_samp = np.linspace(x_c[0], x_c[-1], cols)
186
+ y_samp = np.linspace(y_c[0], y_c[-1], rows)
187
+
188
+ # Nearest-neighbour cell lookup via edge-sorted searchsorted
189
+ xi = np.searchsorted(x_edges, x_samp) - 1
190
+ xi = np.clip(xi, 0, cols - 1)
191
+ yi = np.searchsorted(y_edges, y_samp) - 1
192
+ yi = np.clip(yi, 0, rows - 1)
193
+
194
+ return data[np.ix_(yi, xi)]
@@ -0,0 +1,6 @@
1
+ """anyplotlib.axes — grid-cell and inset axes containers."""
2
+
3
+ from anyplotlib.axes._axes import Axes
4
+ from anyplotlib.axes._inset_axes import InsetAxes
5
+
6
+ __all__ = ["Axes", "InsetAxes"]