How to generate a Point or PointGeometry from a da.SearchCurser that can be used as an input Point in queryPointAndDistance()

2837
5
Jump to solution
11-17-2017 11:50 AM
AlexanderAudet
New Contributor III

My question involves handling data types, particularly of strings, points and tuples. I start with a single object (I think I can say feature object as it has geometry on top of other attributes) selected by location in a feature layer. I then try to access a point geometry from that object using the SHAPE@TRUECENTROID token within a arcpy.da.SearchCurser() method and set that Point Geometry equal to a variable. I then call that variable within the queryPointAndDistance() function as my input Point or PointGeometry, but Arcpy gives me the following at the end of the error message error. 

File "<expression>", line 1, in <module>   File "<string>", line 22, in Strike ValueError: (612744.9906049052, 3417217.9973794315)

It appear that it does not recognize my function as either a Point or PointGeometry. Where does the output from the curser function become something different (a different type perhaps)? 

This post python - ArcPy QueryPointAndDistance: Incorrect Lengths? - Stack Overflow  suggested to me that by setting a variable equal to a SearchCurser, that variable would equal the geometry object specified. Is there any difference between the logic used there when the he gets the line geometry and what I am doing that I did not catch? 

The problematic part of the code is as follows:

If it helps answer the question, this script is within a def in the codeblock of a CalculateField_management() method so 'shape' = the geometry of the record being calculated, and PairedCheck6 is my feature layer with one selected record. 

codeblock = """def Strike(shape, seed, fid):

        # PairedCheck6 = feature layer with single selection

        cursorResult = arcpy.da.SearchCursor('PairedCheck6','SHAPE@TRUECENTROID').next()[0]
        centroid = None

        if len(cursorResult) > 0:
            centroid = cursorResult
        else:
            return '5000'
        (pointGeometry, distance, minDistance, isCentroidRight) = shape.queryPointAndDistance( centroid, False)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍"""‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 I can show more of the code if requested, but I did not want to ask anyone to look through more than is required. 

0 Kudos
1 Solution

Accepted Solutions
JoshuaBixby
MVP Esteemed Contributor

This is a datatype issue.  According to SearchCursor—Help | ArcGIS Desktop :

  • SHAPE@TRUECENTROID —A tuple of the feature's true centroid x,y coordinates.

The token you are using with the Search Cursor isn't returning a geometry, it is returning a Python tuple.  You will need to turn that Python tuple of coordinates into a PointGeometry—Help | ArcGIS Desktop .  Something along the lines of:

SR = # arcpy spatial reference object
ptg = PointGeometry(arcpy.Point(*centroid), SR)‍‍

View solution in original post

5 Replies
JoshuaBixby
MVP Esteemed Contributor

This is a datatype issue.  According to SearchCursor—Help | ArcGIS Desktop :

  • SHAPE@TRUECENTROID —A tuple of the feature's true centroid x,y coordinates.

The token you are using with the Search Cursor isn't returning a geometry, it is returning a Python tuple.  You will need to turn that Python tuple of coordinates into a PointGeometry—Help | ArcGIS Desktop .  Something along the lines of:

SR = # arcpy spatial reference object
ptg = PointGeometry(arcpy.Point(*centroid), SR)‍‍
DanPatterson_Retired
MVP Emeritus

simple point* geometries can also be more readily obtained using 

SHAPE@XY etc http://desktop.arcgis.com/en/arcmap/latest/analyze/python/writing-geometries.htm

or even SHAPE@X and ...@Y as well.  For point objects, obviously it shouldn't matter which you use, but what is returned depends depends on how you call it

flds = ['OBJECTID', 'SHAPE@TRUECENTROID']
args = [in_fc, flds, None, None, False, (None, None)]
cur = arcpy.da.SearchCursor(*args)
a = cur._as_narray()
a[0]
(1, [340005.73319999967, 5024293.363399999])


flds = ['OBJECTID', 'SHAPE@X', 'SHAPE@Y']
args = [in_fc, flds, None, None, False, (None, None)]
cur = arcpy.da.SearchCursor(*args)
a = cur._as_narray()
a[0]
(1, 340005.73319999967, 5024293.363399999)
AlexanderAudet
New Contributor III

I thought that I might have fixed it for a moment. You can put either a point or a PointGeometry into into the queryPointAndDistance(in_point) according to PointGeometry—ArcPy Classes | ArcGIS Desktop. However, when I create either one, it gives the ValueError message for my point/PointGeometry.

        cursorResult = arcpy.da.SearchCursor('PairedCheck6','SHAPE@TRUECENTROID').next()[0]
        centroid = None

        if len(cursorResult) > 0:
            centroid = cursorResult
            ptg = arcpy.Point(*centroid)
        else:
            return '5000'
        (pointGeometry, distance, minDistance, isCentroidRight) = shape.queryPointAndDistance( ptg, False)

Traceback (most recent call last):   File "<expression>", line 1, in <module>   File "<string>", line 23, in Strike ValueError: <Point (612744.990605, 3417217.99738, #, #)>  Failed to execute (CalculateField).

This is the entire error code, although I think that the above is the important part. 

Runtime error Traceback (most recent call last): File "<string>", line 49, in <module> File "c:\program files (x86)\arcgis\desktop10.4\arcpy\arcpy\management.py", line 3360, in CalculateField raise e ExecuteError: ERROR 000539: Error running expression: Strike( GPVARIANTOBJECT0, 124, 1 ) Traceback (most recent call last): File "<expression>", line 1, in <module> File "<string>", line 23, in Strike ValueError: <Point (612744.990605, 3417217.99738, #, #)> Failed to execute (CalculateField).

        cursorResult = arcpy.da.SearchCursor('PairedCheck6','SHAPE@TRUECENTROID').next()[0]
        centroid = None
        
        if len(cursorResult) > 0:
            centroid = cursorResult
            inTable = # My shapefile
            spatialRef = arcpy.Describe(inTable).spatialReference
            ptg = arcpy.PointGeometry(arcpy.Point(*centroid), spatialRef)
        else:
            return '5000'
        (pointGeometry, distance, minDistance, isCentroidRight) = shape.queryPointAndDistance( ptg, False)

Traceback (most recent call last):   File "<expression>", line 1, in <module>   File "<string>", line 26, in Strike ValueError: <PointGeometry object at 0xedb99b0[0xedb9140]>  Failed to execute (CalculateField).

I am wondering if there is something wrong with the original spatial reference of my data, as when I had originally found the reference by describing my feature class. 

inTable = #my shapefile 
spatialRef = arcpy.Describe(inTable).spatialReference

# Print the spatial reference name
print spatialRef.name

# returns: unnamed‍‍‍‍‍‍‍‍

However, this might be getting beyond the scope of my original question as it is no longer about how to make my input a Point, but why my input point does not work. 

0 Kudos
DanPatterson_Retired
MVP Emeritus

you should always define the coordinate system before working with geometries.  If you know what it is, use the define project tool then retry.  Unknown is not the same as None.  If you don't use a defined SR, then geometry values will be in error... minor, but there is no record of the geoprocessing engine having been fixed (unless someone wants to point me to the official documentation)

AlexanderAudet
New Contributor III

Turns out it was the shape in the 

shape.queryPointAndDistance(ptg, False)

that was wrong. I had to make a new geometry object by selecting the record and putting it into a FeatureLayer ( MakeFeatureLayer_management() ), then copy that record as a geomentry object using ( CopyFeatures_management() ). I then had to select that one object to take it out of the array (I think) so that I ended up with shapeG as my polyline geometry.

codeblock = """def Strike(shape, seed, fid):
        arcpy.MakeFeatureLayer_management("my shapefile", 'shapelyr', '"FID" ='+str(fid))

        g = arcpy.Geometry()  
        geometryList = arcpy.CopyFeatures_management('shapelyr', g)  
        shapeG = geometryList[0]

        cursorResult = arcpy.da.SearchCursor('PairedCheck6','SHAPE@TRUECENTROID').next()[0]
        centroid = None

        if len(cursorResult) > 0:
            centroid = cursorResult

            ptg = arcpy.Point(*centroid)

        else:
            return '5000'

        (pointGeometry, distance, minDistance, isCentroidRight) = shapeG.queryPointAndDistance( ptg, False)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Not sure whose answer I should mark as correct now. 

0 Kudos