3

I want to slice an array of [x,y] coordinate pairs by x value in Python 3.x, in a similar way to the solution to this question but with coordinates rather than a 1d list.

For example for the (numpy) array of coordinates I want a function like:

coords = np.array([[1.5,10],[2.5,20],[3.5,30],[4.5,40],[5.5,50]])
def slice_coords_by_x(xmin, xmax, arr):
    *some function*
slice_coords_by_x(2, 4, arr)
>>>[[2.5,20],[3.5,30]]

Not overly fussy if the solution is inclusive or exclusive of xmin and xmax since i'll be using this over a large range of over 1000 or so.

1
  • So you basically want to filter? Is it guaranteed that the x coordinates are ordered? Commented Jan 16, 2017 at 20:36

4 Answers 4

2

Slice and create a mask with such min-max limits and thus select rows with boolean-indexing -

def slice_coords_by_x(arr, xmin, xmax):
    return arr[(arr[:,0] >= xmin) & (arr[:,0] <= xmax)] 

Sample runs -

In [43]: arr
Out[43]: 
array([[  1.5,  10. ],
       [  2.5,  20. ],
       [  3.5,  30. ],
       [  4.5,  40. ],
       [  5.5,  50. ]])

In [44]: slice_coords_by_x(arr, xmin=2, xmax=4)
Out[44]: 
array([[  2.5,  20. ],
       [  3.5,  30. ]])

In [45]: slice_coords_by_x(arr, xmin=1, xmax=5)
Out[45]: 
array([[  1.5,  10. ],
       [  2.5,  20. ],
       [  3.5,  30. ],
       [  4.5,  40. ]])
Sign up to request clarification or add additional context in comments.

1 Comment

Appreciated all the answers thanks all- chose this one purely because it doesn't depend on another package and it retains the numpy array type over Python's own array
2

Without numpy, you could use bisect for this, to find insertion point. Note that the parameter is a list (I was adding None as second parameter as seen in here, but it's not useful).

import bisect

coords = [[1.5,10],[2.5,20],[3.5,30],[4.5,40],[5.5,50]]

def slice_coords_by_x(lower,upper,arr):
    l=bisect.bisect_left(arr,[lower])
    u=bisect.bisect_right(arr,[upper])
    return arr[l:u]

print(slice_coords_by_x(2,4,coords))

result:

[[2.5, 20], [3.5, 30]]

bisect requires that the list is sorted (which seems to be the case) or that won't work.

7 Comments

Can't you simply use [lower] instead of [lower,None]? At least for bisect_left?
nope: TypeError: unorderable types: list() < int()
but [lower] is still a list.
given I query bisect.bisect_left(arr,[2.5,None]), I get TypeError: unorderable types: int() < NoneType()... With arr the one defined above.
Funny. So the answer I linked to telling to put None is just wrong. Wait: it must be python 2 only, as you were able to compare strings with ints, etc... not anymore in python 3.
|
2

Unordered

If the given list of points are unordered, you can use a filter, and materialize with list:

def slice_coords_by_x(xmin,xmax,arr):
    return list(filter(lambda p: xmin < p[0] < xmax,arr))

You can evidently feed your sorted list to this as well, but it will take considerably more time than the next approach.

Sorted list

Given the points are sorted by x-coordinate, you can use the bisect package:

def slice_coords_by_x(xmin,xmax,arr):
    left = bisect.bisect_left(arr,[xmin])
    right = bisect.bisect_right(arr,[xmax])
    return arr[left:right]

Comments

2

Shouldn't simply

def slice_coords_by_x(xmin, xmax, arr):
    return [i for i in arr if xmin <= i[0] and i[0] <= xmax]

do the trick? It's readable, fast and accessible.

This list can be sorted or even pass an array, but the approach should be accessible enough to be changed to any needs.

6 Comments

if xmin <= i[0] and i[0] <= xmax => if xmin <= i[0] <= xmax is even better. Willem answer already covers that, though.
if xmin <= i[0] and i[0] <= xmax and if xmin <= i[0] <= xmax are actually one and the same thing.
probably, but the latter is more "pythonic".
Also I am not sure, that Willems answer is any kind of superior to mine. So why shouldn't I write a way easier to read and understand? PS.: I wrote the answer before Willem, I actually typed it as a comment before, deleted it, reformated it and saved it and I didn't saw Willems answer before.
You have to be more aggressive when answering ;)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.