I wrote this code to remove points that create a straight line when plotted.
For instance, this has many points in a straight line:
import matplotlib.pyplot as plt import numpy as np pattern = np.array( [ 9, 10, 11, 10, 9, 8, 6, 5, 4, 3, 4, 5, 7, 6, 5, 4, 2, 1, 2, 3, 4, 5, 7, 8, 9, 10, 8, 7, 8, 9, 10, 11, 10, 11, 12, 13, 12, 11, 10, 8, 7, 6, 5, 4, 6, 5, 3, 2, 3, 2, 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 21, 19, 18, 16, 15, 14, 12, 11, 12, 11, 10, 11, 12, 13, 14, 15, 13, 12, 11, 10, 9, 8, 7, 6, 5, 6, 5, 4, 6]) plt.plot(pattern) plt.plot(pattern, 'bo') plt.show()
Using the degrees
function I can remove any lines that create an angle of
180deg between the two neighboring points.
from numpy.lib.stride_tricks import as_strided
def moving_slice(a, k):
a = a.ravel()
return as_strided(a, (a.size - k + 1, k), 2 * a.strides)
def degrees(x, y):
x_window, y_window = moving_slice(x, 3), moving_slice(y, 3)
x_window = np.concatenate((x_window, x_window[:, None, 0]), axis=1)
y_window = np.concatenate((y_window, y_window[:, None, 0]), axis=1)
triangle_sides = np.sqrt(np.square(np.diff(x_window)) + np.square(np.diff(y_window)))
squared_sides = np.square(triangle_sides)
cos_num = np.sum(squared_sides[:, :2], axis=1) - squared_sides[:, 2]
cos_den = 2 * np.prod(triangle_sides[:, :2], axis=1)
return np.degrees(np.arccos(cos_num / cos_den))
This is what I'm trying to achieve:
# My review function
angles = degrees(np.arange(len(pattern)), pattern)
pattern = pattern[1:-1] # <- No angles between the end points
less_than_180 = angles < 180
plt.plot(pattern[less_than_180])
plt.plot(pattern[less_than_180], 'bo')
plt.show()
You can see that it's pretty good. Missed a few points to remove (due to decimal accuracy) but otherwise the function does what I want. I'd like to know if there is a simpler way to achieve the desired result without calculating all the angles. What do you think?
x
will always be consecutive integers. So that would work also. \$\endgroup\$