Search code examples
pythonmathmatplotlibspiral

How to get the length of the entire 3d linear function in Python?


I create a graph of a logarithmic spiral in the form of a spring. I'm using the below parametric equations:

x=a*exp(b*th)*cos(th)
y=a*exp(b*th)*sin(th)

Here is my code:

from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['legend.fontsize'] = 10

fig = plt.figure(figsize=(10,10))
ax = fig.gca(projection='3d')

a=0.6
b=0.2
th=np.linspace(0, 25, 1000)
x=a*np.exp(b*th)*np.cos(th)
y=a*np.exp(b*th)*np.sin(th)
z = np.linspace(0, 2, len(th))
ax.plot(x, y, z)

ax.plot(x, y, zdir='z', zs=0)
ax.plot(x, z, zdir='y', zs=100)

ax.set_xlim([-100, 100])
ax.set_ylim([-100, 100])
ax.set_zlim([-0, 2.5])

plt.show()

This gives me the following output:

graph of a logarithmic spiral in the form of a spring

Can I get the length of the entire spiral? Is it possible to mark the position of a point on the graph, which lies in the distance (for example, 5), starting from the beginning of the graph in point (x,y)=(0,0), and pull out these coordinates? I will be grateful for any tips.


Solution

  • Pythagoras works as well in 3 dimensions. Any line segment si has a length of

    si = sqrt(xi**2+yi**2+zi**2)
    

    Hence,

    a=0.6
    b=0.2
    th=np.linspace(0, 25, 1000)
    x=a*np.exp(b*th)*np.cos(th)
    y=a*np.exp(b*th)*np.sin(th)
    z = np.linspace(0, 2, len(th))
    
    diffs = np.sqrt(np.diff(x)**2+np.diff(y)**2+np.diff(z)**2)
    length = diffs.sum()
    print length # prints 451.011712939
    

    the length of the line is 451.
    Note that the extention of the line in z direction is much smaller than in x and y, so we might as well leave out z completely, the error when doing so is 0.025 or 0.006%.

    The other aim is to find the point on the line where the line is some length l=5 long. Of course since we work with numerical data, we do not find the point where it is exactly 5 units long, but e.g. rather that point where the length is smaller than 5 but closest to it. We can calculate the index at which point that happens,

    l = 5 # length to find coordinate of
    cumlenth = np.cumsum(diffs)
    s = np.abs(np.diff(np.sign(cumlenth-l))).astype(bool)
    c = np.argwhere(s)[0][0]
    

    and then find that index in the original arrays.

    print c   # index of coordinate, here 192
    print x[c], y[c], z[c] # 0.144750230412 -1.56183108038 0.384384384384
    

    We might then label that point with a scatter,

    ax.scatter([x[c]], [y[c]], [z[c]], color="crimson")
    

    enter image description here