Repository: matplotlib/matplotlib

Issue:
# [Bug]: alpha array-type not working with RGB image in imshow()

### Bug summary

Hi,
Whereas `alpha = constant` works with RGB image, this is not the case when working with an `array-type` for alpha.
(In my real case, I can only pass standard imshow parameters like `alpha `to the function of the library I use, and not a RGBA array).
Patrick

### Code for reproduction

```python
import numpy as np
import matplotlib.pyplot as plt
from skimage.color import gray2rgb

arr = np.random.random((10, 10))
arr_rgb = gray2rgb(arr)

alpha = np.ones_like(arr)
alpha[:5] = 0.2

plt.figure()
plt.tight_layout()
plt.subplot(121)
plt.title("Expected outcome")
plt.imshow(arr, alpha=alpha, cmap='gray')
plt.subplot(122)
plt.title("Actual outcome")
plt.imshow(arr_rgb, alpha=alpha)
plt.show()
```


### Actual outcome

![image](https://github.com/matplotlib/matplotlib/assets/16154687/89322c0b-4ccd-46e1-9f2a-50b5f3511dfa)


### Expected outcome

![image](https://github.com/matplotlib/matplotlib/assets/16154687/4d7fcedf-2c54-4f07-a35d-ad23afeb9df6)


### Additional information

_No response_

### Operating system

Windows

### Matplotlib Version

3.7.1

### Matplotlib Backend

TkAgg

### Python version

Python 3.10.11

### Jupyter version

_No response_

### Installation

pip

Implementation patch:
diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py
index 483526fcd0a0..e4d6eebcc5c0 100644
--- a/lib/matplotlib/image.py
+++ b/lib/matplotlib/image.py
@@ -512,8 +512,10 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
                     if A.shape[2] == 3:  # image has no alpha channel
                         A = np.dstack([A, np.ones(A.shape[:2])])
                 elif np.ndim(alpha) > 0:  # Array alpha
-                    # user-specified array alpha overrides the existing alpha channel
-                    A = np.dstack([A[..., :3], alpha])
+                    if A.shape[2] == 3:  # RGB: use array alpha directly
+                        A = np.dstack([A, alpha])
+                    else:  # RGBA: multiply existing alpha by array alpha
+                        A = np.dstack([A[..., :3], A[..., 3] * alpha])
                 else:  # Scalar alpha
                     if A.shape[2] == 3:  # broadcast scalar alpha
                         A = np.dstack([A, np.full(A.shape[:2], alpha, np.float32)])


Test patch:
diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py
index 02af308963a3..0f051afbc894 100644
--- a/lib/matplotlib/tests/test_image.py
+++ b/lib/matplotlib/tests/test_image.py
@@ -1857,7 +1857,7 @@ def test_interpolation_stage_rgba_respects_alpha_param(fig_test, fig_ref, intp_s
     axs_ref[0][2].imshow(im_rgba, interpolation_stage=intp_stage)
 
     # When the image already has an alpha channel, multiply it by the
-    # scalar alpha param, or replace it by the array alpha param
+    # alpha param (both scalar and array alpha multiply the existing alpha)
     axs_tst[1][0].imshow(im_rgba)
     axs_ref[1][0].imshow(im_rgb, alpha=array_alpha)
     axs_tst[1][1].imshow(im_rgba, interpolation_stage=intp_stage, alpha=scalar_alpha)
@@ -1869,7 +1869,8 @@ def test_interpolation_stage_rgba_respects_alpha_param(fig_test, fig_ref, intp_s
     new_array_alpha = np.random.rand(ny, nx)
     axs_tst[1][2].imshow(im_rgba, interpolation_stage=intp_stage, alpha=new_array_alpha)
     axs_ref[1][2].imshow(
-        np.concatenate(  # combine rgb channels with new array alpha
-            (im_rgb, new_array_alpha.reshape((ny, nx, 1))), axis=-1
+        np.concatenate(  # combine rgb channels with multiplied array alpha
+            (im_rgb, array_alpha.reshape((ny, nx, 1))
+             * new_array_alpha.reshape((ny, nx, 1))), axis=-1
         ), interpolation_stage=intp_stage
     )