Skip to content

Commit 44770ae

Browse files
authored
Merge pull request #28437 from chaoyihu/imshow-alpha-not-respected
Respect array alpha with interpolation_stage='rgba' in _Imagebase::_make_image
2 parents 177f28c + 8a032c1 commit 44770ae

File tree

3 files changed

+75
-11
lines changed

3 files changed

+75
-11
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
*alpha* parameter handling on images
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
When passing and array to ``imshow(..., alpha=...)``, the parameter was silently ignored
5+
if the image data was a RGB or RBGA image or if :rc:`interpolation_state`
6+
resolved to "rbga".
7+
8+
This is now fixed, and the alpha array overwrites any previous transparency information.

lib/matplotlib/image.py

+21-11
Original file line numberDiff line numberDiff line change
@@ -501,17 +501,27 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
501501
if A.ndim == 2: # interpolation_stage = 'rgba'
502502
self.norm.autoscale_None(A)
503503
A = self.to_rgba(A)
504-
alpha = self._get_scalar_alpha()
505-
if A.shape[2] == 3:
506-
# No need to resample alpha or make a full array; NumPy will expand
507-
# this out and cast to uint8 if necessary when it's assigned to the
508-
# alpha channel below.
509-
output_alpha = (255 * alpha) if A.dtype == np.uint8 else alpha
510-
else:
511-
output_alpha = _resample( # resample alpha channel
512-
self, A[..., 3], out_shape, t, alpha=alpha)
513-
output = _resample( # resample rgb channels
514-
self, _rgb_to_rgba(A[..., :3]), out_shape, t, alpha=alpha)
504+
alpha = self.get_alpha()
505+
if alpha is None: # alpha parameter not specified
506+
if A.shape[2] == 3: # image has no alpha channel
507+
output_alpha = 255 if A.dtype == np.uint8 else 1.0
508+
else:
509+
output_alpha = _resample( # resample alpha channel
510+
self, A[..., 3], out_shape, t)
511+
output = _resample( # resample rgb channels
512+
self, _rgb_to_rgba(A[..., :3]), out_shape, t)
513+
elif np.ndim(alpha) > 0: # Array alpha
514+
# user-specified array alpha overrides the existing alpha channel
515+
output_alpha = _resample(self, alpha, out_shape, t)
516+
output = _resample(
517+
self, _rgb_to_rgba(A[..., :3]), out_shape, t)
518+
else: # Scalar alpha
519+
if A.shape[2] == 3: # broadcast scalar alpha
520+
output_alpha = (255 * alpha) if A.dtype == np.uint8 else alpha
521+
else: # or apply scalar alpha to existing alpha channel
522+
output_alpha = _resample(self, A[..., 3], out_shape, t) * alpha
523+
output = _resample(
524+
self, _rgb_to_rgba(A[..., :3]), out_shape, t)
515525
output[..., 3] = output_alpha # recombine rgb and alpha
516526

517527
# output is now either a 2D array of normed (int or float) data

lib/matplotlib/tests/test_image.py

+46
Original file line numberDiff line numberDiff line change
@@ -1711,3 +1711,49 @@ def test_resample_dtypes(dtype, ndim):
17111711
axes_image = ax.imshow(data)
17121712
# Before fix the following raises ValueError for some dtypes.
17131713
axes_image.make_image(None)[0]
1714+
1715+
1716+
@pytest.mark.parametrize('intp_stage', ('data', 'rgba'))
1717+
@check_figures_equal()
1718+
def test_interpolation_stage_rgba_respects_alpha_param(fig_test, fig_ref, intp_stage):
1719+
axs_tst = fig_test.subplots(2, 3)
1720+
axs_ref = fig_ref.subplots(2, 3)
1721+
ny, nx = 3, 3
1722+
scalar_alpha = 0.5
1723+
array_alpha = np.random.rand(ny, nx)
1724+
1725+
# When the image does not have an alpha channel, alpha should be specified
1726+
# by the user or default to 1.0
1727+
im_rgb = np.random.rand(ny, nx, 3)
1728+
im_concat_default_a = np.ones((ny, nx, 1)) # alpha defaults to 1.0
1729+
im_rgba = np.concatenate( # combine rgb channels with array alpha
1730+
(im_rgb, array_alpha.reshape((ny, nx, 1))), axis=-1
1731+
)
1732+
axs_tst[0][0].imshow(im_rgb)
1733+
axs_ref[0][0].imshow(np.concatenate((im_rgb, im_concat_default_a), axis=-1))
1734+
axs_tst[0][1].imshow(im_rgb, interpolation_stage=intp_stage, alpha=scalar_alpha)
1735+
axs_ref[0][1].imshow(
1736+
np.concatenate( # combine rgb channels with broadcasted scalar alpha
1737+
(im_rgb, scalar_alpha * im_concat_default_a), axis=-1
1738+
), interpolation_stage=intp_stage
1739+
)
1740+
axs_tst[0][2].imshow(im_rgb, interpolation_stage=intp_stage, alpha=array_alpha)
1741+
axs_ref[0][2].imshow(im_rgba, interpolation_stage=intp_stage)
1742+
1743+
# When the image already has an alpha channel, multiply it by the
1744+
# scalar alpha param, or replace it by the array alpha param
1745+
axs_tst[1][0].imshow(im_rgba)
1746+
axs_ref[1][0].imshow(im_rgb, alpha=array_alpha)
1747+
axs_tst[1][1].imshow(im_rgba, interpolation_stage=intp_stage, alpha=scalar_alpha)
1748+
axs_ref[1][1].imshow(
1749+
np.concatenate( # combine rgb channels with scaled array alpha
1750+
(im_rgb, scalar_alpha * array_alpha.reshape((ny, nx, 1))), axis=-1
1751+
), interpolation_stage=intp_stage
1752+
)
1753+
new_array_alpha = np.random.rand(ny, nx)
1754+
axs_tst[1][2].imshow(im_rgba, interpolation_stage=intp_stage, alpha=new_array_alpha)
1755+
axs_ref[1][2].imshow(
1756+
np.concatenate( # combine rgb channels with new array alpha
1757+
(im_rgb, new_array_alpha.reshape((ny, nx, 1))), axis=-1
1758+
), interpolation_stage=intp_stage
1759+
)

0 commit comments

Comments
 (0)