Edit 3:
It was found that the main question:
How to put a "black and transparent" mask before the matplotlib image created by imshow ? The mask should be derived from a previously completed black and white matplotlib drawing.
The following code demonstrates this feature by accessing and blending rgba bitmaps:
import numpy as np import matplotlib.pyplot as plt import matplotlib.cm as cm import matplotlib.mlab as mlab def get_rgba_bitmap(fig): fig.canvas.draw() tab = fig.canvas.copy_from_bbox(fig.bbox).to_string_argb() ncols, nrows = fig.canvas.get_width_height() return np.fromstring(tab, dtype=np.uint8).reshape(nrows, ncols, 4) def black_white_to_black_transpa(rgba): rgba[:, :, 3] = 255 - rgba[:, :, 0] rgba[:, :, 0:3] = 0 def over(rgba1, rgba2): if rgba1.shape != rgba2.shape: raise ValueError("rgba1 and rgba2 shall have same size") alpha = np.expand_dims(rgba1[:, :, 3] / 255., 3) rgba = np.array(rgba1 * alpha + rgba2 * (1.-alpha), dtype = np.uint8) return rgba[:, :, 0:3]
Donation: 
I tested your original photon test and the image quality looked fine

Now, if you want the background image to be transparent too:
- Set fig1 background to white, i.e.
fig1 = plt.figure(facecolor='white') , since white will become transparent when transferred to black_white_to_black_transpa - Set fig2 background to transparent
fig2.patch.set_alpha(0.0) as it will be saved unchanged in bitmap_rgba2 - Finally, take care of the alpha channel when mixing
bitmap_rgba1 and bitmap_rgba2 inside over (see below for a possible modification)
def over(rgba1, rgba2): if rgba1.shape != rgba2.shape: raise ValueError("rgba1 and rgba2 shall have same size") alpha1 = np.expand_dims(rgba1[:, :, 3] / 255., axis=3) alpha2 = np.expand_dims(rgba2[:, :, 3] / 255., axis=3) alpha = 1. - (1.-alpha1) * (1.-alpha2) C1 = rgba1[:, :, 0:3] C2 = rgba2[:, :, 0:3] C = (alpha1 * C1 + (1-alpha1) * alpha2 * C2) / alpha rgba = np.empty_like(rgba1, dtype = np.uint8) rgba[:, :, 0:3] = C rgba[:, :, 3] = 255 * alpha[:, :, 0] return rgba
last (?) edit: There seems to be an inconsistency between the array returned by to_string_argb and expected with imshow (rgb channel order). A possible solution is to change ax.imshow(over(bitmap_rgba1, bitmap_rgba2)) to:
over_tab = over(bitmap_rgba1, bitmap_rgba2) over_tab[:, :, 0:3] = over_tab[:, :, ::-1][:, :, 1:4] ax.imshow(over_tab)