0

This is my first question and I hope I can describe my issue properly.

I tried to write down a minimal example. My goal is to get a nice plot of a vector field in the xy plane (so just one layer, but a 3d view) where the colors of my arrows should be completely red (blue) if they are pointing completely in the positive (negative) z-direction and gray if they are located in the xy plane. (Slightly red resp. red if they have some positive resp. negative z component etc - so I thought about a 'coolwarm' colormap. But I do not really know how to tho this. I tried to solve my problem with this question and the answers Adding colors to a 3d quiver plot in matplotlib and with the way I am adding my color bars to pcolormesh-plots where it is working fine. , but I didn't really manage to do it properly, as you can see here: plot obtained from my code

I do not really understand some of the code they used there and it would be nice if someone could help me with that :) I do not understand what this part does q.set_array(np.linspace(-1,1,3)) and why I need q.set_edgecolor(c) and q.set_facecolor(c). Besides I am

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import BoundaryNorm
from matplotlib.ticker import MaxNLocator

# Make the grid
x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2),
                      np.arange(-0.8, 1, 0.2),
                      np.arange(0.0, 0.6, 0.5))

# Make the direction data for the arrows
u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z)
v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z)
w = 0.2 + np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z)

#define colorbar like I usually do it for 2d density plot etc where it works
cmap = 'coolwarm'
cm = plt.get_cmap(cmap)
plot_min = -1.
plot_max = 1.
levels = MaxNLocator(nbins=100).tick_values(plot_min, plot_max)
norm = BoundaryNorm(levels, ncolors=cm.N, clip=True)

# Color by z-component of vectors (u,v,w) angle
c = w
# Flatten and normalize
c = (c.ravel() - c.min()) / c.ptp()
# Repeat for each body line and two head lines
c = np.concatenate((c, np.repeat(c, 2)))
# Colormap
c = getattr(plt.cm, cmap)(c)

fig = plt.figure(figsize=(10,7))
ax = fig.gca(projection='3d')
q = ax.quiver(x, y, z, u, v, w, colors=c, cmap = cmap, length=0.1, normalize=norm)
q.set_array(np.linspace(-1,1,3))

cbar = fig.colorbar(q, ticks=[-1, 0, 1], fraction=0.015)
cbar.ax.set_yticklabels(['-1', '0', '1'])
cbar.ax.tick_params(labelsize=15)
q.set_edgecolor(c)
q.set_facecolor(c)
#ax.set_zlim(-0.4, 0.4)
ax.view_init(azim=90, elev=20)
ax.grid(False)
plt.axis('off')
plt.show()

if this would work, it would be super cool! Is there a way to make the arrows look nicer? It would be perfect if the arrows could look like the ones in Mathematica-plots like this: example from Mathematica

Thank you a lot in advance!

  • documentation for `linspace` https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html, basically it gives you a list of three equally spaces values between -1 and 1 – CervEd May 07 '20 at 14:06
  • yeah I know that linspace slices the interval btw, -1 and 1, but I meant I don't get it, why or how they used it (in that post that I linked) for their color bar. And yeah you're right - thatnks for the advice! Besides I am confused about this whole part about the colors from `c = (c.ravel() - c.min()) / c.ptp()` and the next lines until I definie my figure fig with the size – beginner2020 May 07 '20 at 22:38

1 Answers1

0

"Tube" Arrows in Python

I found this awesome post. It was exactly the way I want my arrows to look like in the end :)