|
| 1 | +# anyplotlib 0.1.0 — first public release |
| 2 | + |
| 3 | +**anyplotlib** is a plotting library built on Python, JavaScript, and |
| 4 | +[anywidget](https://anywidget.dev/) for fast, interactive, in-browser plotting |
| 5 | +— in Jupyter, in the docs, and (new in this release) embedded in standalone apps. |
| 6 | + |
| 7 | +This first release ships the full core: `Figure`, `Axes`, `GridSpec` / |
| 8 | +`subplots`, the `Plot1D` / `Plot2D` / `PlotMesh` / `Plot3D` / `PlotBar` / |
| 9 | +`PlotXY` plot types, a marker system, interactive overlay widgets, and a |
| 10 | +two-tier callback registry. |
| 11 | + |
| 12 | +## Install |
| 13 | + |
| 14 | +```bash |
| 15 | +pip install anyplotlib |
| 16 | +``` |
| 17 | + |
| 18 | +Requires Python ≥ 3.10. Optional extras: `anyplotlib[jupyter]`, `anyplotlib[docs]`. |
| 19 | + |
| 20 | +## Highlights |
| 21 | + |
| 22 | +### New plotting surfaces |
| 23 | +- **`PlotXY` / `Axes.axes2d`** — a blank data-coordinate 2-D axis (matplotlib |
| 24 | + `transData` + `PathCollection` model). Draw `scatter` / `plot` / `fill` / |
| 25 | + `text` in data coords with per-point face/edge colours and `aspect="equal"` |
| 26 | + — the surface for stereographic / IPF / pole-figure plots (e.g. an `orix` |
| 27 | + backend). |
| 28 | +- **Fast density heatmaps** — `PlotXY.pcolormesh` rasterizes regular meshes into |
| 29 | + a single blit whose cost is independent of cell count (a 256×256 heatmap draws |
| 30 | + as fast as 32×32). The underlying `add_raster` primitive draws an RGBA image |
| 31 | + between data-coord corners, with an optional `clip_path` polygon and a |
| 32 | + `smooth=True` bilinear option. |
| 33 | +- **`InsetAxes`** — floating overlay sub-plots above the main grid (`add_inset`), |
| 34 | + supporting every plot type plus interactive minimise / maximise / restore. |
| 35 | +- **True-colour `imshow`** — `(H, W, 3|4)` arrays now render as RGB(A) instead of |
| 36 | + silently dropping channels. |
| 37 | + |
| 38 | +### 3-D and GPU |
| 39 | +- **`Axes.voxels()`** — volumes as shaded translucent cubes, with a draggable |
| 40 | + `PlaneWidget` slice selector that fires `pointer_move` / `pointer_up` |
| 41 | + callbacks; voxels on the slice plane glow. |
| 42 | +- **WebGPU acceleration** — `scatter3d` and `voxels` render on the GPU via WebGPU |
| 43 | + when available (`gpu="auto"`), with a transparent, identical-looking Canvas2D |
| 44 | + fallback when no GPU is present. Query the active path with `plot.gpu_active`. |
| 45 | +- **Richer 3-D scatter** — per-point `colors=`, a `bounds=` override, single-point |
| 46 | + `set_highlight()`, a shaded reference `set_sphere()`, and a proper turntable |
| 47 | + camera (matplotlib `azim` / `elev` semantics). |
| 48 | + |
| 49 | +### Interactivity |
| 50 | +- **Touch support** — one-finger pan / orbit / drag, two-finger pinch zoom, and |
| 51 | + double-tap, on iPad / iPhone / trackpads, with no API change. |
| 52 | +- **Data-coordinate picking** — `double_click` on 1-D / `PlotXY` panels now |
| 53 | + reports `ydata` alongside `xdata`. |
| 54 | +- **Typography** — `fontsize` on labels/titles/colorbars, `set_tick_label_size()`, |
| 55 | + and a mini-TeX subset inside `$...$` (super/subscripts, Greek, `\times`, `\AA`, |
| 56 | + `\degree`) rendered natively on the canvas; text is no longer clipped. |
| 57 | + |
| 58 | +### Performance |
| 59 | +- **Geometry sync channel** — large, slow-changing buffers are deduped by content |
| 60 | + hash, so view-only updates (highlight, view, zoom, widget drags) no longer |
| 61 | + re-transmit geometry. |
| 62 | +- **`Figure.batch()`** — coalesces panel pushes so linked-view handlers send one |
| 63 | + update per changed panel instead of one per mutation. |
| 64 | +- **Voxels ~2–3× faster** via sprite caching and cached projection/depth-sort. |
| 65 | +- **~50× faster Pyodide dispatch** — interactions call a pre-compiled dispatcher |
| 66 | + instead of recompiling Python source every frame, so the interactive docs keep |
| 67 | + up with gestures. |
| 68 | + |
| 69 | +### Embedding outside Jupyter |
| 70 | +- `fig.save_html()` / `fig.to_html()` export a self-contained interactive page. |
| 71 | +- `figure_esm.js` exports a `mount(el, state, opts)` entry point for direct JS |
| 72 | + embedding (Electron, MDI windows, plain web pages) with `onEvent` callbacks, |
| 73 | + live `setPanelState`, `resize`, and `dispose`. |
| 74 | +- The new `anyplotlib.embed` module provides `figure_state()`, `esm_path()`, and a |
| 75 | + transport-agnostic `FigureBridge` for two-way Python ↔ JS sync over any pipe. |
| 76 | + |
| 77 | +### Documentation tooling |
| 78 | +- The `anyplotlib.sphinx_anywidget` extension renders live, Pyodide-powered |
| 79 | + figures in the docs (`.. anywidget-figure::` directive, automatic wheel |
| 80 | + building, Sphinx Gallery integration). |
| 81 | + |
| 82 | +## Bug fixes |
| 83 | +- 3-D plane-widget drags no longer snap back (view-only pushes stop clobbering an |
| 84 | + in-progress drag). |
| 85 | +- GPU 3-D panels self-heal when a WebGPU device is lost mid-draw (no more vanishing |
| 86 | + voxels/axes until a window resize) — seen on Safari's experimental WebGPU. |
| 87 | +- Large voxel volumes no longer render "empty" in WebGPU browsers (e.g. PyCharm's |
| 88 | + JCEF) — the plot canvas background is now transparent while the GPU path is active. |
| 89 | +- The 3-D voxel highlight no longer floats onto random voxels in large volumes. |
| 90 | +- Interactive (⚡) docs figures are much smoother under Pyodide (the ~50× dispatch |
| 91 | + speedup above). |
| 92 | + |
| 93 | +## Full changelog |
| 94 | +See [`CHANGELOG.rst`](./CHANGELOG.rst) for the complete, detailed list. |
0 commit comments