Inspector: multi-view data inspection with a per-table view picker

This commit is contained in:
2026-06-28 22:13:34 +03:00
parent a75ea5b59e
commit 8cad80f738
10 changed files with 537 additions and 258 deletions
@@ -42,26 +42,25 @@ above it is data; everything below it is a Vega `View` we own and must tear down
### The data inspector rides the boundary too
The data inspector (the Live Preview and Chart Builder panel showing the chart's input
vs. resolved rows — spec §04) reads runtime rows through the handle, never the raw view:
`RenderHandle.inspectData()` returns the input + resolved tables (`{ input, resolved }`,
or `null` when no chart is up), wrapping the view exactly like `toImageURL`. It works in
two layers:
The data inspector (the Live Preview and Chart Builder panel showing each drawn table's
input vs. resolved rows — spec §04) reads runtime rows through the handle, never the raw
view: `RenderHandle.inspectData()` returns the inspectable tables (`{ tables }`, or `null`
when no chart is up), wrapping the view exactly like `toImageURL`. It works in two layers:
- **Enumerate + pick (`view.getState` + `core/result-data`).** A compiled Vega dataflow
holds many named datasets; Vega-Lite names them by convention — `source_<n>` per parsed
source, `data_<n>` per transform stage. The pure `pickSourceDataset` / `pickResultDataset`
choose the **most-upstream source** (the input) and **most-downstream output** (what the
marks draw), skipping dataflow internals (`marks`, `root`, layout, selection `*_store`s).
A spec with no transforms resolves both to the same table. The picking is pure (in `core`,
unit-tested); only the enumeration touches the view.
- **Read lazily.** `getState` serializes the datasets it lists, so it is **only called while
the panel is open** — a collapsed inspector costs nothing, which is why the panel reads on
demand rather than on every render.
Limitation: one name per direction can't represent a multi-view spec (layer/concat/facet
produce several `data_<n>`); the most-downstream/upstream ones are returned, and a full
dataset selector is left as a future option.
- **Enumerate from the compiled spec (`core/inspect-views`).** A composed spec draws
several tables; `inspectableViews` walks the compiled Vega spec — the marks tree's
`from.data` (what each mark draws) and `data[].source` (the lineage, the documented Vega
format) — to list, in document order, one entry per **distinct drawn table** with its
`resolved` (post-transform, what the marks draw) and `input` (most-upstream source) ends.
Enumerating by drawn table, not by authored view, is forced by Vega-Lite desugaring (a
`point: true` line compiles to two layers — a compiled table can't be traced back to one
authored view). Selection `*_store`s and `facet_domain*` layout tables aren't drawn, so
they fall out for free. The walk is pure (in `core`, unit-tested); the boundary reads each
table's rows via `view.data(name)`.
- **Read lazily.** Reading serializes rows, so it happens **only while the panel is open**
a collapsed inspector costs nothing, which is why the panel reads on demand rather than on
every render. (A multi-view spec yields several tables; the panel's `SelectControl` picker
chooses which to show — labels never expose Vega's compiler names, see arch 10.)
---