Loop through selected features, works in Model Builder, but not in Python

20091
9
08-14-2011 01:33 AM
RomySchroeder
New Contributor
Hi,

I have problems to get a loop for selected features running in Python. I built a workflow in Model Builder and exported the script to python. But in Python I get an error message if I try to run it. It says: Python cannot open a toolbox... I get the feeling that the function "iterateFeatureSelection_mb" does not work in py. I could not find it in the Desktop Help, too.
Could someone have a look on this. I am new to Python and don´t know how to write this as a loop.
Thank you!
Posted the code below and attached the model from Model Builder as an image.

import arcpy
# Load required toolboxes
arcpy.ImportToolbox("Model Functions")

# Local variables:
Solarpot_PotsdamPVend = "Solarpot_PotsdamPVend"
DSM_inside_PV_Punkt = "D:\\UniGIS\\MT\\Daten\\Bearbeitung\\MT_Scratch.gdb\\DSM_inside_PV_Punkt"
Geb_Geb_ID = "I_Solarpot_PotsdamPVend"
Punkt_inGeb__Geb_ID_ = "D:\\UniGIS\\MT\\Daten\\Bearbeitung\\MT_scratch.gdb\\Punkt_inGeb_%Geb_ID%"

# Process: Iterate Feature Selection
arcpy.IterateFeatureSelection_mb(Solarpot_PotsdamPVend, "", "false")
# Process: Clip
arcpy.Clip_analysis(DSM_inside_PV_Punkt, Geb_Geb_ID, Punkt_inGeb__Geb_ID_, "")
Tags (2)
0 Kudos
9 Replies
StacyRendall1
Occasional Contributor III
Yeah, the export to Python thing is rubbish... The reason you get the error is that 'Model Functions' is not something Python can import, and I think Iterate Feature Selection is part of that toolbox that cannot be imported (the _mb implies it is part of the Model Builder tools). Iteration in Python is done with a for loop. For example:
for x in range(4):
    print(x)

would output:
0
1
2
3
>>>


Python can also iterate over structures called Lists (documentation), which are represented by items within square brackets, i.e. [1,2,3].

If you use the arcpy functions like ListFeatureClasses it will make a list of the feature classes in the dataset, so you could do something like:
FCs = arcpy.ListFeatureClasses('C:\\Data\\Data1.gdb')
for FC in FCs:
    arcpy.AddMessage('Opened:'+FC)


It looks like you are iterating over a feature selection, but not selecting any features - was that to iterate over all the features? If so, you can use the Arcpy Search Cursor to do this (read the docs).

If you are making a selection in a previous tool and that is an input, just be warned that it may not be honoured by the Python script...
0 Kudos
RomySchroeder
New Contributor
Hi Stacy,

thank you for the helpful information and examples. I´d like to run the loop for an existing selection of features, that means as a first step the user interactively defines the features that should be further analyzed by my script. Then a loop process should run for every selected feature.

I tried to work with an interactive user selection and used the "Feature Set" Tool for this, but it does not work the way I want. I have a layer with lots of houses and one layer with DTM points and I´d like to clip DTM points inside the selection and write them into different files named after the ID of the selected house (I use %ID_house% for this). As a result I should get files with the house ID as name and a bunch of points that lay inside this house. But "feature set" only gives me the points inside the interactively digitized polygons and not the whole house... So my workaround is to make the user do a selection with the ArcMap selection tool first and then run my tool... (please see my Thread here:

But you pointed out that Python may ignore this previous selection. What can I do instead?

Romy
0 Kudos
LoganPugh
Occasional Contributor III
Most geoprocessing tools, if run from within ArcMap, operate on the selected set of features by default if the input is a feature layer with an active selection. I don't think Feature Set is the right parameter type in this situation, so try Feature Layer.

I would probably use Make Feature Layer first to capture the set of selected features and then iterate over the features in the created layer using a search cursor.

In your loop:

  1. Use select by location with the points layer as the input layer and the shape (geometry object) of the current house as the selecting layer.

  2. Use Copy Features, which operates on the selected set of features, to save the selected points to their own feature class, using the house number attribute to appropriately name each feature class


example script:
## Parameters:
## 0 (input) - Input Features (Feature Layer)
## 1 (input) - Selecting Features (Feature Layer)
## 2 (input) - Selecting Features Field (Field, obtained from Selecting Features)
## 3 (input) - Output Workspace (Workspace)
## 4 (output, derived) - Output Feature Class(es) (Feature Class, multivalue)

import arcpy, os
from arcpy import env

env.overwriteOutput = True

inputFeatures = arcpy.GetParameterAsText(0)
selectingFeatures = arcpy.GetParameterAsText(1)
selectingFeaturesFieldName = arcpy.GetParameterAsText(2)
outputWorkspace = arcpy.GetParameterAsText(3)

env.workspace = outputWorkspace
arcpy.AddMessage("Current workspace: %s" % outputWorkspace)

inputLayer = arcpy.MakeFeatureLayer_management(inputFeatures)
selectingLayer = arcpy.MakeFeatureLayer_management(selectingFeatures)

desc = arcpy.Describe(inputLayer)
inputLayerName = desc.name

desc = arcpy.Describe(selectingLayer)
selectingLayerName = desc.name
selectingLayerShapeFieldName = desc.featureClass.shapeFieldName

outputFCs = []
rows = arcpy.SearchCursor(selectingLayer)
for row in rows:
    arcpy.management.SelectLayerByLocation(inputLayer, "HAVE_THEIR_CENTER_IN", row.getValue(selectingLayerShapeFieldName), "", "NEW_SELECTION")
    count = int((arcpy.GetCount_management(inputLayer))[0])
    rowValue = str(row.getValue(selectingFeaturesFieldName))
    arcpy.AddMessage("%d feature(s) of layer %s found in layer %s (%s: %s)" % (count, inputLayerName, selectingLayerName, selectingFeaturesFieldName, rowValue))
    if (count > 0):
        outputFC = inputLayerName + "_" + rowValue
        arcpy.AddMessage("Copying selected feature(s) to %s" % outputFC)
        arcpy.CopyFeatures_management(inputLayer, outputFC)
        outputFCs.append(outputFC)
del row, rows
arcpy.SetParameterAsText(4, ";".join(outputFCs))
0 Kudos
RomySchroeder
New Contributor
Thank you for your advice and the sample code. The hint with Feature Layer sounds promising. I´ll try to implement that in my code, but won´t be able to do that until tomorrow.

I´ll give a short response if the script runs.

Thank you very much!
Romy
0 Kudos
RomySchroeder
New Contributor
Hi,

today I tried to get the cript running and it does. Unfortunately it copies all features into the input layer and then loops over all 4000 objects and not only the selected houses.

I think it has something to do with how I implemented the script in ArcMap. I went to own_toolbox and added the new script. In the script´s Parameters I just added the Selecting Features Layer as a Parameter (Parameter #1 in your script example) but I am not sure wich data type I should select (I used Feature Class) and wich parameter properties to use. All other parameters were set in the script (with full pathnames).

If I run the script now, the user is prompted to put in the path of the selecting Features Layer... and I think the previous selection made in ArcMap is not even considered...

Can you help me with the correct setup?
Thank you,
Romy
0 Kudos
LoganPugh
Occasional Contributor III
Use Feature Layer, not Feature Class. See the comments at the top of my example script.
0 Kudos
RomySchroeder
New Contributor
Use Feature Layer, not Feature Class. See the comments at the top of my example script.


Oh, thanks, I could not see the wood for the trees. The scrips works fine now.

I have only two questions left concerning the following lines of python code:

outputFCs = [] # is this the indication that the new variable outputFCs contains a list of values?
rows = arcpy.SearchCursor(selectingLayer)
for row in rows:
arcpy.management.SelectLayerByLocation(inputLayer, "HAVE_THEIR_CENTER_IN", row.getValue(selectingLayerShapeFieldName), "", "NEW_SELECTION")
count = int((arcpy.GetCount_management(inputLayer))[0])

rowValue = str(row.getValue(selectingFeaturesFieldName))
arcpy.AddMessage("%d feature(s) of layer %s found in layer %s (%s: %s)" % (count, inputLayerName, selectingLayerName, selectingFeaturesFieldName, rowValue))
if (count > 0):
outputFC = inputLayerName + "_" + rowValue
arcpy.AddMessage("Copying selected feature(s) to %s" % outputFC)
arcpy.CopyFeatures_management(inputLayer, outputFC)
outputFCs.append(outputFC)
#what does the .append function? I have no idea what this line of code does.
del row, rows
arcpy.SetParameterAsText(4, ";".join(outputFCs))
#SetParametersAsText ist used to give back a result from the script. Is this some kind of text message for the user, saying that some new layers have been created? What does this line of script do? I did not recognize any text messages from the script. And the Desktop Help is a bit confusing for me ("Sets a specified parameter property by index using an object. This is used when passing objects from a script to a script tool. If you need to pass a text value to a script tool, use SetParameterAsText.")

Thank you,
Romy
0 Kudos
LoganPugh
Occasional Contributor III
The first line you ask about initializes an empty Python list object. A list is one of the several sequence types in Python: http://docs.python.org/library/stdtypes.html#typesseq

The second line appends each output feature class (created by the CopyFeatures command) to the list object.

The third line converts the list object to a semicolon-delimited string of the feature classes and then sets the value of the fourth parameter, which in my test script tool is an output, derived parameter of type Feature Class and with the MultiValue option, indicating to the script tool that multiple feature class outputs are being created. Setting this output parameter is what lets ArcMap know to add these feature classes to the map, assuming you have that option enabled under Geoprocessing options, as well as allowing the outputs to be used by subsequent tools in ModelBuilder, for example.
0 Kudos
RomySchroeder
New Contributor
Thank you Logan for your quick response, the explanations and your patience :).
I will implement more functions to the script, but I think I have no more questions for the moment.

Thanks again,
Romy
0 Kudos