3

I'm trying to write a script that clips all feature classes in fcList by the successive rows of a clip feature. I'm using arcpy with ArcGIS 10.0

The problem is that I need to verify whether the current fc of the fcList overlaps the current row of the clip rows. Here is the code (I commented the lines with my doubts, questions, remarks):

import arcpy, os 
arcpy.env.workspace = r'Z:\Documents\SIG\tests\synthese_tocorrect.gdb'
fcList = arcpy.ListFeatureClasses() #the feature class to be clipped by each of the polygon of the clip layer
pochoir = r'Z:\Documents\SIG\tests\decoupe.shp' #the clip layer with multiple polygons
rows = arcpy.SearchCursor(pochoir)
count = 0
outFolder = r'Z:\Documents\SIG\tests\sorties'
for fc in fcList:
    for row in rows:
        p = row.Shape #I'm trying to get only the geometry of the current row but I thing it's not working
        arcpy.MakeFeatureLayer_management(p,"ptmp") #...the output is empty while it should be the first polygon corresponding to the first row of the clip layer.
        arcpy.SelectLayerByLocation_management("ptmp", "INTERSECT", fc)
        arcpy.CopyFeatures_management("ptmp","ptmpselect")
        nbrow = arcpy.GetCount_management("ptmpselect")

        if nbrow > 0:
            secteur = row.secteur #The integer ID of each polygon of the clip layer
            out_poly = (outFolder, fc + "_" + str(secteur) + "_" + string(count))
            arcpy.ClipAnalysis(fc, "ptmpselect", out_poly)
            arcpy.DeleteManagement("ptmp")
            arcpy.DeleteManagement("ptmpselect")
            count = count + 1
        else:
            secteur = row.secteur # I know I repeat myself. Any idea to avoid it ? 
            out_poly = (outFolder, fc + "_" + str(secteur) + "_" + string(count))

del row, rows, pochoir, count, outFolder, fc, fcList
  • Do you mean to delete ptmp and ptmpselect and iterate the counter only if there's an overlap? If not, pull them outside of the conditional. – Erica Nov 24 '14 at 12:36
2

Creating a layer file for your clip shapefile and using selection would be how I would accomplish this task. Remember that when a geoprocessing tool is used it will only perform the process on selected features. In the below script, I first create a feature layer from the clip shapefile, to allow for selection. I then iterate through each feature class to be clipped. For each iteration, I iterate through each feature in the clip layer file. I select each feature based on OID, and then perform my clip. The output naming convention is different than in your script (out_poly variable), but you can tweak this to your liking. It has been a while since I've used the older version of the search cursor, so hopefully I got that code correct.

Code:

import arcpy, os
arcpy.env.workspace = r'Z:\Documents\SIG\tests\synthese_tocorrect.gdb'
fcList = arcpy.ListFeatureClasses() #the feature class to be clipped by each of the polygon of the clip layer
pochoir = r'Z:\Documents\SIG\tests\decoupe.shp' #the clip layer with multiple polygons
outFolder = r'Z:\Documents\SIG\tests\sorties'
fcList = arcpy.ListFeatureClasses()

arcpy.MakeFeatureLayer_management (pochoir, "pochoirlyr") #Create layer to allow for selection

OIDField = arcpy.Describe ("pochoirlyr").OIDFieldName #Get name of OID field

for fc in fcList:
    arcpy.MakeFeatureLayer_management (os.path.join (arcpy.env.workspace, fc), "lyr")
    pocursor = arcpy.SearchCursor ("pochoirlyr")
    for porow in pocursor:
        sql = '"' + OIDField + '" = ' + str (row.getValue(OIDField)) #SQL to select one feature
        arcpy.SelectLayerByAttribute_management ("pochoirlyr", "", sql) #Select polygon feature by OID
        arcpy.SelectLayerByLocation_management ("lyr", "", "pochoirlyr") #Select feature layer to be clipped by selected clip feature 
        if arcpy.Describe ("lyr").FIDSet: #Check for selection
            out_poly = (outFolder, fc + "_" + str (row.getValue(OIDField))) #Output feature class
            arcpy.ClipAnalysis(fc, "pochoirlyr", out_poly)
    del porow
    del pocursor
    arcpy.Delete_management ("lyr")
    arcpy.SelectLayerByAttribute_management ("pochoirlyr", "CLEAR_SELECTION")

I hope this helps!

EDIT: Edited so that clip is only performed if features overlap.

  • Hi, and thank you for the tips, it works well. Know, only intersecting layers are clip as I wanted. But the script stops after the first feature class processing without error. I used try: / except: but no error were recorded. Strange. – Samy-DT Nov 26 '14 at 11:34
  • Ohhh shoot, my code is wrong! The code only works once, because once a selection is performed, the proceeding cursors only occur on the one selected clip feature. Updated with a "CLEAR_SELECTION" to rectify this. Try it now. Note: If you don't get an error outright when running a script, adding a try/except will not add any new information, as far as I am aware. – Emil Brundage Nov 26 '14 at 16:21
  • Thanks a lot, it works well! I just add the removal of the temp "lyr" after the clearing of the selection for allow to its renew for the next fc ;). – Samy-DT Nov 27 '14 at 9:51
  • I'm glad to help. I've added the delete to my answer. – Emil Brundage Nov 27 '14 at 16:39
  • this script which was working well is now unusable without changing anything. I have a new error alert "porow is not defined". I don't understand because it seems well defined in python synthax and was working 2 days ago...Any idea ? – Samy-DT Dec 15 '14 at 13:48
5
# I know I repeat myself. Any idea to avoid it ?

Move secteur = row.secteur outside the if/else statements (before if nbrow > 0:).


Move rows = arcpy.SearchCursor(pochoir) inside the for loop (after for fc in fcList:)


I think that you aren't accessing the geometry properly. Reference Reading Geometries and Working with geometry in Python.

# tells you the shapeFieldName of pochoir
shapeName = arcpy.Describe(pochoir).shapeFieldName

# actually stores the geometry somewhere
p = row.getValue(shapeName)

Alternatively, don't mess with the geometry. Make a feature layer for each row by including a where_clause to select only that row from the original feature class.

for row in rows:
    id = row.secteur
    where_clause = "secteur = '{}'".format(id)
    arcpy.MakeFeatureLayer_management(pochoir, "ptmp", where_clause)

You aren't actually counting the rows yet. The GetCount_management function needs a couple steps to get the row count as a numeric value.

result = arcpy.GetCount_management("ptmpselect")
nbrow= int(result.getOutput(0))

if nbrow > 0: ...

or just the following (although for beginners I recommend keeping things more spread out, like above):

result = arcpy.GetCount_management("ptmpselect")

if int(result.getOutput(0)) > 0: ...

For improved readability, I'd suggest:

outName = "{0}_{1}_{2}".format(fc, secteur, count)

and then use outName instead of fc + "_" + str(secteur) + "_" + string(count) twice.

  • Hello Erica and thank you very much for the useful informations. Anyway I modified my script whith your suggestions but I had a first problem with the format of the where clause. According to this link : stackoverflow.com/questions/5446964/…, one have to specify the value between the {} so I fixed it by doing {0} without really understanding how the query works. The second issue is an error message concerning the feature layer. So I thing there is still an issue with the where_clause that I can't figure out. – Samy-DT Nov 24 '14 at 14:46
  • @Samy-DT The value needs to be specified between the brackets {} in Python 2.7 or later; I thought Arc 10.0 came with 2.7, but looks like it was 2.65 (sorry!). Try arcpy.MakeFeatureLayer_management(pochoir, "ptmp", where_clause) (using the full feature class pochoir instead of the row). – Erica Nov 24 '14 at 14:52
  • okey, I'll try this. And is it possible to have a little explanation about what is expected inside the {}. Should I write any value with the expected type ? For example, for outName = "{nameofanyfc}_{anynumberofsecteurfield}_{anyinteger}".format(fc, secteur, count)). Thanks a lot for support – Samy-DT Nov 24 '14 at 15:19
  • The value in the brackets is the index of what comes after -- so outName = "{0}_{1}_{2}".format(fc, secteur, count) – Erica Nov 24 '14 at 15:57
  • Ok well understood for format. I made a few try this morning and I know I'm about to get what I want but there is still an issue with getting the count of the row. nbrow = int(result.getOutput(0)) return an error message : no result attribute. Can you explain a little further the role and meaning of this line ? Thanks for support – Samy-DT Nov 25 '14 at 10:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.