extract non-incremental rows from numpy array

2932
7
Jump to solution
01-12-2016 01:37 PM
Bartvan_der_Wolf
New Contributor II

Here's my problem, hope anybody can get me on the way...

I need to remove the "caps" of long polygon(road) features. The caps are created by boundary lines. Each line can slice the same polygon multiple times. After converting the line to points I'm able to select the points touching the polygon. But the selection can contain multiple start-end-points for each slice.

incremental_ID.jpg

Here's the array of selected points.

[

(6, [163320.90700000152, 379580.6550000012])

(7, [163320.90900000185, 379580.34699999914])

(8, [163320.92320000008, 379577.6838000007])

(9, [163320.941300001, 379574.2791999988])

(10, [163320.95899999887, 379570.9439999983])

(11, [163320.97700000182, 379567.63800000027])

(12, [163320.98000000045, 379567.12000000104])

(27, [163321.24599999934, 379517.67599999905])

(28, [163321.26900000125, 379513.493999999])

(29, [163321.28799999878, 379509.9620000012])

(30, [163321.3040000014, 379506.8920000009])

]

And this is my goal output-array. I need these corners!

[

(6, [163320.90700000152, 379580.6550000012])

(12, [163320.98000000045, 379567.12000000104])

(27, [163321.24599999934, 379517.67599999905])

(30, [163321.3040000014, 379506.8920000009])

]

At first I tried to use the searchcursor, but i was unable to identify the next-id in a loop to see if it's ID is just+1. So my thought is to use the numpy array, but i'm still on the ground...

How do I loop this numpy array or mayby use some smart numpy function to remove unwanted rows from the array?

This is the code that created the array:

tmppt_lay = arcpy.MakeFeatureLayer_management(tmppt, "tmppoints_lay", "", "", "OBJECTID OBJECTID VISIBLE NONE;SHAPE SHAPE VISIBLE NONE;ORIG_FID ORIG_FID VISIBLE NONE")

tmppt_sel = arcpy.SelectLayerByLocation_management(tmppt_lay, "INTERSECT", bit2, "0,02 Meters", "NEW_SELECTION")

#now loop these selected points and identify future split-points

srows = arcpy.SearchCursor(tmppt_sel)

sdesc = arcpy.Describe(tmppt_sel)

selectionCount = len(sdesc.fidset.split(";"))

arcpy.AddMessage("  selected points: " + str( selectionCount))

#for srow in srows:

       #got stuck here!

#try the numpy way..

sArr = arcpy.da.FeatureClassToNumPyArray (tmppt_sel, ["OID@","SHAPE@XY"], "#", rd)

oArr = arcpy.Array()

cnt = 0

for oi, xy in sArr:

           if cnt==0:      #this is always the startpoint

               arcpy.AddMessage("start point in: " + str(loid) + ":   id: " + str(oi) + ", " +  str(xy))

           elif (cnt==selectionCount-1):     #this is always the endpoint

               arcpy.AddMessage("end point in: " + str(loid) + ":   id: " + str(oi) + ", " +  str(xy))

           else:   #here i need to findout if the next point has an ID 1 larger thn the current

              arcpy.AddMessage("counter + 1: " + str(int(cnt+1)))

              nextcnt = cnt+1

              nextrow = sArr[nextcnt])   # this does NOT work

              #nextid = nextrow[0]

              #arcpy.AddMessage("nextid: " + str(nextid))

           cnt+=1

Het bericht is bewerkt door: Bart van der Wolf Added a loop for the array, but stuck on the same point as with using the searchcursor.

0 Kudos
1 Solution

Accepted Solutions
DanPatterson_Retired
MVP Emeritus

or this

>>> a = np.array([0,1,2,3,4,7,8,9,10,15,16, 19,20])
>>> b = np.where(a[1:]-a[:-1] > 1)
>>> b
(array([ 4,  8, 10]),)

but since you are using recarrays it will probably be

b = np.where(a['ID'][1:] - a['ID'][:-1] > 1 ) 

where 'ID' is the name of the first field (could be OID... check with a.dtype where a is your array

View solution in original post

7 Replies
DanPatterson_Retired
MVP Emeritus

A sample recarray to demo.  You just need to slice

My sample array

>>> rec
    ||(0, |6.0, 0.0|, u'a', 10)|
    |(1, |7.0, 9.0|, u'c', 1)|
    |(2, |8.0, 6.0|, u'b', 2)|
    |(3, |3.0, 2.0|, u'a', 5)|
    |(4, |6.0, 0.0|, u'a', 5)|
    |(5, |2.0, 5.0|, u'b', 2)|
    |(6, |3.0, 2.0|, u'a', 10)|
    |(7, |8.0, 6.0|, u'b', 2)|
    |(8, |7.0, 10.0|, u'c', 1)|
    |(9, |6.0, 0.0|, u'a', 10)||

>>> a = rec[[0,3,6,9]]
>>> a
rec.array([(0, [6.0, 0.0], u'a', 10), (3, [3.0, 2.0], u'a', 5),
      (6, [3.0, 2.0], u'a', 10), (9, [6.0, 0.0], u'a', 10)],
      dtype=[('ID', '<i4'), ('XY', '<f8', (2,)), ('Class', '<U4'), ('Count', '<i4')])
>>> a.reshape((-1,1))
rec.array([[(0, [6.0, 0.0], u'a', 10)],
      [(3, [3.0, 2.0], u'a', 5)],
      [(6, [3.0, 2.0], u'a', 10)],
      [(9, [6.0, 0.0], u'a', 10)]],
      dtype=[('ID', '<i4'), ('XY', '<f8', (2,)), ('Class', '<U4'), ('Count', '<i4')])

>>>

Bartvan_der_Wolf
New Contributor II

Hi Dan,

Thanks for your reaction. I think I understand what youre showing me. I see I can just grab the proper rows from the array when i identified them. But how do I extract the ID from the next element in the array when looping?

0 Kudos
Bartvan_der_Wolf
New Contributor II

I got it! I was just not using proper syntax on the array. This works.

        sArr = arcpy.da.FeatureClassToNumPyArray (tmppt_sel, ["OID@","SHAPE@XY"], "#", rd)

        oArr = arcpy.Array()

        cnt = 0

        for oi, xy in sArr:

           if cnt==0:

              arcpy.AddMessage("start point in: " + str(loid) + ":  id: " + str(oi) + ", " +  str(xy))

           elif (cnt==selectionCount-1):

              arcpy.AddMessage("end point in: " + str(loid) + ":  id: " + str(oi) + ", " +  str(xy))

           else:  

              arcpy.AddMessage("thisID: " + str(oi)+  " nextid: " + str(sArr[cnt+1][0]))

           cnt+=1

produces:

thisID: 7 nextid: 8

thisID: 8 nextid: 9

thisID: 9 nextid: 10

thisID: 10 nextid: 11

thisID: 11 nextid: 12

thisID: 12 nextid: 27

thisID: 27 nextid: 28

thisID: 28 nextid: 29

thisID: 29 nextid: 30

Now I can identify the proper points.

0 Kudos
DarrenWiens2
MVP Honored Contributor

Glad you got it to work. You can also do it looking backwards (probably can use some refinement):

>>> my_array = [6,7,8,9,10,11,12,27,28,29,30]
... one_back = 0
... out_array = []
... for current in my_array:
...    if current <> one_back + 1:
...        out_array.append(one_back)
...        out_array.append(current)
...    one_back = current
... out_array.remove(0)
... out_array.append(one_back)
... print out_array
...
[6, 12, 27, 30]
Bartvan_der_Wolf
New Contributor II

Nice Thanks!

0 Kudos
DanPatterson_Retired
MVP Emeritus

or this

>>> a = np.array([0,1,2,3,4,7,8,9,10,15,16, 19,20])
>>> b = np.where(a[1:]-a[:-1] > 1)
>>> b
(array([ 4,  8, 10]),)

but since you are using recarrays it will probably be

b = np.where(a['ID'][1:] - a['ID'][:-1] > 1 ) 

where 'ID' is the name of the first field (could be OID... check with a.dtype where a is your array

Bartvan_der_Wolf
New Contributor II

Thanks Dan, now I'm off!

0 Kudos