Friday 19 April 2019

arcpy - How can I use updateParameters to handle both points AND polyline feature layers?


I'm using ArcMap 10.2.1 and Python 2.7.5.


I would like my updateParameters to enable and disable fields based on if a feature is a point or a polygon. If the point is selected then I need the measure. If the line is selected then I need the begin measure and the end measure. I am getting a similar error as coolDude when I open my tool in ArcMap.


There is an excellent discussion that almost answers my question posted here: Understanding updateParameters and updateMessages interaction in Python Toolbox?


The questioner (coolDude) had two related questions that also got very close to answering my question. However, the tool I am writing is comparing either two point features, a point and a line feature, or two line features.


The error suggest that my describe method is incorrect. Python developers, am I using the syntax incorrectly? I checked out my code in the console and I got the desired effect.



Here is my getParameterInfo method:


    input_base_feature = arcpy.Parameter(displayName="Base Feature",
name="input_base_feature",
datatype="GPFeatureLayer",
parameterType="Required",
direction="Input")
params.append(input_base_feature)
input_base_id_field = arcpy.Parameter(displayName="Base Feature ID Field",
name="input_base_id_field",
datatype="Field",

parameterType="Required",
direction="Input")
input_base_id_field.parameterDependencies = [input_base_feature.name]
params.append(input_base_id_field)

input_base_measure_field = arcpy.Parameter(displayName="Base Feature Measure Field",
name="input_base_measure_field",
datatype="Field",
parameterType="Required",
direction="Input")

input_base_measure_field.parameterDependencies = [input_base_feature.name]
input_base_measure_field.filter.list = ['Float', 'Double']
params.append(input_base_measure_field)

input_base_begin_measure_field = arcpy.Parameter(displayName="Base Feature Begin Measure Field",
name="input_base_begin_measure_field",
datatype="Field",
parameterType="Required",
direction="Input")
input_base_begin_measure_field.parameterDependencies = [input_base_feature.name]

input_base_begin_measure_field.filter.list = ['Float', 'Double']
params.append(input_base_begin_measure_field)

input_base_end_measure_field = arcpy.Parameter(displayName="Base Feature End Measure Field",
name="input_base_end_measure_field",
datatype="Field",
parameterType="Required",
direction="Input")
input_base_end_measure_field.parameterDependencies = [input_base_feature.name]
input_base_end_measure_field.filter.list = ['Float', 'Double']

params.append(input_base_end_measure_field)

Further down in the code, I use the updateParameter method:


    desc_base = arcpy.Describe(parameters[4].value)
if desc_base.shapeType == 'Point':
parameters[6].enabled = True,
parameters[6].parameterType = 'Required',
parameters[7].enabled = False,
parameters[7].parameterType = 'Optional',
parameters[8].enabled = False,

parameters[8].parameterType = 'Optional'
elif desc_base.shapeType == 'Polyline':
parameters[6].enabled = False,
parameters[6].parameterType = 'Optional',
parameters[7].enabled = True,
parameters[7].parameterType = 'Required',
parameters[8].enabled = True,
parameters[8].parameterType = 'Required'
else:
arcpy.AddMessage("Incorrect type for input_base_feature. Point or polyline features only.")


My guess is


    desc_base = arcpy.Describe(parameters[4].value)

Is incorrect. The other error I get has to do with the line:


    parameters[6].parameterType = 'Required',

I tried it without comments and I tried replacing the .value with .valueAsText and I got the same errors. Speaking of, here are the errors:


When I select a Centerline:


Traceback (most recent call last): 

File "C:\Workspace\qcerator\src\eaglepyqc\toolboxes\check_for_overlaps.py",
line 147, in updateParameters desc_base = arcpy.Describe(parameters[4].value)

File "c:\program files (x86)\arcgis\desktop10.2\arcpy\arcpy\__init__.py",
line 1234, in Describe return gp.describe(value)

File "c:\program files (x86)\arcgis\desktop10.2\arcpy\arcpy\geoprocessing\_base.py",
line 374, in describe self._gp.Describe(*gp_fixargs(args, True)))

AttributeError: Object: Error in parsing arguments for Describe


When I select a Base Feature (line):


Traceback (most recent call last): 
File "C:\Workspace\qcerator\src\eaglepyqc\toolboxes\check_for_overlaps.py",
line 153, in updateParameters parameters[8].enabled = False

TypeError: list indices must be integers, not tuple

When I select a Base feature (point):


Traceback (most recent call last): 

File "C:\Workspace\qcerator\src\eaglepyqc\toolboxes\check_for_overlaps.py",
line 150, in updateParameters parameters[6].enabled = False

TypeError: list indices must be integers, not tuple

And finally, a screenshot of the toolbox so you can see the whole thing. I left out lines of code that sets up the Centerline and cross feature inputs for the sake of brevity.


Python Toolbox Tool


The reason I put in the lines with "required" or "optional" is I still get the green dots next to the grayed-out fields. Furthermore, the fields only get grayed-out if a polyline is selected. The if statement doesn't work if a point feature class is selected from the drop-down menu.



Answer



I was able to take the answer @DWynne gave me for Python Toolbox Error Messages and apply it to this problem. The issue of enabling/disabling ID, Begin and End Measure fields using updateParameters was a red herring. Instead, preventing the user from even selecting bad data (i.e. a polygon feature) could be handled using the updateMessages method.



def updateMessages(self, parameters):
"""
Definition needed for Python Toolbox.
"""
centerline_value = parameters[0].valueAsText
if centerline_value:
desc = arcpy.Describe(centerline_value)
if desc.shapeType != 'Polyline':
parameters[0].setErrorMessage('Only polylines are accepted')
# If the user selects a Base feature class instead of a table, this ensures only points and polylines are present.

base_compare = parameters[4].valueAsText
if base_compare:
desc = arcpy.Describe(base_compare)
if desc.datasettype in ['FeatureLayer', 'FeatureClass'] and desc.shapeType not in ['Point','Polyline']:
parameters[4].setErrorMessage('Only points, polylines and tables are accepted')
# If the user selects a Cross feature class instead of a table, this ensures only points and polylines are present.
cross_compare = parameters[9].valueAsText
if cross_compare:
desc = arcpy.Describe(cross_compare)
if desc.datasettype in ['FeatureLayer', 'FeatureClass'] and desc.shapeType not in ['Point','Polyline']:

parameters[9].setErrorMessage('Only points, polylines and tables are accepted')
return

Now I am able to display a message preventing the tool from running. I also added the additional functionality allowing a table (with route id, begin measure, and end measure fields) as a parameter for base and cross features.


Also, the errors I was receiving "AttributeError: Object: Error in parsing arguments for Describe" have to do with not checking the parameters as either:


desc = parameters[0].valueAsText
desc = parameters[0].value
desc = parameters[0].altered
desc = parameters[0].hasBeenValidated


If the parameter is checked, then I can go on to make .shapeType and .dataType boolean statements. There are more on ESRI's documentation but those are ones I've used before.


Side note: It is a matter of Pep-8 rule breaking preference if you want your lines to extend past 80 OR have an extra line of code. I prefer using the boolean AND instead of a nested if.


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...