简体   繁体   中英

How to convert arrays of x,y,z coordinates to 3D path in numpy

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:

2D网格路径

...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:

3D网格路径

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM