33
votes

I'd like to make an overlay of several hexbin plots, but with builtin colormaps only the last one is visible. I don't want to construct a colormap de novo. How one would add linear alpha to the colormap without knowing the inner structure of the colormap beforehand?

2

2 Answers

55
votes

I'm not quite sure if this qualifies within "not knowing the inner structure of the colormap", but perhaps something like this would work to add a linear alpha to an existing colormap?

import numpy as np
import matplotlib.pylab as pl
from matplotlib.colors import ListedColormap

# Random data
data1 = np.random.random((4,4))

# Choose colormap
cmap = pl.cm.RdBu

# Get the colormap colors
my_cmap = cmap(np.arange(cmap.N))

# Set alpha
my_cmap[:,-1] = np.linspace(0, 1, cmap.N)

# Create new colormap
my_cmap = ListedColormap(my_cmap)

pl.figure()
pl.subplot(121)
pl.pcolormesh(data1, cmap=pl.cm.RdBu)
pl.colorbar()

pl.subplot(122)
pl.pcolormesh(data1, cmap=my_cmap)
pl.colorbar()

enter image description here

7
votes

I'd like to extend the answer by Bart by a fix, that eliminates the line artifacts in the colorbar. Some history: as of today, these line artifacts still persist, and are not well solved (see Matplotlib: Add a custom colorbar that runs from full transparent to full color (remove artifacts), why does my colorbar have lines in it?). However, every color with an alpha channel is nothing but a mixture of the color with its background. Therefore, if you know the background, you can calculate the corresponding non-alpha color (see https://www.viget.com/articles/equating-color-and-transparency/).

The following solution assumes, that actual transparency is not necessary for the figure. If one uses true alpha in the figure and an own colormap with calculated non-alpha color values if desired.

import numpy as np
import matplotlib.pylab as pl
from matplotlib.colors import ListedColormap

# Random data
data1 = np.random.random((4,4))

# Choose colormap which will be mixed with the alpha values
cmap = pl.cm.RdBu

# Get the colormap colors
my_cmap = cmap(np.arange(cmap.N))
# Define the alphas in the range from 0 to 1
alphas = np.linspace(0, 1, cmap.N)
# Define the background as white
BG = np.asarray([1., 1., 1.,])
# Mix the colors with the background
for i in range(cmap.N):
    my_cmap[i,:-1] = my_cmap[i,:-1] * alphas[i] + BG * (1.-alphas[i])
# Create new colormap which mimics the alpha values
my_cmap = ListedColormap(my_cmap)

# Plot
f, axs = pl.subplots(1,2, figsize=(8,3))
h = axs[0].pcolormesh(data1, cmap=pl.cm.RdBu)
cb = f.colorbar(h, ax=axs[0])

h = axs[1].pcolormesh(data1, cmap=my_cmap)
cb = pl.colorbar(h, ax=axs[1])
f.show()

image wo artifacts