1

I am using ArcMap 10.3.1.

I have two parameters for my script tool. The first is the type of product to be created, the second is the scale of the product. Digital Map / No scale required are the default values defined in the Tool Validator code.

If it is a paper product, the user selects the appropriate scale from the drop-down list. As it exists now, the problem I can't solve is that if the user changes the value of parameter 0 to paper map, the list of scales from the list becomes available but the value is still the default ("No scale required") so an error is thrown because that option is not in the scale list. The error clears when I select the scale from the list, but I want only those choices available and obviously don't want the error to appear at all.

Likewise if I then change parameter 0 back to Digital Map the "No scale required" value appears but the error message is thrown again because that value is not in the scale list, which is somehow still appearing. There is no way to clear the error at this point.

Ideally it works as follows: If user picks Paper, only the scales appear. If user switches back to Digital, only the "No scale required" value appears. And so on with switching back and forth (because I can't guarantee my users' behaviour). How can I get these different combinations to appear and change as intended without any errors.

import arcpy
class ToolValidator(object):

  def __init__(self):
    self.params = arcpy.GetParameterInfo()

  def initializeParameters(self):
    # Define the list of product types the user can choose from
    self.params[0].filter.list = ["Digital Map", "Paper Map"]
    self.params[0].value = "Digital Map"  
    return

  def updateParameters(self):
    if self.params[0].value == "Digital Map":
        self.params[1].value = "No scale required"                
    if self.params[0].value == "Paper Map":
        self.params[1].filter.list = ["1:10,000", "1:25,000"]
    return

  def updateMessages(self):
    return
  • 1
    You're not changing your .filter.list on parameter 1 if parameter 0 is changed from paper map to digital map, hence the error. if self.params[0].value == "Digital Map": self.params[1].value = "No scale required" but add self.params[1].filter.list = ["No scale required"] before you set your params[0].value should get you out of trouble. Try that and see if it fixes your issue, if so please answer your own question with your updated working code. – Michael Stimson Nov 25 '19 at 0:33
  • @MichaelStimson do you mean I should try adding your suggestion self.params[1].filter.list = ["No scale required"] in the initializeParameters section before the self.params[0].value = "Digital Map" line? Or did you suggest that that line would go in the updateParameters section? (I will try this out first thing in the morning, hard to visualize the results without the software here - thank you in the meantime) – DavidA Nov 25 '19 at 1:41
3

The problem is in your code:

def updateParameters(self):
    if self.params[0].value == "Digital Map":
        self.params[1].value = "No scale required"                
    if self.params[0].value == "Paper Map":
        self.params[1].filter.list = ["1:10,000", "1:25,000"]
    return 

If you think like a computer your initialization sets parameter 0 as "Digital Map" which fires the updateParameters event so your parameter 1 is set to a value of "No scale required" with no filter list, so it's valid. If you change parameter 0 to "Paper Map" then a filter list is set for parameter 1 to ["1:10,000", "1:25,000"] but the filter list does not contain "No scale required" which parameter 1 is currently set to. Then if you change parameter 0 back from "Paper Map" to "Digital Map" parameter 1 changes back to "No scale required" but the filter isn't modified and as "No scale required" isn't in ["1:10,000", "1:25,000"] the value is not valid.

I suggest you change your updateParameters code to something like this:

  def updateParameters(self):
    if not self.params[0].hasBeenValidated :                # Only do this bit if the value of 0 has changed
      if self.params[0].value == "Digital Map":
          self.params[1].filter.list = ["No scale required"] # ensure this is in the list
          self.params[1].value = "No scale required"                
      if self.params[0].value == "Paper Map":
          self.params[1].filter.list = ["1:10,000", "1:25,000"]
          self.params[1].value = "1:10,000" # Default scale?                
      return

Ensuring that when parameter 0 is changed the filter and value of parameter 1 is modified so that a valid value from the filter exists in the parameter 1 input.

Edit: I've included the not hasBeenValidated for parameter 0 as the value of hasBeenValidated for all parameters is set to true at the end of a validator cycle:

hasBeenValidated is false if a parameter's value has been modified by the user since the last time updateParameters() and internal validate was called. Once internal validate has been called, geoprocessing automatically sets hasBeenValidated to true for every parameter.

Because the validator is also called when parameter 1 changes it overwrites the changed value with the default, by including the not hasBeenValidated for parameter 0 this ensures that the update of parameter 1 properties only occurs if the parameter 0 changes.

  • Your way of explaining the logic has really helped me, not only with this but with some other nagging problems, so thank you very much. I was not thinking enough like a computer :) No more errors appear which is great and I'm able to switch between parameter 0 options, but there is one problem still however - because the params[1].value is set to the default "1:10,000" I am not able to change that to the other available option in the filter list (1:25,000). I've tried re-ordering things but no dice yet. Any ideas? – DavidA Nov 25 '19 at 13:12
  • 1
    Oh, my bad. I wasn't thinking enough like a computer, I wasn't taking into account that updating the value of parameter 1 also fired the updateParameters event, so it's not that you can't change the value it's just that the updateParameters is changing it back. I'll fix that now. – Michael Stimson Nov 25 '19 at 23:30
  • Ah, great. This works now too, and I'll be able to use this 'template' for other projects with issues I've been putting off. Good to see the multiple ways of doing things, gives the user some flexibility. Cheers. – DavidA Nov 26 '19 at 13:10
0

I combined some help received here and elsewhere and am using the following as the solution that does exactly what I want in the validator. Thank you, appreciate the advice and tips for thinking like the machine.

import arcpy
class ToolValidator(object):

  def __init__(self):
    self.params = arcpy.GetParameterInfo()

  def initializeParameters(self):
    self.params[0].filter.list = ["Digital Map", "Paper Map"]
    self.params[0].value = "Digital Map"     
    return

  def updateParameters(self):
    if self.params[0].value == None:
      self.params[0].value = "Digital Map"
    if self.params[0].valueAsText == "Digital Map":
      self.params[1].filter.list = ["Not applicable"]
      self.params[1].value = "Not applicable"
      self.params[1].enabled = False    
    else:
      self.params[1].filter.list = ["1:10,000", "1:25,000"]
    if self.params[1].value not in self.params[1].filter.list:
      self.params[1].value = self.params[1].filter.list[0]
      self.params[1].enabled = True
    return

  def updateMessages(self):
    return

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.