Skip to content
Advertisement

fitting closed curve to a set of noisy points

This is my set of data, where I would like to fit a closed curve to, just like this post

array([[ 0.3 , -0.05],
       [ 0.35, -0.05],
       [ 0.4 , -0.05],
       [ 0.45, -0.05],
       [ 0.5 , -0.05],
       [ 0.55, -0.05],
       [ 0.6 , -0.05],
       [ 0.65, -0.05],
       [ 0.7 , -0.05],
       [ 0.75, -0.05],
       [ 0.8 , -0.05],
       [ 0.85, -0.05],
       [ 0.9 , -0.05],
       [ 0.95, -0.05],
       [ 1.  , -0.05],
       [ 1.05, -0.05],
       [ 1.1 , -0.05],
       [ 1.15, -0.05],
       [ 1.2 , -0.05],
       [ 1.25, -0.05],
       [ 1.3 , -0.05],
       [ 1.35, -0.05],
       [ 1.4 , -0.05],
       [ 1.45, -0.05],
       [ 1.5 , -0.05],
       [ 1.55, -0.05],
       [ 1.6 , -0.05],
       [ 1.65, -0.05],
       [ 1.7 , -0.05],
       [ 1.75, -0.05],
       [ 1.8 , -0.05],
       [ 0.  , -0.1 ],
       [ 0.05, -0.1 ],
       [ 0.  , -0.15],
       [ 2.1 , -0.15],
       [ 2.15, -0.15],
       [ 0.  , -0.2 ],
       [ 2.1 , -0.2 ],
       [ 2.15, -0.2 ],
       [ 2.2 , -0.2 ],
       [ 2.2 , -0.25],
       [ 2.35, -0.35],
       [-0.15, -0.4 ],
       [ 2.35, -0.4 ],
       [-0.15, -0.45],
       [ 2.35, -0.45],
       [ 2.4 , -0.45],
       [ 2.35, -0.5 ],
       [ 2.4 , -0.5 ],
       [ 2.4 , -0.55],
       [-0.25, -0.6 ],
       [-0.2 , -0.6 ],
       [ 2.4 , -0.6 ],
       [ 2.45, -0.6 ],
       [-0.4 , -0.65],
       [ 2.45, -0.65],
       [-0.4 , -0.7 ],
       [ 2.45, -0.7 ],
       [ 2.5 , -0.7 ],
       [ 2.45, -0.75],
       [ 2.45, -0.8 ],
       [-0.5 , -0.85],
       [ 2.45, -0.85],
       [ 2.5 , -0.85],
       [-0.5 , -0.9 ],
       [ 2.45, -0.9 ],
       [ 2.5 , -0.9 ],
       [-0.5 , -0.95],
       [ 2.5 , -0.95],
       [-0.5 , -1.  ],
       [ 2.5 , -1.  ],
       [-0.5 , -1.05],
       [-0.45, -1.05],
       [ 2.5 , -1.05],
       [-0.5 , -1.1 ],
       [-0.45, -1.1 ],
       [ 2.5 , -1.1 ],
       [ 2.55, -1.1 ],
       [-0.5 , -1.15],
       [-0.45, -1.15],
       [ 2.5 , -1.15],
       [ 2.55, -1.15],
       [-0.5 , -1.2 ],
       [-0.45, -1.2 ],
       [ 2.5 , -1.2 ],
       [ 2.55, -1.2 ],
       [-0.45, -1.25],
       [ 2.55, -1.25],
       [-0.45, -1.3 ],
       [ 2.55, -1.3 ],
       [-0.45, -1.35],
       [ 2.55, -1.35],
       [-0.45, -1.4 ],
       [ 2.55, -1.4 ],
       [-0.45, -1.45],
       [-0.4 , -1.45],
       [ 2.55, -1.45],
       [-0.45, -1.5 ],
       [-0.4 , -1.5 ],
       [ 2.6 , -1.5 ],
       [-0.45, -1.55],
       [-0.4 , -1.55],
       [ 2.6 , -1.55],
       [-0.45, -1.6 ],
       [-0.4 , -1.6 ],
       [ 2.6 , -1.6 ],
       [-0.45, -1.65],
       [-0.4 , -1.65],
       [ 2.6 , -1.65],
       [-0.45, -1.7 ],
       [-0.4 , -1.7 ],
       [ 2.6 , -1.7 ],
       [-0.4 , -1.75],
       [ 2.55, -1.75],
       [-0.4 , -1.8 ],
       [ 2.55, -1.8 ],
       [-0.45, -1.85],
       [-0.4 , -1.85],
       [ 2.55, -1.85],
       [-0.45, -1.9 ],
       [-0.4 , -1.9 ],
       [-0.4 , -1.95],
       [-0.4 , -2.  ],
       [-0.35, -2.  ],
       [-0.4 , -2.05],
       [-0.35, -2.05],
       [ 2.5 , -2.05],
       [ 2.55, -2.05],
       [-0.35, -2.1 ],
       [ 2.5 , -2.1 ],
       [ 2.55, -2.1 ],
       [-0.35, -2.15],
       [ 2.5 , -2.15],
       [ 2.55, -2.15],
       [-0.4 , -2.2 ],
       [-0.35, -2.2 ],
       [ 2.5 , -2.2 ],
       [-0.4 , -2.25],
       [-0.35, -2.25],
       [-0.35, -2.3 ],
       [ 2.45, -2.3 ],
       [-0.3 , -2.35],
       [ 2.45, -2.35],
       [-0.3 , -2.4 ],
       [-0.3 , -2.45],
       [-0.2 , -2.6 ],
       [ 2.05, -2.6 ],
       [ 2.2 , -2.6 ],
       [ 2.25, -2.6 ],
       [ 2.1 , -2.65],
       [-0.15, -2.7 ],
       [-0.05, -2.75],
       [ 0.  , -2.75],
       [ 0.05, -2.75],
       [ 0.1 , -2.75],
       [ 0.15, -2.75],
       [-0.05, -2.8 ],
       [ 0.  , -2.8 ],
       [ 0.05, -2.8 ],
       [ 0.1 , -2.8 ],
       [ 1.1 , -2.8 ],
       [ 1.15, -2.8 ],
       [ 1.2 , -2.8 ],
       [ 1.25, -2.8 ],
       [ 1.3 , -2.8 ],
       [ 1.35, -2.8 ],
       [ 1.4 , -2.8 ],
       [ 1.45, -2.8 ],
       [ 1.5 , -2.8 ],
       [ 1.55, -2.8 ],
       [ 1.6 , -2.8 ],
       [ 1.65, -2.8 ],
       [ 1.7 , -2.8 ],
       [ 1.75, -2.8 ],
       [ 1.8 , -2.8 ],
       [ 0.7 , -2.85],
       [ 0.75, -2.85],
       [ 0.8 , -2.85],
       [ 0.85, -2.85],
       [ 0.9 , -2.85],
       [ 0.95, -2.85],
       [ 1.  , -2.85],
       [ 1.05, -2.85]])

here is the visualized dataset:

points in my dataset However, these are the results I got no matter how I sort my array. sort array according to x values sort array according to y values

I pinned a few problems about my dataset but don’t know how to deal with them:

  1. Many x and y values are not one to one
  2. Points are not sorted in a neighboring order

So if my assumptions are correct, the main question would be how can I sort the array in such an order that the splprep method works? If not, I would really appreciate any solution that helps me solve the problem!

[Update] Thanks to @michael-szczesny ‘s reply I got a satisfying result solved

Advertisement

Answer

You can translate your data to the origin an sort by the complex angle.

Setup the data

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import splprep, splev

x = np.array(
      [[-0.50, -1.20],
       [-0.50, -1.15],
       [-0.50, -1.10],
       [-0.50, -1.05],
       [-0.50, -1.00],
       [-0.50, -0.95],
       [-0.50, -0.90],
       [-0.50, -0.85],
       [-0.45, -1.90],
       [-0.45, -1.85],
       [-0.45, -1.70],
       [-0.45, -1.65],
       [-0.45, -1.60],
       [-0.45, -1.55],
       [-0.45, -1.50],
       [-0.45, -1.45],
       [-0.45, -1.40],
       [-0.45, -1.35],
       [-0.45, -1.30],
       [-0.45, -1.25],
       [-0.45, -1.20],
       [-0.45, -1.15],
       [-0.45, -1.10],
       [-0.45, -1.05],
       [-0.40, -2.25],
       [-0.40, -2.20],
       [-0.40, -2.05],
       [-0.40, -2.00],
       [-0.40, -1.95],
       [-0.40, -1.90],
       [-0.40, -1.85],
       [-0.40, -1.80],
       [-0.40, -1.75],
       [-0.40, -1.70],
       [-0.40, -1.65],
       [-0.40, -1.60],
       [-0.40, -1.55],
       [-0.40, -1.50],
       [-0.40, -1.45],
       [-0.40, -0.70],
       [-0.40, -0.65],
       [-0.35, -2.30],
       [-0.35, -2.25],
       [-0.35, -2.20],
       [-0.35, -2.15],
       [-0.35, -2.10],
       [-0.35, -2.05],
       [-0.35, -2.00],
       [-0.30, -2.45],
       [-0.30, -2.40],
       [-0.30, -2.35],
       [-0.25, -0.60],
       [-0.20, -2.60],
       [-0.20, -0.60],
       [-0.15, -2.70],
       [-0.15, -0.45],
       [-0.15, -0.40],
       [-0.05, -2.80],
       [-0.05, -2.75],
       [0.00, -2.80],
       [0.00, -2.75],
       [0.00, -0.20],
       [0.00, -0.15],
       [0.00, -0.10],
       [0.05, -2.80],
       [0.05, -2.75],
       [0.05, -0.10],
       [0.10, -2.80],
       [0.10, -2.75],
       [0.15, -2.75],
       [0.30, -0.05],
       [0.35, -0.05],
       [0.40, -0.05],
       [0.45, -0.05],
       [0.50, -0.05],
       [0.55, -0.05],
       [0.60, -0.05],
       [0.65, -0.05],
       [0.70, -2.85],
       [0.70, -0.05],
       [0.75, -2.85],
       [0.75, -0.05],
       [0.80, -2.85],
       [0.80, -0.05],
       [0.85, -2.85],
       [0.85, -0.05],
       [0.90, -2.85],
       [0.90, -0.05],
       [0.95, -2.85],
       [0.95, -0.05],
       [1.00, -2.85],
       [1.00, -0.05],
       [1.05, -2.85],
       [1.05, -0.05],
       [1.10, -2.80],
       [1.10, -0.05],
       [1.15, -2.80],
       [1.15, -0.05],
       [1.20, -2.80],
       [1.20, -0.05],
       [1.25, -2.80],
       [1.25, -0.05],
       [1.30, -2.80],
       [1.30, -0.05],
       [1.35, -2.80],
       [1.35, -0.05],
       [1.40, -2.80],
       [1.40, -0.05],
       [1.45, -2.80],
       [1.45, -0.05],
       [1.50, -2.80],
       [1.50, -0.05],
       [1.55, -2.80],
       [1.55, -0.05],
       [1.60, -2.80],
       [1.60, -0.05],
       [1.65, -2.80],
       [1.65, -0.05],
       [1.70, -2.80],
       [1.70, -0.05],
       [1.75, -2.80],
       [1.75, -0.05],
       [1.80, -2.80],
       [1.80, -0.05],
       [2.05, -2.60],
       [2.10, -2.65],
       [2.10, -0.20],
       [2.10, -0.15],
       [2.15, -0.20],
       [2.15, -0.15],
       [2.20, -2.60],
       [2.20, -0.25],
       [2.20, -0.20],
       [2.25, -2.60],
       [2.35, -0.50],
       [2.35, -0.45],
       [2.35, -0.40],
       [2.35, -0.35],
       [2.40, -0.60],
       [2.40, -0.55],
       [2.40, -0.50],
       [2.40, -0.45],
       [2.45, -2.35],
       [2.45, -2.30],
       [2.45, -0.90],
       [2.45, -0.85],
       [2.45, -0.80],
       [2.45, -0.75],
       [2.45, -0.70],
       [2.45, -0.65],
       [2.45, -0.60],
       [2.50, -2.20],
       [2.50, -2.15],
       [2.50, -2.10],
       [2.50, -2.05],
       [2.50, -1.20],
       [2.50, -1.15],
       [2.50, -1.10],
       [2.50, -1.05],
       [2.50, -1.00],
       [2.50, -0.95],
       [2.50, -0.90],
       [2.50, -0.85],
       [2.50, -0.70],
       [2.55, -2.15],
       [2.55, -2.10],
       [2.55, -2.05],
       [2.55, -1.85],
       [2.55, -1.80],
       [2.55, -1.75],
       [2.55, -1.45],
       [2.55, -1.40],
       [2.55, -1.35],
       [2.55, -1.30],
       [2.55, -1.25],
       [2.55, -1.20],
       [2.55, -1.15],
       [2.55, -1.10],
       [2.60, -1.70],
       [2.60, -1.65],
       [2.60, -1.60],
       [2.60, -1.55],
       [2.60, -1.50]])

Convert your data to complex coordinates with np.angle((xs[:,0] + 1j*xs[:,1])) and use it to sort your data.

xs = (x - x.mean(0))
x_sort = xs[np.angle((xs[:,0] + 1j*xs[:,1])).argsort()]

Now you can plot(code by @rth) your data in the right order.

# plot from https://stackoverflow.com/a/31466013/14277722 as mentioned in the question
tck, u = splprep(x_sort.T, u=None, s=0.0, per=1) 
u_new = np.linspace(u.min(), u.max(), 1000)
x_new, y_new = splev(u_new, tck, der=0)

plt.figure(figsize=(10,10))
plt.plot(x_sort[:,0], x_sort[:,1], 'ro')
plt.plot(x_new, y_new, 'b--');

Out:

plot sorted data

Advertisement