diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index dc7b82386216..48089011acf2 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -5099,8 +5099,10 @@ def imshow(self, X, cmap=None, norm=None, aspect=None, luminance data. Note if you pass a `norm` instance, your settings for `vmin` and `vmax` will be ignored. - alpha : scalar, optional, default: None - The alpha blending value, between 0 (transparent) and 1 (opaque) + alpha : [scalar | array_like], optional, default: None + The alpha blending value, between 0 (transparent) and 1 (opaque). + If `scalar` is an array, the alpha blending values are applied + pixel by pixel, and `scalar` must have the same shape as `X`. origin : ['upper' | 'lower'], optional, default: None Place the [0,0] index of the array in the upper left or lower left diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 6e716b74300a..4d0c72f9e6ae 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -237,6 +237,7 @@ def __init__(self, ax, self.axes = ax self._imcache = None + self._array_alpha = None self.update(kwargs) @@ -260,7 +261,11 @@ def set_alpha(self, alpha): ACCEPTS: float """ - martist.Artist.set_alpha(self, alpha) + if np.isscalar(alpha): + martist.Artist.set_alpha(self, alpha) + else: + self._array_alpha = alpha + martist.Artist.set_alpha(self, 1.0) self._imcache = None def changed(self): @@ -409,6 +414,10 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, if alpha is None: alpha = 1.0 + # Apply the array alpha if provided + if self._array_alpha is not None: + A[..., 3] *= self._array_alpha + _image.resample( A, output, t, _interpd_[self.get_interpolation()], self.get_resample(), alpha, @@ -419,7 +428,7 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, # colormapping works correctly hid_output = output output = np.ma.masked_array( - hid_output[..., 0], hid_output[..., 3] < 0.5) + hid_output[..., 0], hid_output[..., 3] == 0) # relabel under data output[hid_output[..., 1] > .5] = -1 # relabel over data @@ -427,6 +436,12 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, output = self.to_rgba(output, bytes=True, norm=False) + # Restore the alpha channel + if created_rgba_mask and self._array_alpha is not None: + output[..., 3] = (output[..., 3] * hid_output[..., 3]).astype( + output.dtype + ) + # Apply alpha *after* if the input was greyscale without a mask if A.ndim == 2 or created_rgba_mask: alpha = self.get_alpha() diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_array_alpha.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_array_alpha.pdf new file mode 100644 index 000000000000..d69df80fa9f2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/image_array_alpha.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_array_alpha.png b/lib/matplotlib/tests/baseline_images/test_image/image_array_alpha.png new file mode 100644 index 000000000000..9714c49a024d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/image_array_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_array_alpha.svg b/lib/matplotlib/tests/baseline_images/test_image/image_array_alpha.svg new file mode 100644 index 000000000000..b902359131d9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/image_array_alpha.svg @@ -0,0 +1,385 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image_over_under.png b/lib/matplotlib/tests/baseline_images/test_image/mask_image_over_under.png index 6433cd355e85..77da9d1e8e1c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/mask_image_over_under.png and b/lib/matplotlib/tests/baseline_images/test_image/mask_image_over_under.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png index 322e8c00478f..45c9d6cc9d1c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png and b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png differ diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index bb963b1e0247..ad579ad8c8cd 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -741,3 +741,16 @@ def test_empty_imshow(): with pytest.raises(RuntimeError): im.make_image(fig._cachedRenderer) + + +@image_comparison(baseline_images=['image_array_alpha']) +def test_image_array_alpha(): + '''per-pixel alpha channel test''' + x = np.linspace(0, 1) + xx, yy = np.meshgrid(x, x) + + zz = np.exp(- 3 * ((xx - 0.5) ** 2) + (yy -0.7 ** 2)) + + fig = plt.figure() + ax = fig.add_subplot(111) + ax.imshow(zz, alpha=zz)