0

I am trying to create a custom tool via python script that selects features in multiple fc's within a feature dataset that are missing values, then from the selected features, creates two outputs: one for points and one for lines. I also want the outputs to have the following fields: OBJECTID, TYPEOFFEATURE, and WHATISMISSING, with the fields populated with their respective attributes. For example, WHATISMISSING should have the field from the fc that has null values and TYPEOFFEATURE should have the fc that . I am not sure how to create two separate outputs determined by the feature type or how to create the fields in them.

This is what I have so far. BTW the datasets are in an enterprise geodatabase so if my workspace is the wrong syntax, please let me know:

import arcpy
# Set the workspace for ListFeatureClasses
arcpy.env.workspace = r"C:\DatabaseCon\GIS.sde"
# Use the ListFeatureClasses function to return a list of feature classes.
fc = list(set(arcpy.ListFeatureClasses("ARCFM.Light", "Point", feature_dataset="ARCFM.ElectricDataset")) | set(arcpy.ListFeatureClasses("ARCFM.Pole", "Point", feature_dataset="ARCFM.ElectricDataset")) | set(arcpy.ListFeatureClasses("ARCFM.SurfaceStructure", "Line", feature_dataset="ARCFM.ElectricDataset")) | set(arcpy.ListFeatureClasses("ARCFM.UndergroundStructure", "Line", feature_dataset="ARCFM.ElectricDataset")))
# loop through the list of feature classes, select by attribute depending on the fc, and export the selected features to a shapefile.
for ifc in fc:
 if ifc = "ARCFM.Light":
 arcpy.management.SelectLayerByAttribute(ifc, '"LIGHTTYPE" IS NULL')
 elif ifc = "ARCFM.Pole":
 arcpy.management.SelectLayerByAttribute(ifc, '"Subtype" IS NULL')
 elif ifc = "ARCFM.SurfaceStructure":
 arcpy.management.SelectLayerByAttribute(ifc, '"Subtype" IS NULL')
 elif ifc = "ARCFM.UndergroundStructure":
 arcpy.management.SelectLayerByAttribute(ifc, '"Subtype" IS NULL')
# create layer from selection
for mfl in fc:
 if mfl.arcpy.management.ListDatasets.feature_type = "POINT": 
 arcpy.management.MakeFeatureLayer(ARCFM.Light, 
 "r"C:\DatabaseConnection\DirectConnectGISPROD.sde\points_missing_features, "", "", 
 "OBJECTID", "TYPEOFFEATURE", "WHATISMISSING") | 
 arcpy.management.MakeFeatureLayer(ARCFM.Pole, 
 "r"C:\DatabaseConnection\DirectConnectGISPROD.sde\points_missing_features, "", "", 
 "OBJECTID", "TYPEOFFEATURE", "WHATISMISSING")
 else:
 arcpy.management.MakeFeatureLayer(ARCFM.SurfaceStructure, 
 "r"C:\DatabaseConnection\DirectConnectGISPROD.sde\lines_missing_features, "", "", 
 "OBJECTID", "TYPEOFFEATURE", "WHATISMISSING") | 
 arcpy.management.MakeFeatureLayer(ARCFM.UndergroundStructure, 
 "r"C:\DatabaseConnection\DirectConnectGISPROD.sde\lines_missing_features, "", "", 
 "OBJECTID", "TYPEOFFEATURE", "WHATISMISSING")

I know I am missing things like determining constraints for the fields in the output fc's, I just don't know how to do that in Python.

PolyGeo
65.5k29 gold badges115 silver badges349 bronze badges
asked Jun 22, 2022 at 15:51

2 Answers 2

0

I figured it out:

import arcpy
import os
# Set the workspace to the geodatabase that contains the feature classes
arcpy.env.overwriteOutput = True
# define the feature classes that the rows that contain null values will be inserted into.
outputLocation = arcpy.GetParameterAsText(0)
nullPntFc = arcpy.GetParameterAsText(1)
nullLineFc = arcpy.GetParameterAsText(2)
connection = arcpy.GetParameterAsText(3)
arcpy.env.workspace = connection
#nullPolyFc = arcpy.GetParameterAsText(4)
#Create the output null point feature class
sr = arcpy.SpatialReference(2283)
arcpy.CreateFeatureclass_management(outputLocation, nullPntFc, "POINT", spatial_reference=sr)
arcpy.management.AddField(os.path.join(outputLocation, nullPntFc), "FC", "TEXT")
arcpy.management.AddField(os.path.join(outputLocation, nullPntFc), "FC_objectId", "LONG")
arcpy.management.AddField(os.path.join(outputLocation, nullPntFc), "AttributeMissing", "TEXT")
#Create the output null line feature class
arcpy.CreateFeatureclass_management(outputLocation, nullLineFc, "POLYLINE", spatial_reference=sr)
arcpy.management.AddField(os.path.join(outputLocation, nullLineFc), "FC", "TEXT")
arcpy.management.AddField(os.path.join(outputLocation, nullLineFc), "FC_objectId", "LONG")
arcpy.management.AddField(os.path.join(outputLocation, nullLineFc), "AttributeMissing", "TEXT")
#Create output null polygon feature class
#arcpy.CreateFeatureclass_management(outputLocation, nullPolyFc, "POLYGON", spatial_reference=sr)
#arcpy.management.AddField(os.path.join(outputLocation, nullPolyFc), "FC", "TEXT")
#arcpy.management.AddField(os.path.join(outputLocation, nullPolyFc), "FC_objectId", "LONG")
#arcpy.management.AddField(os.path.join(outputLocation, nullPolyFc), "AttributeMissing", "TEXT")
# Get the list of feature classes in the geodatabase
fcListLine = arcpy.ListFeatureClasses("*Section", feature_dataset = "ARCFM.ElectricDataSet")
fcListPoint = arcpy.ListFeatureClasses("*Transformer", feature_dataset = "ARCFM.ElectricDataSet") + arcpy.ListFeatureClasses("*Bank", feature_dataset = "ARCFM.ElectricDataSet") + arcpy.ListFeatureClasses("*Location", feature_dataset = "ARCFM.ElectricDataSet") 
fcListSelection =fcListLine+fcListPoint
#fcListSelection = ['ARCFM.SecondaryUGLineSection', 'ARCFM.RegulatorBank']
arcpy.AddMessage('feature classes :'+str(fcListSelection))
for fc in fcListSelection:
 # Describe feature class to get attributes used in nullPntFc, nullPolylineFc, and nullPolygonFc.
 desc = arcpy.Describe(fc)
 fcName = desc.name
 fcType = desc.shapeType # Point, Polyline, Polygon
 arcpy.AddMessage(fcName + ' - '+ fcType)
 # get the field names to be used in the search cursor
 fieldNames = [field.name for field in arcpy.ListFields(fc) if field.name.endswith("FEEDERID") or field.name.endswith("LOCATIONID") or field.name.endswith("PHASINGCODE")]+['SHAPE@', 'OID@']
 arcpy.AddMessage(fieldNames)
 # Get the shape field index from the list of fields. The index will be used in the search cursor to pull the shape value
 #fields = arcpy.ListFields(fc)
 # Dump point features with null attributes in the point feature classes into nullPntFc
 if fcType == 'Point':
 insertCursor = arcpy.da.InsertCursor(os.path.join(outputLocation, nullPntFc), ['SHAPE@XY', 'FC', 'FC_objectId', 'AttributeMissing'])
 searchCursor = arcpy.da.SearchCursor(fc, fieldNames)
 for row in searchCursor:
 null_fields = ''
 for i in range(len(fieldNames)-3):
 if row[i]==None:
 null_fields+=fieldNames[i]+','
 oid = row[5]
 fcName = fc
 if len(null_fields) > 1:
 insertCursor.insertRow([row[4], fcName, oid, null_fields[:-1]])
 
 
 if fcType == 'Polyline':
 insertCursor = arcpy.da.InsertCursor(os.path.join(outputLocation, nullLineFc), ['SHAPE@', 'FC', 'FC_objectId', 'AttributeMissing'])
 searchCursor = arcpy.da.SearchCursor(fc, fieldNames)
 for row in searchCursor:
 null_fields = ''
 for i in range(len(fieldNames)-2):
 if row[i]==None:
 null_fields+=fieldNames[i]+','
 oid = row[4]
 fcName = fc
 if len(null_fields) > 1:
 insertCursor.insertRow([row[3], fcName, oid, null_fields[:-1]])
 if fcType == 'Polygon':
 insertCursor = arcpy.da.InsertCursor(os.path.join(outputLocation, nullPolyFc), ['SHAPE@', 'FC', 'FC_objectId', 'AttributeMissing'])
 searchCursor = arcpy.da.SearchCursor(fc, fieldNames)
 for row in searchCursor:
 null_fields = ''
 for i in range(len(fieldNames)-2):
 if row[i]==None:
 null_fields+=fieldNames[i]+','
 oid = row[4]
 fcName = fc
 insertCursor.insertRow([row[3], fcName, oid, null_fields[:-1]])
answered Jul 8, 2022 at 13:41
-1

Please see comments for information

# Set the workspace to the geodatabase that contains the feature classes
arcpy.env.workspace = r'C:\Temp\SelectNullFeatures\Geodatabase.gdb'
arcpy.env.overwriteOutput = True
# define the feature classes that the rows that contain null values will be inserted into.
nullPntFc = r'C:\Temp\SelectNullFeatures\Geodatabase2.gdb\NullPoints'
outPolyPath = r'C:\Temp\SelectNullFeatures\Geodatabase2.gdb'
# Get the list of feature classes in the geodatabase
fcList = arcpy.ListFeatureClasses()
# print(fcList)
for fc in fcList:
 # Describe feature class to get attributes used in nullPntFc, nullPolylineFc, and nullPolygonFc.
 desc = arcpy.Describe(fc)
 fcName = desc.name
 fcType = desc.shapeType # Point, Polyline, Polygon
 print(fcName + ' - '+ fcType)
 # get the field names to be used in the search cursor
 fieldNames = [field.name for field in arcpy.ListFields(fc)]
 print(fieldNames)
 # Get the shape field index from the list of fields. The index will be used in the search cursor to pull the shape value
 fields = arcpy.ListFields(fc)
 for field in fields:
 if field.type == 'Geometry':
 shapeFieldIndex = fields.index(field)
 # Dump point features with null attributes in the point feature classes into nullPntFc
 if fcType == 'Point':
 count = 0
 while count < len(fieldNames) - 1:
 with arcpy.da.SearchCursor(fc,fieldNames) as sc:
 for row in sc:
 if None in row:
 fieldName = fieldNames[count]
 insertCursor = arcpy.da.InsertCursor(nullPntFc, ('SHAPE@XY', 'FC', 'FC_objectId', 'AttributeMissing'))
 insertRow = [row[shapeFieldIndex], fcName, str(row[0]), fieldName]
 print(insertRow)
 insertCursor.insertRow(insertRow)
 del insertCursor
 count += 1
 ''' using insert cursor on polylines and polygons is more difficult. I think you would have to build the
 geometry object to insert. Someone can correct me if I am wrong. I chose to go a different route with these shape types'''
 if fcType == 'Polyline':
 # Make a feature layer to be able to select rows with null values
 fcFeatLyr = arcpy.MakeFeatureLayer_management(fc, 'polylineFcLyr')
 # Insert the objectID column into the field names list. the objectID will be part of the selection where clause
 fieldNames.insert(0, 'OID@')
 with arcpy.da.SearchCursor(fc, fieldNames) as sc:
 for row in sc:
 #selects any row in the feature class that has a null attribute
 if None in row:
 selectedFcFeatLyr = arcpy.SelectLayerByAttribute_management(fcFeatLyr, 'ADD_TO_SELECTION', 'OBJECTID = {}'.format(row[0]))
 #export the selected rows to a new feature class
 arcpy.FeatureClassToFeatureClass_conversion(selectedFcFeatLyr, outPolyPath, fcName + '_Nulls')
 # same as polylines, but just with different variables
 if fcType == 'Polygon':
 fcFeatLyr = arcpy.MakeFeatureLayer_management(fc,'polygonFcLyr')
 fieldNames.insert(0,'OID@')
 with arcpy.da.SearchCursor(fc, fieldNames) as sc:
 for row in sc:
 if None in row:
 selectedFcFeatLyr = arcpy.SelectLayerByAttribute_management(fcFeatLyr, 'ADD_TO_SELECTION', 'OBJECTID = {}'.format(row[0]))
 arcpy.FeatureClassToFeatureClass_conversion(selectedFcFeatLyr, outPolyPath,fcName + '_Nulls')```
Your insertCursor must match the the fields in the nullPntFc.
Example:
insertCursor = arcpy.da.InsertCursor(nullPntFc, ('SHAPE@XY', 'FC', 'FC_objectId', 'AttributeMissing'))
Image of my nullPtFc fields:
[![NullPtsFc fields][1]][1]
 [1]: https://i.sstatic.net/HUAqs.jpg
answered Jun 24, 2022 at 21:43
11
  • 1
    Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center. Commented Jun 24, 2022 at 21:44
  • Thank you! I have a question about the arcpy.ListFeatureClasses function. Is it possible to have multiple arguments to narrow down the list of fc's in the function? I want 10 specific fc's in a dataset to be selectable, and they have different names and geometry types. Commented Jun 27, 2022 at 17:40
  • I am not aware of being able to pass in multiple arguments into the arcpy.ListFeatureClasses. One way to get the list you want, would be to compare the arcpy.ListFeatureClasses list to a list of Feature classes you want using list comprehension. For example: returnedList = [fc1, fc2, fc3] desiredFcList = [fc1, fc2] fcList = [fc for fc in returnedList if fc in desiredFcList] Commented Jun 28, 2022 at 14:35
  • Ok so I added to the line fieldNames = with fieldNames = [field.name for field in arcpy.ListFields(fc) if field.name.endswith("FEEDERID") or field.name.endswith("LOCATIONID") or field.name.endswith("PHASINGCODE")] + ['SHAPE@XY'] But I am getting an error on the line insertRow = [row[shapeFieldIndex], fcName, str(row[0]), fieldName] that says "IndexError: tuple index out of range" I can't figure out why this is the case because I defined the fields for the searchCursor. Commented Jul 6, 2022 at 19:00
  • Modified to fieldNames = [field.name for field in arcpy.ListFields(fc) if field.name.endswith("FEEDERID") or field.name.endswith("LOCATIONID") or field.name.endswith("PHASINGCODE") or field.name.endswith('SHAPE@')] but I am not sure what to modify on insertCursor and insertRow if they contain the fields I want to add to the new feature class (Shape@, FC, FC_objectID, AttributeMissing) Commented Jul 7, 2022 at 12:47

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.