1

Data:

I have the following vector field:

enter image description here

Goal

I would like to have the arrow transparency proportional to the arrow length.

My Attempt:

I set the "alpha" value equal to the length:

import numpy as np
import matplotlib.pyplot as plt

# DATA FIELD (1,N,M)
dz = np.array([[[0.24884899, 0.24884899, 0.24884899, 0.24884899, 0.24884899,
         0.24884899],
        [0.248849  , 0.248849  , 0.248849  , 0.248849  , 0.248849  ,
         0.248849  ],
        [0.24885767, 0.24885513, 0.24885108, 0.24885113, 0.2488552 ,
         0.24885767],
        [0.2451304 , 0.24563262, 0.24642831, 0.24641793, 0.24561579,
         0.2451304 ],
        [0.0764377 , 0.12581053, 0.09866768, 0.10043774, 0.12461962,
         0.0764377 ],
        [0.03382106, 0.03394624, 0.03414449, 0.03414171, 0.03394174,
         0.03382106]]])

dx = np.zeros(np.shape(dz))
dy = np.zeros(np.shape(dz))

# DATA POINTS (N,)
X = np.array([0. , 0.2, 0.4, 0.6, 0.8, 1. ])
Y = X 
Z = np.array([-500., -360., -220.,  -80.,   60.,  200.])


# COMPUTE LENGTH OF VECTORS
length = np.sqrt(dx[0]**2+ dz[0]**2)

# PLOT 2D Cross-Section of vector field
fig = plt.figure(dpi=300)
Q = plt.quiver(X, Z, dx[0], dz[0], length, units='xy' ,angles='xy', scale=0.005,  
       pivot = "tail", headaxislength = 5, headlength = 5, cmap='jet', alpha = length)
fig.colorbar(Q)
plt.gca().invert_yaxis()
plt.ylabel("Z")
plt.xlabel("X")
plt.title("2D Cross-Section")

Problem:

... I get:

TypeError: alpha must be a float or None

Edit

3D Vector Field to test

import matplotlib.pyplot as plt
import numpy as np

plt.rcParams["figure.figsize"] = [7.50, 3.50]
plt.rcParams["figure.autolayout"] = True

fig = plt.figure(dpi = 300)

ax = fig.add_subplot(projection='3d')

x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2),
                     np.arange(-0.8, 1, 0.2),
                     np.arange(-0.8, 1, 0.2))

u = x
v = y
w = z

ax.quiver(x, y, z, u, v, w, length=0.2)
ax.axis('off')

plt.show()

enter image description here

Edit 2

The resulting plot does not have consistent alpha values. It seems that some long vectors are still not transparent. The transparency should increase linearly from the center, which is not the case here:

import numpy as np, matplotlib.pyplot as plt


def plot_3d_quiver(x, y, z, u, v, w):
    c = np.sqrt(np.abs(v)**2 + np.abs(u)**2 + np.abs(w)**2)
    length = np.repeat(((c - c.min())/(c.max() - c.min())).ravel(), 3)
    c = (c.ravel() - c.min())/c.ptp()
    c = np.concatenate((c, np.repeat(c, 2)))
    c = plt.cm.jet(c)
    
    # INVERT -> Long vectors should be more transparent
    c[:, -1] = 1 - length

    fig = plt.figure(dpi = 300)
    ax = fig.gca(projection = '3d')
    ax.quiver(x, y, z, u, v, w, length = .5, arrow_length_ratio = 0.2, alpha=c)
    # ax.axis('off')


x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2),
                      np.arange(-0.8, 1, 0.2),
                      np.arange(-0.8, 1, 0.2))
u = x
v = y
w = z

plot_3d_quiver(x, y, z, u, v, w)

plt.show()

enter image description here

halfer
  • 19,824
  • 17
  • 99
  • 186
henry
  • 875
  • 1
  • 18
  • 48
  • maybe you should try using ```c[:,-1]``` for the ```alpha``` parameter in the ```quiver``` – Udi Aug 18 '21 at 16:18

1 Answers1

1

From the TypeError you got, I suspect you are using a old version of matplotlib. Checking the documentation for the last version, regarding alpha parameter:

Property Description
alpha array-like or scalar or None

So the last version of matplotlib supports alpha as array-like. If you update your package, you should solve the TypeError.


(used matplotlib 3.4.2)
Taking inspiration from this answer, you could define a colormap which includes the transparency:

cmap = plt.cm.jet
my_cmap = cmap(np.arange(cmap.N))
alphas = np.linspace(0, 1, cmap.N)
BG = np.asarray([1., 1., 1.,])
for i in range(cmap.N):
    my_cmap[i,:-1] = my_cmap[i,:-1] * alphas[i] + BG * (1.-alphas[i])
my_cmap = ListedColormap(my_cmap)

And then pass it to quiver:

Q = plt.quiver(X, Z, dx[0], dz[0], length, units='xy' ,angles='xy', scale=0.005,
       pivot = "tail", headaxislength = 5, headlength = 5, cmap=my_cmap)

Complete Code

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

# DATA FIELD (1,N,M)
dz = np.array([[[0.24884899, 0.24884899, 0.24884899, 0.24884899, 0.24884899,
         0.24884899],
        [0.248849  , 0.248849  , 0.248849  , 0.248849  , 0.248849  ,
         0.248849  ],
        [0.24885767, 0.24885513, 0.24885108, 0.24885113, 0.2488552 ,
         0.24885767],
        [0.2451304 , 0.24563262, 0.24642831, 0.24641793, 0.24561579,
         0.2451304 ],
        [0.0764377 , 0.12581053, 0.09866768, 0.10043774, 0.12461962,
         0.0764377 ],
        [0.03382106, 0.03394624, 0.03414449, 0.03414171, 0.03394174,
         0.03382106]]])

dx = np.zeros(np.shape(dz))
dy = np.zeros(np.shape(dz))

# DATA POINTS (N,)
X = np.array([0. , 0.2, 0.4, 0.6, 0.8, 1. ])
Y = X
Z = np.array([-500., -360., -220.,  -80.,   60.,  200.])


# COMPUTE LENGTH OF VECTORS
length = np.sqrt(dx[0]**2+ dz[0]**2)

# COLORMAP DEFINITION
cmap = plt.cm.jet
my_cmap = cmap(np.arange(cmap.N))
alphas = np.linspace(0, 1, cmap.N)
BG = np.asarray([1., 1., 1.,])
for i in range(cmap.N):
    my_cmap[i,:-1] = my_cmap[i,:-1] * alphas[i] + BG * (1.-alphas[i])
my_cmap = ListedColormap(my_cmap)

# PLOT 2D Cross-Section of vector field
fig = plt.figure(dpi=300)
Q = plt.quiver(X, Z, dx[0], dz[0], length, units='xy' ,angles='xy', scale=0.005,
       pivot = "tail", headaxislength = 5, headlength = 5, cmap=my_cmap)
fig.colorbar(Q)
plt.gca().invert_yaxis()
plt.ylabel("Z")
plt.xlabel("X")
plt.title("2D Cross-Section")

plt.show()

enter image description here

You can also reverse the transparency and set different maximum and minimum value by changing the first and second parameters of np.linspace:

alphas = np.linspace(1, 0.1, cmap.N)

enter image description here


Considering the 3D vector field that you provided in the edit and taking inspiration from this answer, you can edit the 4-th value of c, which determinates the transparency, accordingly to the vector length:

import numpy as np, matplotlib.pyplot as plt


def plot_3d_quiver(x, y, z, u, v, w):
    c = np.sqrt(np.abs(v)**2 + np.abs(u)**2 + np.abs(w)**2)
    length = np.repeat(((c - c.min())/(c.max() - c.min())).ravel(), 3)
    c = (c.ravel() - c.min())/c.ptp()
    c = np.concatenate((c, np.repeat(c, 2)))
    c = plt.cm.jet(c)

    c[:, -1] = 1 - length

    fig = plt.figure(dpi = 300)
    ax = fig.gca(projection = '3d')
    ax.quiver(x, y, z, u, v, w, colors = c, length = .5, arrow_length_ratio = 0.2, cmap = plt.cm.jet)
    ax.axis('off')


x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2),
                      np.arange(-0.8, 1, 0.2),
                      np.arange(-0.8, 1, 0.2))
u = x
v = y
w = z

plot_3d_quiver(x, y, z, u, v, w)

plt.show()

enter image description here

Zephyr
  • 11,891
  • 53
  • 45
  • 80
  • Thank you very much for your very helpful answer! Would you mind testing your solution with the 3D Vector field that I just posted on my question? Many thanks! – henry Aug 16 '21 at 13:11
  • Thanks a lot!! (very cool) The Only thing: It's hard for me to see if the arrows on the edge are really transparent or just another color. Would you mind increasing the transparency on the longer ones a bit such that they really vanish? – henry Aug 16 '21 at 14:02
  • 2
    It seems to me that you are changing the colors of the arrows, but not the transparency as asked in the OP's question. –  Aug 16 '21 at 14:06
  • You can customize the tranparency of the arrow by editing `alphas = np.linspace(A, B, cmap.N)` where the `A` parameter is the opacity of the shorter arrows, while the `B` parameter is the opacity of the longer ones. So, `alphas = np.linspace(1, 0, cmap.N)` should do the job – Zephyr Aug 16 '21 at 14:14
  • Thanks for your comment, but it still does not seem to be transparent. Can't you just simply set the real alpha keyword value equal to a normalized length array? . – henry Aug 16 '21 at 14:24
  • You are right, my mistake. I updated my answer accordingly, hoping this may fulfill your requirements – Zephyr Aug 16 '21 at 14:39
  • @Zephyr Please see Edit 2. I tried your approach, but the resulting plot does not show a linear increase in transparency. Do you see why? – henry Aug 17 '21 at 10:51