Given list of alpha values in 3D scatter does not match with plotted result

74 views Asked by At

I try to visualize the classification of points in 3D. When I give the classification to the 'c' parameter in the scatter function the result is as expected. But When I give the exact same classifications to the 'alpha' parameter, it seems to become noise.

Here is an example with a sin wave. (I scaled the alpha parameter to reveal that it's only noise)

import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
mpl.rcParams['figure.facecolor'] = 'white'

# Orientation sampling
angles = range(0,360,10)
euler = np.array([[[[x,y,z] for z in angles] for y in angles] for x in angles])
euler = euler.reshape((-1,3))

# Make some classification
cls = np.abs(np.sin(euler.mean(1)))
print("min:", cls.min())
print("max:", cls.max())
print("mean:", cls.mean())

# visualize
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.scatter(euler[:,0],euler[:,1],euler[:,2], c=cls, s=5, alpha=1.0, cmap='viridis')
plt.show()

fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.scatter(euler[:,0],euler[:,1],euler[:,2], c='b', s=5, alpha=cls**10/10)
plt.show()

Output:

min: 0.0
max: 0.9999727218865074
mean: 0.6366588835775282

c=cls shows a nice sin wave:

c=cls shows a nice sin wave

alpha=cls**10/10 shows points with random alpha value:

alpha=cls**10/10 shows points with random alpha value

I expected to see the same pattern when assigning the classification to the alpha value.

I currently work around the issue by using the point size to hide the lower classified points.

1

There are 1 answers

0
JohanC On

It is unclear what's going on. Normally, since matplotlib 3.4, alpha as an array is supported for a scatter plot, both 2D and 3D. Unlike the c parameter, which automatically gets transformed to the range 0 - 1, the alpha parameter should allready be in the correct range.

Nevertheless, you can get the same effect using a colormap with alpha values.

Here is an example:

import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, to_rgba
import numpy as np

mpl.rcParams['figure.facecolor'] = 'white'

# Orientation sampling
angles = range(0, 360, 10)
euler = np.array([[[[x, y, z] for z in angles] for y in angles] for x in angles])
euler = euler.reshape((-1, 3))

# Make some classification
cls = np.abs(np.sin(euler.mean(1)))
# visualize
alpha_cmap = LinearSegmentedColormap.from_list('', ['b', to_rgba('b', alpha=0)])

fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.scatter(euler[:, 0], euler[:, 1], euler[:, 2], c=cls, s=5, cmap=alpha_cmap)
plt.show()

matplotlib scatter with alpha array

As the c parameter is used here, it gets automatically expanded to the range 0 to 1. You can experiment with vmin and vmax to change the range. Or you can use a different lower alpha when creating the LinearSegmentedColormap (optionally reversing the order of the colors).