The crossing points or intersection indices between two series a
and b
are the indices i
where:
- either (ai < bi and ai+1 > bi+1) (
b
crosses a
from above)
- or (ai > bi and ai+1 < bi+1) (
b
crosses a
from below)
- or ai = bi (
a
and b
touch)
So we can get the indices by comparing the 'current' (i-th) and 'next' (i+1-th) values of each array.
def intersection_points(a, *others):
if a.ndim != 1 or any(other.shape != a.shape for other in others):
raise ValueError('The arrays must be single dimensional and the same length')
others = np.array(others)
indices = np.argwhere(
((a[:-1] < others[..., :-1]) & (a[1:] > others[..., 1:])) |
((a[:-1] > others[..., :-1]) & (a[1:] < others[..., 1:])) |
(a[:-1] == others[..., :-1]))
return indices[indices[:, 1].argsort()] # sort by i
a = np.array([9887.89, 9902.99, 9902.99, 9910.23, 9920.79, 9911.34, 9920.01, 9927.51, 9932.3, 9932.33, 9928.87, 9929.22, 9929.22, 9935.24, 9935.24, 9935.26, 9935.26, 9935.68, 9935.68, 9940.5])
b = np.array([9935.26, 9935.26, 9935.68, 9935.68, 9940.5, 9925.19, 9925.19, 9929.62, 9929.65, 9929.93, 9932.55, 9936.81, 9936.84, 9937.26, 9932.55, 9932.55, 9932.55, 9932.6, 9932.6, 9932.6])
c = np.array([9928.87, 9929.22, 9929.22, 9935.24, 9935.24, 9935.26, 9935.26, 9935.68, 9935.68, 9940.5, 9925.19, 9925.19, 9929.62, 9929.65, 9929.93, 9932.55, 9936.81, 9936.84, 9937.26, 9932.55])
print(intersection_points(a, b, c))
This returns an array of intersection points in this format:
[[ 0 7]
[ 0 9]
[ 1 9]
[ 1 11]
[ 1 12]
[ 0 13]
[ 1 15]
[ 1 18]]
meaning that b
(your list_2
) intersects with a
at indices 7, 9, 13, and c
(your list_3
) intersects with a
at indices 9, 11, 12, 15 and 18.
You seem to want the returned value to somehow alternate between intersections of the different lines and 'wait for the other array values to cross the list before it can go through'. It's not entirely clear what this would mean in every case but you can possibly do this by manipulating the result like this:
ip = intersection_points(a, b, c)
print(np.concatenate(([ip[0]], ip[1:][ip[:-1, 0] != ip[1:, 0]])))
returning
[[ 0, 7],
[ 1, 9],
[ 0, 13],
[ 1, 15]]
i.e. the first crossing is of b
at index 7, then c
at 9, then b
at 13, and finally c
at 15.