Skip to content

Improve image inset resampling quality#1077

Merged
has2k1 merged 2 commits into
mainfrom
fix-inset-image-quality
Jun 15, 2026
Merged

Improve image inset resampling quality#1077
has2k1 merged 2 commits into
mainfrom
fix-inset-image-quality

Conversation

@has2k1

@has2k1 has2k1 commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Summary

Image insets (inset_element with a PIL.Image or numpy.ndarray) previously
handed the full-resolution image to matplotlib's BboxImage and let it resample
to the inset's size at render time. matplotlib's resampler aliases badly on large
downscales — the regime an inset typically hits — producing soft, moiré-ridden
images.

This change pre-resizes the source to the inset's exact device-pixel footprint
with PIL and renders it pixel-for-pixel (interpolation="none"), choosing the
filter by scaling direction.

Resampling policy

direction filter why
downscale LANCZOS antialiases the reduction; matplotlib's resampler aliases on large downscales
upscale / 1:1 NEAREST stays crisp; smooth filters (bicubic, LANCZOS) look hazy and ring on hard edges

Implementation notes

  • Inputs are normalised to a pristine PIL.Image once, on construction
    (_to_pil_image); a float ndarray follows matplotlib's [0, 1] convention.
  • The resize happens in _arrange_in_box, not draw(): the device-pixel size is
    only known after the layout engine finalises the inset's bbox at render time.
    draw() just creates the BboxImage; _arrange_in_box sets its data.

Baselines

Updated the affected image-inset baselines (image_aspect_fit_top_right,
image_aspect_fit_bottom, image_standalone) to reflect the new resampling.

has2k1 added 2 commits June 15, 2026 15:59
Pre-resize the source to the inset's exact device-pixel footprint with
PIL and render it pixel-for-pixel (interpolation='none'), instead of
letting matplotlib resample the full-resolution image. Downscale with
LANCZOS to antialias (matplotlib's resampler aliases on large
reductions); enlarge with NEAREST to stay crisp (smooth filters look
hazy and ring on hard edges).
@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.30435% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.07%. Comparing base (d7b9533) to head (fecdbfb).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
plotnine/composition/_inset_image.py 91.30% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1077      +/-   ##
==========================================
- Coverage   87.07%   87.07%   -0.01%     
==========================================
  Files         208      208              
  Lines       14341    14355      +14     
  Branches     1789     1791       +2     
==========================================
+ Hits        12488    12500      +12     
- Misses       1286     1287       +1     
- Partials      567      568       +1     

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

@has2k1 has2k1 merged commit fecdbfb into main Jun 15, 2026
14 checks passed
@has2k1 has2k1 deleted the fix-inset-image-quality branch June 15, 2026 19:22
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