问题
GH issue #3343
I am using the imshow function in matplotlib to visualize some data. What I have are two arrays, A and B, that are the same size. I would like to use a colormap to show scalar values in A, and I would like to use the alpha channel to show the scalar values in B. In other words, if the value at a given coordinate in both A and B is large, then the pixel in the plot will be bright green and opaque. If it is large in A and not B, then it will be bright green but mostly transparent. And if it is large in B and not A, then it will be opaque but white.
However, the resulting image is not what I am expecting. My input data is called d, and it is a combination of the RGB values that result from mapping the A array with a matplotlib colormap (i.e. mpl.cm.BuGn(A)) and the B array.
Here I'm going to plot the full image (what I want to actually use), the RGB image (A, mapped with BuGn), and the alpha-providing array (B, with a grayscale colormap).
f, (ax0, ax1, ax2) = plt.subplots(1, 3, figsize=(5, 2.5))
ax0.imshow(d)
ax1.imshow(d[..., :-1])
ax2.imshow(d[..., -1])

I am confused about where the splotchy gray junk in the full image is coming from, since there aren't any values in the colormap that are those colors. To show this effect more dramatically, I can change the bounds of the colormap so they are far away from the extremes of the data and re-plot:

I don't understand why pixels that are white with a large alpha value show up as gray. Opaque white should still be white.
Note that this behavior is different than if I plot the RGB component array and lower the transparancy with the alpha kwarg, i.e. ax2.imshow(d[..., :-1], alpha=.3):

回答1:
My first answer was completely wrong, so here's my new attempt.
DaveAllen's comment above accurately reproduces the issue.
import numpy as np
import matplotlib.pyplot as plt
d = np.ones((100, 100, 4), dtype=np.uint8)*255
d[:, :, 3] = np.linspace(0, 255, num=100)
plt.imshow(d, interpolation='none')
plt.show()
Produces:

You would expect a white image on a white background with variable alpha to be completely white. And that would be the case with "straight" alpha.
It would seem that matlplotlib's graphics backend is displaying the image assuming "premultiplied" alpha, which means that the alpha affects the color of the image. This would explain the image above.
http://en.wikipedia.org/wiki/Alpha_compositing http://blogs.msdn.com/b/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx https://www.mail-archive.com/matplotlib-users@lists.sourceforge.net/msg22377.html
Pixels that are (1.0,1.0,1.0,0.5), when displayed, have their color first multiplied by their alpha channel, so they appear (0.5,0.5,0.5,0.5), gray.
The pixels on the right are opaque and white, so they appear white. The pixels on the left are displayed black and transparent so they appear the same as the background color, which is white.
The pixels in the middle are grey because they are displayed neither white nor transparent.
回答2:
The revised answer by the venerable ballsdotballs seems plausible. From that mailing list post, it looks like handling of alpha values was not carefully thought out. Further, from the example in the original post, it seems to me that the alpha arg in imshow is composited differently than alpha numbers provided in RGBA data.
To work around whatever blending Agg is doing, one could avoid alpha and do the compositing manually.
A = np.tile(np.linspace(0, 1, num=100), (100, 1)) # gradient
B = A.T
d = plt.cm.BuGn(A)
d[..., -1] = B
composite = (d[..., :-1] * d[..., -1].reshape(100, 100, 1) +
(1 - d[..., -1]).reshape(100, 100, 1))
fig, axes = plt.subplots(1, 2)
axes[0].imshow(d)
axes[1].imshow(composite)

I'm sure there's a better way to do the reshaping, but that's not the issue here.
来源:https://stackoverflow.com/questions/25089068/how-does-imshow-handle-the-alpha-channel-with-an-m-x-n-x-4-input