Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a1fbee5

Browse filesBrowse files
committed
FIX: masked images with interpolation
When determining which pixels to mask in the resampled image, if _any_ contribution to final value comes from a masked pixel, mask the result. Due to Agg special-casing the meaning of the alpha channel, the interpolation for the mask channel needs to be done separately. This is probably a template for doing the over/under separately. print out exact hash on travis
1 parent fbe562c commit a1fbee5
Copy full SHA for a1fbee5

File tree

7 files changed

+331
-7
lines changed
Filter options

7 files changed

+331
-7
lines changed

‎.travis.yml

Copy file name to clipboardExpand all lines: .travis.yml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ before_install:
7676

7777
install:
7878
- ccache -s
79+
- git describe
7980
# Upgrade pip and setuptools. Mock has issues with the default version of
8081
# setuptools
8182
- |

‎lib/matplotlib/image.py

Copy file name to clipboardExpand all lines: lib/matplotlib/image.py
+43-7Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -371,9 +371,20 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
371371
# this is to work around spurious warnings coming
372372
# out of masked arrays.
373373
with np.errstate(invalid='ignore'):
374-
rgba[..., 1] = A < 0 # under data
375-
rgba[..., 2] = A > 1 # over data
376-
rgba[..., 3] = ~A.mask # bad data
374+
rgba[..., 1] = np.where(A < 0, np.nan, 1) # under data
375+
rgba[..., 2] = np.where(A > 1, np.nan, 1) # over data
376+
# Have to invert mask, Agg knows what alpha means
377+
# so if you put this in as 0 for 'good' points, they
378+
# all get zeroed out
379+
rgba[..., 3] = 1
380+
if A.mask.shape == A.shape:
381+
# this is the case of a nontrivial mask
382+
mask = np.where(A.mask, np.nan, 1)
383+
else:
384+
# this is the case that the mask is a
385+
# numpy.bool_ of False
386+
mask = A.mask
387+
# ~A.mask # masked data
377388
A = rgba
378389
output = np.zeros((out_height, out_width, 4),
379390
dtype=A.dtype)
@@ -414,12 +425,37 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
414425
# Convert back to a masked greyscale array so
415426
# colormapping works correctly
416427
hid_output = output
428+
# any pixel where the a masked pixel is included
429+
# in the kernel (pulling this down from 1) needs to
430+
# be masked in the output
431+
if len(mask.shape) == 2:
432+
out_mask = np.empty((out_height, out_width),
433+
dtype=mask.dtype)
434+
_image.resample(mask, out_mask, t,
435+
_interpd_[self.get_interpolation()],
436+
True, 1,
437+
self.get_filternorm() or 0.0,
438+
self.get_filterrad() or 0.0)
439+
out_mask = np.isnan(out_mask)
440+
else:
441+
out_mask = mask
442+
# we need to mask both pixels which came in as masked
443+
# and the pixels that Agg is telling us to ignore (relavent
444+
# to non-affine transforms)
445+
# Use half alpha as the threshold for pixels to mask.
446+
out_mask = out_mask | (hid_output[..., 3] < .5)
417447
output = np.ma.masked_array(
418-
hid_output[..., 0], hid_output[..., 3] < 0.5)
419-
# relabel under data
420-
output[hid_output[..., 1] > .5] = -1
448+
hid_output[..., 0],
449+
out_mask)
450+
# 'unshare' the mask array to
451+
# needed to suppress numpy warning
452+
del out_mask
453+
invalid_mask = ~output.mask * ~np.isnan(output.data)
454+
# relabel under data. If any of the input data for
455+
# the pixel has input out of the norm bounds,
456+
output[np.isnan(hid_output[..., 1]) * invalid_mask] = -1
421457
# relabel over data
422-
output[hid_output[..., 2] > .5] = 2
458+
output[np.isnan(hid_output[..., 2]) * invalid_mask] = 2
423459

424460
output = self.to_rgba(output, bytes=True, norm=False)
425461

Binary file not shown.
Loading

‎lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.svg

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.svg
+269Lines changed: 269 additions & 0 deletions
Loading
Loading

‎lib/matplotlib/tests/test_image.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_image.py
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def test_image_interps():
6060
ax3.imshow(X, interpolation='bicubic')
6161
ax3.set_ylabel('bicubic')
6262

63+
6364
@image_comparison(baseline_images=['interp_nearest_vs_none'],
6465
extensions=['pdf', 'svg'], remove_text=True)
6566
def test_interp_nearest_vs_none():
@@ -757,6 +758,23 @@ def test_imshow_endianess():
757758
ax2.imshow(Z.astype('>f8'), **kwargs)
758759

759760

761+
@image_comparison(baseline_images=['imshow_masked_interpolation'],
762+
remove_text=True, style='default')
763+
def test_imshow_masked_interpolation():
764+
np.random.seed(19680801)
765+
a = np.random.random((7, 7))*1000
766+
ndv = -9999.0
767+
a[2:4, 1:5] = ndv
768+
am = np.ma.masked_equal(a, ndv)
769+
770+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3))
771+
ax1.imshow(am, interpolation='nearest')
772+
ax1.set_title("interpolation='nearest'")
773+
ax2.imshow(am, interpolation='bilinear')
774+
ax2.set_title("interpolation='bilinear'")
775+
plt.show()
776+
777+
760778
@cleanup
761779
def test_imshow_no_warn_invalid():
762780
with warnings.catch_warnings(record=True) as warns:

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.