Cade Karrenberg
Cade Karrenberg

Reputation: 53

How to calculate distances in 3D coordinates in an array

I'm trying to calculate initial and subsequent distances between points. The data I was given is a csv where every three columns corresponds to an LED marker. ie column 1 is the x-coord for marker 1, column 2 is the y-coord for marker 1, column 3 is the z-coord for marker 1 ets. each row corresponds to the time at which the location was recorded. I'm having a difficult time figuring out the best way to organize the data so that I can use it. I need to a) find initial locations and initial distances between markers at time 0 and b)find any change in distance between markers at different times.

I originally put all x-coords in an array, all y-coords in an array and all z-coords in an array, but realized that I couldn't (didn't know how?) to iterate over arrays so I could find the difference between the adjacent points. ie. the distance between marker 1 and marker 2 is sqrt((x2-x1)**2+(y2-y1)**2+(z2-z1)**2) but since x2 and x1 are in the same array couldn't (didn't know how?) to iterate the difference between all xs (and ys and zs, respectively). In the code below I transposed the arrays so I could iterate over rows (not columns)

for i in range(m): #where m is the number of markers
    x_diff= x_array[i+1]-x_array[i]
    y_diff=y_array[i+1]-y_array[i]
    z_diff=z_array[i+1]-z_array[i]
    dist=np.sqrt(x_diff**2+y_diff**2+z_diff**2)

I'd like an array where each column is the euclidean distance between adjacent markers and the rows correspond to the distance at each time.

Upvotes: 2

Views: 1230

Answers (3)

dgumo
dgumo

Reputation: 1878

You can use SciPy's pdist function for pairwise distances. For example,

>>> X
array([[1, 2, 3],
       [1, 2, 3],
       [4, 0, 0]])
>>> from scipy.spatial.distance import pdist
>>> pdist(X)
array([0.        , 4.69041576, 4.69041576])

The distances are output as pairs (0,1), (0,2), (1,2).

Upvotes: 2

Daniel F
Daniel F

Reputation: 14399

You need to turn that 2d array into a 3d array.

rows, cols = csv.shape
csv_3d = csv.reshape(rows, -1, 3)

Then np.diff along the second axis (between points)

del_csv_3d = np.diff(csv_3d, axis = 1)

Then take the norm along the last axis

out = np.linalg.norm(del_csv_3d , axis = -1)

This should be the data you need.

Upvotes: 0

Paul Panzer
Paul Panzer

Reputation: 53029

Here is a step-by-step starting from an array that is layed out like your original csv:

# 2 time points, 4 markers, values between 0 and 8
csv = np.random.randint(0,9,(2,12))
csv
# array([[8, 5, 3, 2, 3, 2, 2, 5, 6, 8, 2, 4],
#        [8, 2, 7, 4, 7, 7, 8, 0, 3, 0, 2, 4]])

# reshape to get x,y,z aligned
m,n = csv.shape
xyz = csv.reshape(m,-1,3)
xyz
# array([[[8, 5, 3],
#         [2, 3, 2],
#         [2, 5, 6],
#         [8, 2, 4]],
#
#        [[8, 2, 7],
#         [4, 7, 7],
#         [8, 0, 3],
#         [0, 2, 4]]])

# get coordinate-wise differences between adjacent markers
dist_1d = np.diff(xyz,axis=1)
dist_1d
# array([[[-6, -2, -1],
#         [ 0,  2,  4],
#         [ 6, -3, -2]],
#
#        [[-4,  5,  0],
#         [ 4, -7, -4],
#         [-8,  2,  1]]])

# compute squared Euclidean distance
# (you could take the square root of that but if you are
# only interested in changes it doesn't seem necessary)
eucl2 = (dist_1d*dist_1d).sum(axis=2)
eucl2
# array([[41, 20, 49],
#        [41, 81, 69]])

Upvotes: 0

Related Questions