Skip to content
96 changes: 62 additions & 34 deletions Architecture.md

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ independently. `flexviz` pins a compatible `flexviz-polars` range.

### Changed

- `flexviz` requires the `flexviz-polars` release that ships with it, because
the line envelope kernel now bins the free axis like the display kernel.
- A notebook `show()` displays the server's own `/view` page in its iframe,
like the browser path, instead of a `data:` page that called the server from
another origin. For the deprecated ECharts renderer, `height` now sets only
Expand All @@ -39,6 +41,30 @@ independently. `flexviz` pins a compatible `flexviz-polars` range.
- `flexviz.server.show_server`. Use `Figure.show()`, `Dashboard.show()` or
`flexviz serve`.

### Fixed

- A brush on a histogram or a histogram2d snaps to the edges of its bars or
cells. The bars that Plotly highlights now hold exactly the rows that the
other figures keep, also for a value on a bar edge and on a `Date` axis. A
brush that covers no bar or cell center clears the selection. Before, the
brush snapped to a fixed grid of 2048 steps (128 per axis for a
histogram2d), so the other figures also kept part of the rows of the edge
bars or cells. The live-brush data of such a source now grows with its bars
or cells instead of the fixed grid: with the default 20 bars or 20 × 20
cells it is about 40 to 50 times smaller. A histogram2d finer than
128 × 128 cells makes it larger than before.
- A histogram or a histogram2d on a `Date` column draws each bar at its bin
center, and its hover shows the time of day of that center. Before, the
center was rounded to a whole day, so a bar could sit up to half a day off
its bin, and bars narrower than a day stacked on one day.
- A selection or a zoom on a `Float32` column keeps exactly the values inside
its range. Before, each bound was rounded to the nearest `Float32`, which
could move a value next to the bound to the other side.
- A selection on a `Date` or `Datetime("ms")` column keeps exactly the values
inside its range. Before, a bound with a time of day (or a fraction of a
millisecond) was cut to the day (or millisecond), so a brush that started at
13:00 still kept that day.

## [0.1.0b5] - 2026-09-27

### Added
Expand Down
19 changes: 19 additions & 0 deletions benchmarks/test_codspeed_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,22 @@ def test_build_cubes(benchmark, frame: pl.DataFrame) -> None:
active = ActiveSource(figure_uid="fig_a", column="g", trace_uid=bar.uid)
cubes, trace_cubes = benchmark(engine.build_cubes, infos, {}, [], active)
assert cubes and trace_cubes == {hist.uid: 0}


def test_build_line_cubes(benchmark, frame: pl.DataFrame) -> None:
"""Histogram source (a range free axis), line target: the envelope cube,
wrapper and kernel together."""
hist = Histogram(x="z", bins=50)
line = TRACES["line-minmax"]()
engine = FlexEngine(
backend_lf=LFQueryBuilder(frame),
scalable_traces={hist.uid: hist, line.uid: line},
source_name="bench",
)
infos = [
TraceInfo(hist.uid, hist._axes, hist.trace_type, figure_uid="fig_a"),
TraceInfo(line.uid, line._axes, line.trace_type, figure_uid="fig_b"),
]
active = ActiveSource(figure_uid="fig_a", column="z", trace_uid=hist.uid)
cubes, trace_cubes = benchmark(engine.build_cubes, infos, {}, [], active)
assert cubes and trace_cubes == {line.uid: 0}
8 changes: 4 additions & 4 deletions docs/cube-support-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ A source trace implements `get_cube_source_spec()` and produces a **free axis**

| Source trace | Free-axis kind | Geometry |
|---|---|---|
| `histogram` | **range** (continuous / temporal) | 1-D, P=2048 over the viewport (or full-data) domain |
| `histogram` | **range** (continuous / temporal) | 1-D, the histogram's own bars over the viewport (or full-data) domain |
| `box` | **range** | 1-D over the `data_col` (same gates as hist) |
| `line` | **range** | 1-D over the **x** column only (line selection is x-only); P=2048 |
| `histogram2d` | **box2d** | two range axes (x, y) at P₂D=128 each, packed into one composite `free_bin` |
| `histogram2d` | **box2d** | two range axes (x, y) on the source's own `x_bins × y_bins` cell grid, packed into one composite `free_bin` |
| `bar` | **categorical** | over the ordered label column(s) |
| `pie` | **categorical** | over the label column(s) |
| `treemap` | **categorical** | over the full `path` (prefix selects a subtree) |
Expand Down Expand Up @@ -73,8 +73,8 @@ source free-axis kinds can feed each target measure.**

Notes on the two `❌` columns:
- **`box2d × {line_env, corr}` (#47):** a feasibility-free but real **cell-count / wire-size
wall** — a box2d `line_env` cube is `n_x_buckets × (P₂D+1)²` ≈ `500 × 129²` ≈ 8.3M cells per
line. Gated off; those targets fall back to the per-commit recompute. Tracked in #47.
wall** — a box2d `line_env` cube is `n_x_buckets × nx·ny` cells per line, for example
`500 × 128²` ≈ 8.2M for a 128 × 128 cell source. Gated off; those targets fall back to the per-commit recompute. Tracked in #47.
- **`median` / `n_unique` / box quantiles:** mathematically not decomposable over a partition —
never cube targets, by any source.

Expand Down
Loading
Loading