Given three 1D arrays of X, Y and Z coordinates, how to convert into a 3D mesh path using numpy?
I managed to do this for 2D using numpy (ie no for loops):
import numpy
def path_2d_numpy(x, y):
m1, m2 = numpy.meshgrid(x, y)
m1[1::2] = m1[1::2,::-1]
r = numpy.append(m1, m2)
r.shape = 2,-1
return r.T
from matplotlib import lines
from matplotlib import pyplot
def plot_path_2d(path):
x, y = path.T
pyplot.plot(x, y, '-ro', lw=3)
pyplot.show()
x = numpy.linspace(4, 1, 4)
y = numpy.linspace(1, 5, 5)
path = path_2d_numpy(x, y)
plot_path_2d(path)
which outputs:
...but was unable to do it for 3D. Showing pure python solution (ie without numpy):
import numpy
def path_3d(x, y, z):
nb_points =len(x)*len(y)*len(z)
path = numpy.empty((nb_points, 3))
xord, yord, i = True, True, 0
for zi in z:
for yi in y[::1 if yord else -1]:
for xi in x[::1 if xord else -1]:
path[i] = xi, yi, zi
i += 1
xord = not xord
yord = not yord
return path
from matplotlib import pyplot
from mpl_toolkits.mplot3d import Axes3D
def plot_path_3d(path):
fig = pyplot.figure()
ax = fig.gca(projection='3d')
xx, yy, zz = path.T
ax.plot(xx, yy, zz, '-bo', lw=3)
pyplot.show()
x = numpy.linspace(4, 1, 4)
y = numpy.linspace(1, 5, 5)
z = numpy.linspace(-3, 0, 3)
path = path_3d(x, y, z)
plot_path_3d(path)
which outputs:
Essencialy, what I am looking for is for a numpy implementation of path_3d as I did for path_2d_numpy.
I need this because the actual arrays I am dealing with are quite big. Doing it without numpy is just too slow.
How's this look?
import numpy as np
def path_3d_numpy(x, y, z):
coords = np.stack(np.meshgrid(x, y, z), axis=-1) # shape = (nx, ny, nz, 3)
coords[1::2,:,:] = coords[1::2,::-1,:]
coords[:,1::2,:] = coords[:,1::2,::-1]
return coords.reshape(-1, 3) # flatten out the other axes
Doesn't iterate the points in quite the same order as yours, but you could fix that simply by swapping some indices around
Similarly, your 2d case could be written as
def path_2d_numpy(x, y):
coords = np.stack(np.meshgrid(x, y), axis=-1)
coords[1::2] = coords[1::2,::-1]
return coords.reshape(-1, 2)
For some real overkill, you can extend this to N dimensions:
def path_nd(*args):
coords = np.stack(np.meshgrid(*args), axis=-1)
N = len(args)
axes = np.arange(N)
for i in range(N-1):
# the last axis isn't part of our mesh, so don't roll it
rolled_axes = tuple(np.roll(axes, -i)) + (N,)
rolled_view = np.transpose(coords, rolled_axes)
rolled_view[1::2,:] = rolled_view[1::2,::-1]
return coords.reshape(-1, N)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With