I am putting up a colorbar tool with Python/Matplotlib and need to change the opacity at arbitrary ranges along the Y axis, instead of having the opacity value associated to the colors themselves.
Reading other posts in SO and various online tutorials, I came across posts showing pcolormesh, facecolor, edgecolor or adding the alpha value as the 4th column in the RGB color definition, but none of them actually solves the problem.
If you run my minimum sample code below (with previous help from SO, which I appreciate), you will see the opacity as defined by each color:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
XMIN = 0.0
XMAX = 1.0
YMIN = 1000.0
YMAX = 2000.0
RATIO = 5.0
NUM_COLORS = 256
color_list = ([0.2, 0.88, 0.3, 0.25], [0.33, 1.0, 0.25, 0.15], [0.7, 0.2, 0.5, 1.0], [0.0, 0.34, 0.2, 0.1], [0.5, 0.9, 0.1, 1.0]) # RGBA, 0 to 1 plus opacity
bounds = [YMIN, 1100.0, 1400.0, 1800.0, YMAX]
color_tuples = [(i, color) for i, color in zip(np.interp(bounds, [bounds[0], bounds[-1]], [0, 1]), color_list)]
fig, ax = plt.subplots(1, 1, figsize = (4, 10), num = "Variable opacity by Y?")
segm_cmap = mpl.colors.LinearSegmentedColormap.from_list("Segm_cmap", color_tuples, N = NUM_COLORS)
norm = plt.Normalize(vmin = bounds[0], vmax = bounds[-1])
img = ax.imshow(np.linspace(YMIN, YMAX, NUM_COLORS).reshape(-1, 1), cmap = segm_cmap, norm = norm, interpolation = "bilinear",
origin = "lower", extent = [XMIN, XMAX, YMIN, YMAX])
ax.set_aspect((XMAX - XMIN) / (YMAX - YMIN) * RATIO)
plt.show()
However, just like the color boundaries/gradient defined by the "bounds" list, I thought I could make a similar tuple with x,y pairs and the respective opacity and pass it as "alpha" to imshow(), since Matplotlib documentation suggests it accepts, among other things, a 2D array. Something like:
opacities = ([[XMIN to XMAX, YMIN to 1200], 1.0], [[XMIN to XMAX, 1200.1 to 1500], 0.5], [[XMIN to XMAX, 1500.1 to YMAX], 0.1])
img = ax.imshow(....., alpha = opacities)
That is, a X-range, a Y-range and an opacity value. But I couldn’t for the life of me make it work, nor could I find a few sample codes to guide me. So I said, "for justice, I must go to Don Corl…", I mean, I must seek advice from the wise guys if it is at all possible. For your reference, I have Python 3.10.12 and Matplotlib 3.5.1 (Ubuntu 22.04, if relevant).
2
Answers
The code below creates the pattern for alpha (left), which is applied to a Y grid (centre), resulting in the alpha-shaded image (right).
The code creates a vector of alpha values based on the values and break points you specified. The alpha vector and the y axis vectors are then duplicated onto a 2D grid and rendered.
LinearSegmentedColormap
smooths out the colors (including the alpha values).When the
alpha=
parameter ofimshow()
is 2D, it needs to have the same number of elements as the image data. For your use case,np.where()
can be used to create the alphas from the image data.The code below ignores the alpha given in the original color list: