josie / alder-tools

Plot: max-decimation per column (nvtop keeps 1 sample/col; stride/mean aliasing caused dash artifacts) — peak-preserving

8c2345d6a17aecdde474257425d63a751e44b9c0
josie <administrator@josie-c.com> · 2026-08-30T13:40 · browse files at this commit

parents: 2ce9e55

diff --git a/src/plot.rs b/src/plot.rs
index 01b7f67..1ce0595 100644
--- a/src/plot.rs
+++ b/src/plot.rs
@@ -78,16 +78,27 @@ pub fn render(
     let rows = area.height as usize;
     let cols = area.width as usize;
 
-    // One sample per column, newest at the right; when the window holds
-    // more samples than columns, stride-skip (take every Nth) so the whole
-    // window is visible. Striding preserves steps better than averaging.
+    // nvtop's ring holds exactly one sample per plot column — no draw-time
+    // resampling, so nothing aliases. When our window holds more ticks than
+    // columns, decimate by MAX per column (peak-preserving; mean/stride
+    // made adjacent columns alternate rows → dash artifacts). Buckets run
+    // oldest→newest so the newest sample lands in the rightmost column.
     let samples: Vec<f64> = ring.samples_window(window_ticks).collect();
     if samples.is_empty() {
         return;
     }
-    let stride = samples.len().div_ceil(cols);
-    let shown: Vec<f64> = if stride > 1 {
-        samples.iter().rev().step_by(stride).rev().cloned().collect()
+    let shown: Vec<f64> = if samples.len() > cols {
+        let bucket = samples.len() / cols;
+        let rem = samples.len() % cols;
+        let mut out = Vec::with_capacity(cols);
+        let mut idx = 0;
+        for c in 0..cols {
+            let extra = if c < rem { 1 } else { 0 };
+            let end = idx + bucket + extra;
+            out.push(samples[idx..end].iter().cloned().fold(f64::MIN, f64::max));
+            idx = end;
+        }
+        out
     } else {
         samples
     };