You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A zoomed bin grid does not match the unzoomed grid when the viewport covers the data #124
A zoomed binned trace (histogram, histogram2d, geo_histogram2d) bins on a lattice that starts at 0, with bin width span / n (snap_range in flexviz/trace/bin_grid.py). The unzoomed grid starts at the data minimum. So a viewport that covers the same range as the unzoomed grid gives another grid:
The grid almost always holds n + 1 bins.
The edges move, and discrete data can get an empty bin.
Example: a heatmap with y data 1..7 and y_bins=7. Unzoomed, it has 7 rows, one for each value. A zoom to [1, 7] gives 8 rows on [0.857, 7.714], and the row from 5.14 to 6.0 is empty.
Where users see it
A manual zoom to the data range (on main today).
The first zoom from the unzoomed view: all edges move, also when the range stays almost the same.
A lock on a link group whose members show different ranges (fix(adapters): aggregate linked members at the range a lock pins #116). The lock writes the group viewport for every member, also for the clicked figure, because the validator requires equal viewports in a group. So the clicked heatmap re-bins although its display did not change.
Cause
A zoomed request does not know the data extent of the column. The lattice needs an anchor that does not move under a pan, and 0 is the only anchor that needs no data.
Possible fix
Give zoomed binned requests the data extent of the column. Then do one of these:
Start the lattice at the data minimum. Pans stay stable, and a viewport that covers the data gives the unzoomed grid.
Treat a viewport that covers the data extent as unzoomed.
Cost and scope
One extra min/max pass per zoomed binned request. Earlier measurements: about 25–33 ms on in-memory data, about 100 ms zoomed on a 100M-row scan (geo).
One more consequence of the 0-anchored lattice, found while fixing #133 (2026-09-29).
The snapped range covers the viewport, so the first and last bars can stick out past the viewport by up to almost one bar width. Example: 20 bins, viewport 3..103. The bar width is 5, the snapped range is 0..105 with 21 bars. The first bar spans 0..5, and its center 2.5 is off-screen.
Effects:
The clipped edge bar counts rows the user cannot see (the mask selects the whole snapped range). This is on main today.
Decision: leave it. If this issue anchors the lattice so the grid aligns with the viewport, the overhang disappears and the source grid follows automatically. The alternative, treating a brush end that touches the plot edge as reaching the bar's outer edge, would filter rows the user cannot see and would disagree with Plotly's highlight.
Activity
jvdd commentedon Sep 29, 2026
One more consequence of the 0-anchored lattice, found while fixing #133 (2026-09-29).
The snapped range covers the viewport, so the first and last bars can stick out past the viewport by up to almost one bar width. Example: 20 bins, viewport 3..103. The bar width is 5, the snapped range is 0..105 with 21 bars. The first bar spans 0..5, and its center 2.5 is off-screen.
Effects:
Decision: leave it. If this issue anchors the lattice so the grid aligns with the viewport, the overhang disappears and the source grid follows automatically. The alternative, treating a brush end that touches the plot edge as reaching the bar's outer edge, would filter rows the user cannot see and would disagree with Plotly's highlight.