binning — Parallel 2-D Histogram Binning¶
Source: crates/fastdpplot-core/src/binning.rs
bin_points¶
Bin points into a canvas_width × canvas_height grid for the given viewport.
Algorithm¶
- Compute the bin index for each point:
bx = floor((x - x_min) / x_span * width). - Each rayon thread accumulates into its own local
(counts, value_sums)pair. - Thread-local arrays are reduced by element-wise addition.
- Mean values are computed as
value_sums[i] / counts[i]wherecount > 0.
The parallel fold-reduce strategy avoids per-point mutex locks and keeps floating-point accumulation deterministic up to thread-scheduling.
Performance
For a 4 000 × 4 000 canvas with 10⁸ points, a typical run on an 8-core machine takes ≈1–2 seconds end-to-end (I/O + binning).
Degenerate ranges
If x_span ≤ 0 or y_span ≤ 0 or width == 0 or height == 0, an
all-zero BinGrid is returned immediately (no panic).
Index safety note¶
The single unsafe { get_unchecked_mut } inside the fold closure is sound
because bx = min(floor(…), w-1) < w and by = min(floor(…), h-1) < h,
so idx = by * w + bx < w * h == n.
compute_zoom_tiles¶
pub fn compute_zoom_tiles(
points: &[DotPoint],
max_zoom: u32,
tile_size: usize,
) -> Vec<(u32, BinGrid)>
Pre-compute a zoom pyramid: for each level 0..=max_zoom produce a BinGrid
at resolution tile_size × 2^level.
Returns a Vec<(zoom_level, BinGrid)> sorted by zoom level.
Example¶
// Levels 0–4 at base tile size 256
let pyramid = compute_zoom_tiles(&points, 4, 256);
// resolutions: 256, 512, 1024, 2048, 4096
Note
This function is not currently called by the Panel interactive server (which re-bins on demand) but is useful for pre-generating cached tiles for a tile server.