Skip to content

fix: reject NaN and speed up box plot distribution stats#382

Merged
lpatiny merged 3 commits into
mainfrom
boxplot-reject-nan
Jul 9, 2026
Merged

fix: reject NaN and speed up box plot distribution stats#382
lpatiny merged 3 commits into
mainfrom
boxplot-reject-nan

Conversation

@lpatiny

@lpatiny lpatiny commented Jul 8, 2026

Copy link
Copy Markdown
Member

xBoxPlot, xBoxPlotWithOutliers and xRobustDistributionStats now sort the input once into a Float64Array and reuse it — outliers are read from the sorted prefix/suffix and the non-outlier range is a zero-copy subarray, removing an O(n) filter-copy pass and its allocation.

NaN is now rejected (it corrupts ranks, quartiles and moments): a NaN in the input throws input must not contain NaN values. Infinity stays a valid extreme. Only the public box plot API is re-exported from x/index.ts; the sorted-array helpers stay internal.

xRobustDistributionStats benchmark (deterministic data, ~5% outliers):

n before after speedup
1e3 0.030 ms 0.021 ms 1.4×
1e5 6.46 ms 5.60 ms 1.15×
1e6 63.7 ms 55.2 ms 1.15×

xBoxPlot, xBoxPlotWithOutliers and xRobustDistributionStats now sort the
input once into a Float64Array and reuse it: outliers are read from the
sorted prefix/suffix and the non-outlier range is taken as a zero-copy
subarray, removing an O(n) filter-copy pass and its allocation.

NaN is now rejected (it corrupts ranks, quartiles and moments): a NaN in
the input throws "input must not contain NaN values". Infinity stays a
valid extreme.

Only the public box plot API is re-exported from x/index.ts; the
sorted-array helpers stay internal.

xRobustDistributionStats benchmark (deterministic data, ~5% outliers):
  n=1e3   0.030 -> 0.021 ms  (1.4x)
  n=1e5   6.46  -> 5.60  ms  (1.15x)
  n=1e6   63.7  -> 55.2  ms  (1.15x)
@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.16%. Comparing base (9fed281) to head (e46855d).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #382      +/-   ##
==========================================
+ Coverage   97.13%   97.16%   +0.03%     
==========================================
  Files         207      208       +1     
  Lines        4147     4160      +13     
  Branches     1036     1030       -6     
==========================================
+ Hits         4028     4042      +14     
+ Misses        115      114       -1     
  Partials        4        4              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

lpatiny added 2 commits July 8, 2026 16:49
Extract the identical lowIndex/highIndex scan that was duplicated in
boxPlotWithOutliersFromSorted and xRobustDistributionStats into a shared
getWhiskerBounds helper, so the outlier range cannot drift between the two.
Also type outliers as number[], cache min/max in boxPlotFromSorted, and add
a low-side outlier test for xBoxPlotWithOutliers.
boxPlotWithOutliersAndBounds returns the box plot together with the
non-outlier index range, so xRobustDistributionStats reuses those bounds
for its zero-copy subarray instead of scanning the sorted array a second
time via getWhiskerBounds.
@lpatiny lpatiny merged commit 289ff10 into main Jul 9, 2026
10 checks passed
@lpatiny lpatiny deleted the boxplot-reject-nan branch July 9, 2026 05:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant