@photonviz/core 0.4.0 → 0.5.0
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.
- package/README.md +115 -4
- package/dist/index.d.ts +1297 -43
- package/dist/index.js +2802 -196
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
<a href="https://www.npmjs.com/package/@photonviz/core"><img src="https://img.shields.io/npm/v/@photonviz/core?color=cb3837&logo=npm" alt="npm"/></a>
|
|
11
11
|
<a href="https://www.npmjs.com/package/@photonviz/core"><img src="https://img.shields.io/npm/dm/@photonviz/core?color=cb3837" alt="downloads"/></a>
|
|
12
12
|
<a href="https://bundlephobia.com/package/@photonviz/core"><img src="https://img.shields.io/bundlephobia/minzip/@photonviz/core?label=minzip" alt="size"/></a>
|
|
13
|
+
· <a href="https://coredumpdev.github.io/photon/docs/">📖 Docs</a>
|
|
13
14
|
· <a href="https://coredumpdev.github.io/photon/">▶ Live demo</a>
|
|
15
|
+
· <a href="https://coredumpdev.github.io/photon/llms-full.txt">Docs for AI agents</a>
|
|
14
16
|
</p>
|
|
15
17
|
|
|
16
18
|
<p align="center">
|
|
@@ -49,8 +51,8 @@ plot.addLine({ x: xs, y: ys, color: "#60a5fa", width: 2, name: "signal" });
|
|
|
49
51
|
|
|
50
52
|
| Type | API |
|
|
51
53
|
| --- | --- |
|
|
52
|
-
| Line / Step | `plot.addLine({ x, y, color, width, step })` — real thick lines, round/miter/bevel joins |
|
|
53
|
-
| Scatter | `plot.addScatter({ x, y, size, colorBy })` — instanced
|
|
54
|
+
| Line / Step | `plot.addLine({ x, y, color, width, step, dash })` — real thick lines, round/miter/bevel joins, dashed guides |
|
|
55
|
+
| Scatter / Bubble | `plot.addScatter({ x, y, size, sizes, colors, colorBy })` — instanced; per-point size/colour or colormap by value |
|
|
54
56
|
| Bar | `plot.addBar({ x, y, width, offset, base })` — grouped / stacked |
|
|
55
57
|
| Area | `plot.addArea({ x, y, base })` |
|
|
56
58
|
| Histogram | `plot.addHistogram(values, { bins })` |
|
|
@@ -61,11 +63,117 @@ plot.addLine({ x: xs, y: ys, color: "#60a5fa", width: 2, name: "signal" });
|
|
|
61
63
|
| Error bar / Stem / Quiver | `plot.addErrorBar` · `addStem` · `addQuiver` |
|
|
62
64
|
| Candlestick / OHLC | `plot.addCandlestick({ x, open, high, low, close })` · `addOhlc(...)` — live via `updateLast` / `appendCandle` |
|
|
63
65
|
| Pie / Patches / Graph / Image | `plot.addPie` · `addPatches` · `addGraph` · `addImage` |
|
|
64
|
-
| **Finance** | `addHeikinAshi` · `addRenko` · `addBollinger` · `addVolumeProfile` · `addDepth` + indicators `sma`/`ema`/`wma`/`rsi`/`macd`/`vwap`/`atr`/`stochastic`/`keltner`/`obv`/`ichimoku`/`adx`/`superTrend`/`fibRetracements` |
|
|
66
|
+
| **Finance** | `addHeikinAshi` · `addRenko` · `addBollinger` · `addVolumeProfile` · `addDepth` · `addDrawdown` + indicators `sma`/`ema`/`wma`/`rsi`/`macd`/`vwap`/`atr`/`stochastic`/`keltner`/`obv`/`ichimoku`/`adx`/`superTrend`/`fibRetracements`/`cci`/`mfi`/`williamsR`/`aroon`/`donchian`/`parabolicSar`/`pivotPoints` + `resampleOhlc`/`drawdown` |
|
|
65
67
|
| **Diagrams** | `plot.addTreemap` · `addFunnel` · `addSunburst` · `addGauge` · `addSankey` · `addChord` · `addParallelCoordinates` — pure `*Layout` fns exported too |
|
|
68
|
+
| **ML / DL** | `addTrainingCurves` · `addConfusionMatrix` · `addRocCurve` · `addPrCurve` · `addCalibration` · `addEmbedding` · `addDecisionBoundary` · `addFeatureImportance` · `addShapBeeswarm` · `addPartialDependence` · `addAttentionMap` · `addRidgeline` · `addPredVsActual` · `addResiduals` · `addLiftCurve` · `addLearningCurve` + pure `confusionMatrix`/`rocCurve`/`prCurve`/`calibrationCurve`/`classificationReport`/`rocCurveOvR`/`liftCurve`/`r2`/`rmse`/`mae`/`logLoss`/`brierScore`/`pca` |
|
|
69
|
+
| **Statistics** | `addRegression` (OLS + CI band or LOESS) · `addEcdf` · `addCorrMatrix` · `addPsd` + pure `linearRegression`/`loess`/`ecdf`/`zscore`/`corrMatrix`/`welch`/`savitzkyGolay`/`crossCorrelate`/`windowFunction` |
|
|
70
|
+
| **Model architecture** | `addModelGraph(plot, { graph })` — layered DAG · `addModelGraph3D(plot3d, { graph })` — tensor-shaped blocks (see below) |
|
|
66
71
|
|
|
67
72
|
**Polar** — `new PolarPlot(el)` with `addLine` / `addScatter` (drag to rotate, wheel to zoom).
|
|
68
|
-
**3D** — `new Plot3D(el)` with `addSurface` / `addPointCloud` / `addLine3D` / `addBar3D` / `addQuiver3D` / `addContour3D` / `addIsosurface` / `addVolume` (orbit camera).
|
|
73
|
+
**3D** — `new Plot3D(el)` with `addSurface` / `addPointCloud` / `addLine3D` / `addBar3D` / `addBoxes3D` / `addQuiver3D` / `addContour3D` / `addIsosurface` / `addVolume` (orbit camera, perspective or orthographic).
|
|
74
|
+
|
|
75
|
+
## Model architecture graphs
|
|
76
|
+
|
|
77
|
+
Render the layers of a real model — in 2D as a Netron-style DAG, or in 3D as
|
|
78
|
+
cuboids sized from each layer's output tensor. Both consume the same
|
|
79
|
+
`ModelGraph`, so one export drives either view.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { Plot, Plot3D, addModelGraph, addModelGraph3D, modelGraphFromTorchFx } from "@photonviz/core";
|
|
83
|
+
|
|
84
|
+
const graph = modelGraphFromTorchFx(await (await fetch("/model.json")).json());
|
|
85
|
+
|
|
86
|
+
// Flat DAG — residual/skip edges route around the trunk, boxes colored by layer family.
|
|
87
|
+
addModelGraph(new Plot(el, { hover: false }), { graph, direction: "horizontal", sizeBy: "params" });
|
|
88
|
+
|
|
89
|
+
// Tensor blocks — feature maps shrink while channel depth grows.
|
|
90
|
+
addModelGraph3D(new Plot3D(el3d, { aspectMode: "data", showAxes: false, projection: "orthographic" }), { graph });
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Adapters (all pure, all zero-dependency) — dump the JSON in Python, load it in the browser:
|
|
94
|
+
|
|
95
|
+
<details><summary><b>PyTorch</b> — <code>modelGraphFromTorchFx</code> (keeps skip connections)</summary>
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import json, torch
|
|
99
|
+
from torch.fx import symbolic_trace
|
|
100
|
+
from torch.fx.passes.shape_prop import ShapeProp
|
|
101
|
+
|
|
102
|
+
gm = symbolic_trace(model)
|
|
103
|
+
ShapeProp(gm).propagate(torch.randn(1, 3, 224, 224)) # optional: fills in shapes
|
|
104
|
+
mods = dict(gm.named_modules())
|
|
105
|
+
|
|
106
|
+
def shape_of(n):
|
|
107
|
+
t = n.meta.get("tensor_meta")
|
|
108
|
+
return list(t.shape)[1:] if t is not None else None # drop the batch dim
|
|
109
|
+
|
|
110
|
+
json.dump([{
|
|
111
|
+
"name": n.name,
|
|
112
|
+
"op": n.op,
|
|
113
|
+
"target": str(n.target),
|
|
114
|
+
"args": [a.name for a in n.all_input_nodes],
|
|
115
|
+
"moduleType": type(mods[str(n.target)]).__name__ if n.op == "call_module" else None,
|
|
116
|
+
"shape": shape_of(n),
|
|
117
|
+
"params": sum(p.numel() for p in mods[str(n.target)].parameters())
|
|
118
|
+
if n.op == "call_module" else None,
|
|
119
|
+
} for n in gm.graph.nodes], open("model.json", "w"))
|
|
120
|
+
```
|
|
121
|
+
</details>
|
|
122
|
+
|
|
123
|
+
<details><summary><b>TensorFlow / Keras</b> — <code>modelGraphFromKeras</code></summary>
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
import json
|
|
127
|
+
json.dump({
|
|
128
|
+
"model": json.loads(model.to_json()),
|
|
129
|
+
"shapes": {l.name: list(l.output_shape)[1:] for l in model.layers},
|
|
130
|
+
"params": {l.name: l.count_params() for l in model.layers},
|
|
131
|
+
}, open("model.json", "w"))
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Sequential models chain in declaration order; functional models are wired from
|
|
135
|
+
`inbound_nodes` (both the Keras 2 and Keras 3 nestings are understood).
|
|
136
|
+
</details>
|
|
137
|
+
|
|
138
|
+
<details><summary><b>scikit-learn</b> — <code>modelGraphFromSklearn</code> / <code>mlpModel</code></summary>
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from sklearn.pipeline import Pipeline, FeatureUnion
|
|
142
|
+
from sklearn.compose import ColumnTransformer
|
|
143
|
+
|
|
144
|
+
def to_step(name, est, columns=None):
|
|
145
|
+
node = {"name": name, "type": type(est).__name__}
|
|
146
|
+
if columns is not None: node["columns"] = list(columns)
|
|
147
|
+
if isinstance(est, Pipeline):
|
|
148
|
+
node.update(steps=[to_step(n, e) for n, e in est.steps], mode="sequential")
|
|
149
|
+
elif isinstance(est, ColumnTransformer):
|
|
150
|
+
node.update(steps=[to_step(n, e, c) for n, e, c in est.transformers], mode="parallel")
|
|
151
|
+
elif isinstance(est, FeatureUnion):
|
|
152
|
+
node.update(steps=[to_step(n, e) for n, e in est.transformer_list], mode="parallel")
|
|
153
|
+
return node
|
|
154
|
+
|
|
155
|
+
json.dump(to_step("pipe", pipeline), open("model.json", "w"))
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
An `MLPClassifier` is a real layer stack instead:
|
|
159
|
+
`mlpModel([n_features, *clf.hidden_layer_sizes, clf.n_outputs_])`.
|
|
160
|
+
</details>
|
|
161
|
+
|
|
162
|
+
<details><summary><b>ONNX</b> — <code>modelGraphFromOnnx</code> (any framework)</summary>
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
import json, onnx
|
|
166
|
+
from google.protobuf.json_format import MessageToDict
|
|
167
|
+
|
|
168
|
+
m = onnx.shape_inference.infer_shapes(onnx.load("model.onnx"))
|
|
169
|
+
json.dump(MessageToDict(m.graph), open("model.json", "w"))
|
|
170
|
+
```
|
|
171
|
+
</details>
|
|
172
|
+
|
|
173
|
+
Layers are colored by family (`layerCategory` → conv / linear / norm / activation
|
|
174
|
+
/ pool / attention / …); override with `colors`. The layout itself is pure and
|
|
175
|
+
exported — `modelLayout(graph, opts)` gives box centers, sizes, ranks and routed
|
|
176
|
+
edge paths if you want to draw it yourself.
|
|
69
177
|
|
|
70
178
|
## Features
|
|
71
179
|
|
|
@@ -76,6 +184,9 @@ plot.addLine({ x: xs, y: ys, color: "#60a5fa", width: 2, name: "signal" });
|
|
|
76
184
|
- **Drawing tools** — `new Plot(el, { drawingTools: true })` adds trendline / horizontal / ray / Fibonacci / rectangle tools; drawings are editable (drag handles, relabel, recolor, delete). API: `setDrawTool`/`getDrawTool`/`addDrawing`/`clearDrawings`.
|
|
77
185
|
- **Image export** — every plot has `toDataURL()` / `toBlob()` / `downloadImage()` / `copyToClipboard()` + a toolbar download-PNG button; helpers `canvasToBlob` / `downloadCanvas` / `copyCanvasToClipboard` exported.
|
|
78
186
|
- **Data adapters** — `parseCSV(text)` → a `Table` (`.column()` / `.numeric()`), and `lttb(x, y, threshold)` for downsampling long line series.
|
|
187
|
+
- **Colorbar** — layers that map values to colours report `colorInfo()` and the plot draws a bar per scale (on by default; `colorbar: false` opts out).
|
|
188
|
+
- **Colour** — 12 colormaps (sequential / diverging / cyclic) + 4 categorical palettes; pass inline colours or register your own with `registerColormap` / `registerPalette`.
|
|
189
|
+
- **Interactive legend** — click an entry to hide/show a series; the auto axes re-fit to what is left. `plot.toggleLayer()` / `setLayerVisible()` / `onVisibilityChange()`.
|
|
79
190
|
- **Accessibility** — plots render as `role="img"` with an auto-summarized `aria-label`; override via `ariaLabel` / `setAriaLabel()` / `describe()`.
|
|
80
191
|
- **Many charts, one context** — a single shared WebGL2 context backs every plot, so a page can hold dozens.
|
|
81
192
|
|