Skip to content

Document where the filters differ from scipy.ndimage. - #36

Merged
roytsmart merged 2 commits into
mainfrom
fix-median-note
Aug 20, 2026
Merged

Document where the filters differ from scipy.ndimage.#36
roytsmart merged 2 commits into
mainfrom
fix-median-note

Conversation

@roytsmart

@roytsmart roytsmart commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Two documentation changes; no behavior change.

Correct the note on even-sized median footprints

The note added in #34 had the comparison backwards. For a footprint with an
even number of elements, scipy.ndimage.median_filter() returns the
larger of the two middle elements, not the smaller, because it delegates
to _rank_filter() and asks for the element of rank size // 2:

a = np.array([0., 10., 20., 30., 40.])
scipy.ndimage.median_filter(a, size=2, mode="nearest")
# array([ 0., 10., 20., 30., 40.])   <- the upper element of each pair

where averaging each pair, as numpy.median() and this package do, gives
[0., 5., 15., 25., 35.]. Selecting rather than averaging is what lets
SciPy return a result in the dtype of the input.

Add a "Differences from scipy.ndimage" section

The README and the documentation landing page both open by saying the
filters are similar to those in scipy.ndimage, and then list only the ways
this library does more. That sets up a migrating user to be surprised, and a
Notes block on one function is only read by someone who already suspects a
difference. The new section covers the other half:

  • Boundary modes. "reflect", "constant", and the "grid-*" modes
    raise a ValueError here; "truncate" has no SciPy equivalent.
  • Integer input. Promoted to floating point rather than returned in the
    input dtype, which is what allows a fully-excluded where footprint to
    return NaN (Fix the "mirror" boundary mode and validate mode and size. #32).
  • Even-sized median footprints. The tie-breaking difference above,
    including that SciPy's convention is a biased estimator: on unit-variance
    noise a size=2 median filter shifts the signal by roughly 0.57, while
    the two conventions agree exactly for odd-sized footprints.
size=2  input mean +0.00013   scipy +0.56635   ndfilters +0.00013
size=3  input mean +0.00018   scipy +0.00032   ndfilters +0.00032
size=4  input mean +0.00423   scipy +0.30070   ndfilters +0.00399
size=5  input mean -0.00042   scipy +0.00031   ndfilters +0.00031
size=8  input mean +0.00087   scipy +0.15258   ndfilters +0.00032

The section states the tradeoff in both directions rather than only ours:
SciPy's rank selection never introduces a value that was not already in the
footprint, which averaging does (a 4-level image filtered at size=4 comes
back with 7 levels).

🤖 Generated with Claude Code

The note added in #34 had the comparison backwards. For an even footprint
`scipy.ndimage.median_filter()` returns the larger of the two middle
elements, not the smaller, because it is implemented as a rank filter that
selects the element of rank `size // 2`. Say why, too: selecting an element
of the footprint is what lets SciPy return a result in the dtype of the
input.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (d71d84c) to head (2c570b1).

Additional details and impacted files
@@            Coverage Diff            @@
##              main       #36   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           14        14           
  Lines          677       677           
=========================================
  Hits           677       677           
Flag Coverage Δ
unittests 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ 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.

The README and the documentation landing page both claim the filters are
similar to those in `scipy.ndimage`, and then list only the ways this
library does more. Add the other half: the boundary modes that are not
supported, the promotion of integer input, and the tie-breaking convention
for an even-sized median footprint.

The docstring note that #36 corrects is only read by someone who already
suspects a difference. A migrating user reads the landing page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@roytsmart roytsmart changed the title Correct the note on even-sized median footprints. Document where the filters differ from scipy.ndimage. Aug 20, 2026
@roytsmart
roytsmart merged commit 980969f into main Aug 20, 2026
18 checks passed
@roytsmart
roytsmart deleted the fix-median-note branch August 20, 2026 14:28
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