Gerando lista de opções de múltiplos valores no ArcGIS usando a Validação de Ferramenta sem usar a Frequência?

11

Estou tentando adaptar uma combinação de modelo e script encontrada no blog da ESRI, intitulada 'Gerando uma lista de opções de vários valores'.

No entanto, concluí que parte da validação usada no script incorporado depende da ferramenta 'Frequency' para funcionar corretamente, mas isso só está disponível com uma licença avançada (lame). A postagem do blog explica o fluxo de trabalho e onde fazer o download dos modelos e scripts (mas felizmente os publicarei aqui, mediante solicitação). Até onde eu sei, o núcleo da funcionalidade que procuro, gerando uma lista de opções com vários valores:

insira a descrição da imagem aqui

..é baseado no script de validação funcionando corretamente. Sem a validação, não consigo fazer com que os valores do campo apareçam como uma lista. Existe alguma coisa que eu possa remover desse script de validação para obter a funcionalidade que estou procurando ou existe uma solução alternativa? Não estou familiarizado com o processo de validação. Aqui está o código para a validação (eu ia postar como um exemplo de código, mas parece que pode ser mais fácil seguir): insira a descrição da imagem aqui

[ Nota do editor: aqui está o código de validação real, a imagem não está correta]

import arcpy

class ToolValidator(object):
  """Class for validating a tool's parameter values and controlling
  the behavior of the tool's dialog."""

  def __init__(self):
    """Setup arcpy and the list of tool parameters."""
    self.params = arcpy.GetParameterInfo()

  def initializeParameters(self):
    """Refine the properties of a tool's parameters.  This method is
    called when the tool is opened."""
    return

  def updateParameters(self):
    """Modify the values and properties of parameters before internal
    validation is performed.  This method is called whenever a parmater
    has been changed."""
    if self.params[1].altered: #Set condition - if the input field value changes
        if self.params[1].value: #if the field parameter has a value
            for field in arcpy.Describe(self.params[0].value).fields: #iterate through fields in the input dataset
                if field.name.lower() == self.params[1].value.value.lower(): #find the field object with the same name as field parameter
                    try:
                        if self.params[2].values: #if this parameter has seleted values
                            oldValues = self.params[2].values #set old values to the selected values
                    except Exception:
                        pass
                    values = set() #create an empty set
                    fieldname = self.params[1].value.value #set the value of variable fieldname equal to the input field value
                    FrequencyTable = arcpy.Frequency_analysis (self.params[0].value, "in_memory\Frequency", self.params[1].value.value, "") #for large tables create a frequency table
                    cursor = arcpy.SearchCursor(FrequencyTable, "", "", self.params[1].value.value, "{0} A".format(self.params[1].value.value)) #open a search cursor on the frequency table
                    for row in cursor: #loop through each value
                        values.add(row.getValue(fieldname)) #add the value to the set
                    self.params[2].filter.list = sorted(values) #set the filter list equal to the sorted values
                    newValues = self.params[2].filter.list
                    try:
                        if len(oldValues): # if some values are selected
                            self.params[2].values = [v for v in oldValues if v in newValues] # check if seleted values in new list,
                            # if yes, retain the seletion.
                    except Exception:
                        pass

  def updateMessages(self):
    """Modify the messages created by internal validation for each tool
    parameter.  This method is called after internal validation."""
    return

É possível que minha suposição (via teste) de que a validação é a peça principal seja falsa e que algo mais não esteja permitindo que os valores sejam expostos como uma lista selecionável? Muito obrigado antecipadamente. Ter esse tipo de funcionalidade realmente dará um salto na adoção de vários fluxos de trabalho importantes que estou tentando distribuir em nossa empresa!

Clickinaway
fonte
1
Qual versão do ArcGIS você está usando? Eu pergunto porque em 10.1 o arcpy.da.SearchCursoré muito mais rápido e mais adequado para esta tarefa do que o anterior arcpy.SearchCursor.
precisa saber é o seguinte
1
O código de validação da caixa de ferramentas que você vinculou é diferente do código de validação na imagem que você vinculou. O primeiro requer uma licença avançada porque usa a ferramenta Frequency. O último, detalhado em uma postagem anterior, não deve, porque apenas usa funções padrão do arco, como o SearchCursor. Eu não tenho uma resposta para você, mas se você juntar os dois, talvez possa descobrir.
precisa saber é o seguinte
@ blah268 É 10,2, desculpe por ter perdido isso. Hmm, agora essa é uma observação muito interessante. Vou olhar para isso, mas estou curioso: entendo corretamente que a validação é o que passa os valores como uma lista de opções? a escolha múltipla é a funcionalidade que eu procuro. Eu voltarei para você, e muito obrigado pela resposta!
Clickinaway
1
As propriedades dos parâmetros da ferramenta de script é onde você configura a lista de parâmetros e suas propriedades (que inclui uma propriedade MultiValue). A validação da ferramenta de script é onde essa ferramenta específica preenche os valores de parâmetros de vários valores com base em outros valores de parâmetros (classe de recurso e nome do campo). Brincando com ele em classes de recursos maiores, eu não colocaria isso em produção. Muito lento e também erros se você não tiver marcado "Substituir as saídas das operações de geoprocessamento" nas opções de Geoprocessamento.
blah238
1
Não consigo conversar, mas o que eu sugeriria é editar sua pergunta para detalhar seus requisitos, o que você tentou e o que não está funcionando.
precisa saber é o seguinte

Respostas:

9

Eu pensei que algumas pessoas poderiam achar isso valioso. A ESRI teve a gentileza de ajudar a resolver isso e encontrar uma alternativa à validação usada na postagem do blog que não requer uma licença Avançada. Embora eu certamente tivesse que descobrir alguns itens adicionais, não posso receber crédito pelo código de validação. Mas, os fins justificam os meios e isso se qualifica como a resposta para minha pergunta. Aqui está:

import arcpy
class ToolValidator(object):
  """Class for validating a tool's parameter values and controlling
  the behavior of the tool's dialog."""

  def __init__(self):
    """Setup arcpy and the list of tool parameters."""
    self.params = arcpy.GetParameterInfo()

  def initializeParameters(self):
    """Refine the properties of a tool's parameters.  This method is
    called when the tool is opened."""
    return

  def updateParameters(self):
    """Modify the values and properties of parameters before internal
    validation is performed.  This method is called whenever a parameter
    has been changed."""
    if self.params[0].value and self.params[1].value:
        self.params[2].filter.list = sorted({row[0] for row in arcpy.da.SearchCursor(self.params[0].value, self.params[1].value.value) if row[0]})

  def updateMessages(self):
    """Modify the messages created by internal validation for each tool
    parameter.  This method is called after internal validation."""
    return

O uso do arcpy.da.SearchCursor retorna valores do campo escolhido muito rapidamente, considerando o número de registros que sua pesquisa (pelo menos nos meus dados). Posso iniciar um novo thread para ver se alguém tem alguma idéia de como aplicar um filtro à validação com base em uma consulta. Espero que isso ajude alguém, mas estou feliz por termos uma resposta!

Clickinaway
fonte
1

Fiz isso de outra maneira: usando o banco de dados consiste em níveis variáveis, sem escolher o shapefile ou os campos apenas selecionando itens do primeiro nível, o script de validação gera os valores para o segundo nível de acordo com a sua escolha no primeiro nível, o script:

import arcpy
class ToolValidator(object):
  """Class for validating a tool's parameter values and controlling
  the behavior of the tool's dialog."""

  def __init__(self):  
    """Setup arcpy and the list of tool parameters."""  
    self.params = arcpy.GetParameterInfo()  



  def initializeParameters(self):  
    """Refine the properties of a tool's parameters.  This method is  
    called when the tool is opened."""  
    return  

  def updateParameters(self):

    fc="C:/LUCS/System_shapes/sys.shp"
##    fc = arcpy.MakeFeatureLayer_management(Lucssys)  
    """Modify the values and properties of parameters before internal  
    validation is performed.  This method is called whenever a parmater  
    has been changed."""  
##    if self.params[0].value and self.params[0].value:


    fc="C:/LUCS/System_shapes/sys.shp"  
    col=  ("L1_NAM") 
    self.params[0].filter.list = [str(val) for val in  
                                    sorted(  
                                      set(  
                                        row.getValue(col)  
                                        for row in arcpy.SearchCursor(fc, None, None,col)))]  
    if self.params[0].value not in self.params[0].filter.list:  
      self.params[0].value = self.params[0].filter.list[0]


    if self.params[0].value:

        fc="C:/LUCS/System_shapes/sys.shp"  
        col1=  ("L1_NAM")
        col2=  ("L2_NAM") 
        fields=(col1,col2)
##___________level2___________________________________________________________
    fc="C:/LUCS/System_shapes/sys.shp" 
    col1=  ("L1_NAM")
    col2=  ("L2_NAM") 
    fields=(col1,col2)

    Level0list=[]
    Level0list_uniq=[]
    cursor = arcpy.SearchCursor(fc)
    for row in cursor:
              if (row.getValue(col1)) ==(str(self.params[0].value)):
                      Level0list.append (row.getValue(col2))

    for elem in Level0list:
              if elem not in Level0list_uniq:
                  Level0list_uniq.append(elem)


    if self.params[1].value not in self.params[1].filter.list:  
        self.params[1].filter.list =Level0list_uniq
##________________level3______________________________________________________        
    fc="C:/LUCS/System_shapes/sys.shp" 
    col2=  ("L2_NAM")
    col3=  ("L3_NAM") 
    fields=(col2,col3)
    Level2list=[]
    Level2list_uniq=[]
    cursor = arcpy.SearchCursor(fc)
    for row in cursor:
              if (row.getValue(col2)) ==(str(self.params[1].value)):
                      Level2list.append (row.getValue(col3))
    for elem in Level2list:
              if elem not in Level2list_uniq:
                  Level2list_uniq.append(elem)
    if self.params[2].value not in self.params[2].filter.list:  
        self.params[2].filter.list =Level2list_uniq
##________________level4______________________________________________________        
    fc="C:/LUCS/System_shapes/sys.shp" 
    col3=  ("L3_NAM")
    col4=  ("L4_NAM") 
    fields=(col3,col4)

    Level3list=[]
    Level3list_uniq=[]
    cursor = arcpy.SearchCursor(fc)
    for row in cursor:
              if (row.getValue(col3)) ==(str(self.params[2].value)):
                      Level3list.append (row.getValue(col4))
    for elem in Level3list:
              if elem not in Level3list_uniq:
                  Level3list_uniq.append(elem)
    if self.params[3].value not in self.params[3].filter.list:  
        self.params[3].filter.list =Level3list_uniq
##________________level5______________________________________________________        
    fc="C:/LUCS/System_shapes/sys.shp" 
    col4=  ("L4_NAM")
    col5=  ("L5_NAM") 
    fields=(col4,col5)

    Level4list=[]
    Level4list_uniq=[]
    cursor = arcpy.SearchCursor(fc)
    for row in cursor:
              if (row.getValue(col4)) ==(str(self.params[3].value)):
                      Level4list.append (row.getValue(col5))
    for elem in Level4list:
              if elem not in Level4list_uniq:
                  Level4list_uniq.append(elem)
    if self.params[4].value not in self.params[4].filter.list:  
        self.params[4].filter.list =Level4list_uniq

  def updateMessages(self):  
    """Modify the messages created by internal validation for each tool  
    parameter.  This method is called after internal validation."""  
Younes Idriss
fonte
0
Add new conditions to ensure a single option when the same term exists in more than one category. ِand to force arcpy to deal with arabic fonts

import arcpy
import sys

reload(sys)

sys.setdefaultencoding('utf-8')

class ToolValidator(object):
  """Class for validating a tool's parameter values and controlling
  the behavior of the tool's dialog."""



  def __init__(self):  
    """Setup arcpy and the list of tool parameters."""  
    self.params = arcpy.GetParameterInfo()  




  def updateParameters(self):

    fc="C:/LUCS/System_shapes/sys.shp"
    col=  ("L1_NAM")
 ##________________level1_________________

    self.params[0].filter.list = [str(val) for val in  
                                    sorted(  
                                      set(  
                                        row.getValue(col)  
                                        for row in arcpy.SearchCursor(fc, None, None,col)))]  
    if self.params[0].value not in self.params[0].filter.list:  
      self.params[0].value = self.params[0].filter.list[0]



    if self.params[0].value:

        fc="C:/LUCS/System_shapes/sys.shp"  
        col1=  ("L1_NAM")
        col2=  ("L2_NAM")
        col3=  ("L3_NAM") 
        col4=  ("L4_NAM")
        col5=  ("L5_NAM") 
        fields=(col1,col2,col3,col4,col5)
        Level1list=[]
        Level1list_uniq=[]
        Level2list=[]
        Level2list_uniq=[]
        Level3list=[]
        Level3list_uniq=[]
        Level4list=[]
        Level4list_uniq=[]
        Level5list=[]
        Level5list_uniq=[]

        cursor = arcpy.SearchCursor(fc)
        for row in cursor:
                        if (row.getValue(col1)) ==(str(self.params[0].value)):
                                Level1list.append (row.getValue(col2))

        for elem in Level1list:
                        if elem not in Level1list_uniq:
                            Level1list_uniq.append(elem)


        if self.params[1].value not in self.params[1].filter.list:  
              self.params[1].filter.list =Level1list_uniq
      ##________________level3_________________        
        cursor = arcpy.SearchCursor(fc)
        for row in cursor:
                  if (row.getValue(col1)) ==(str(self.params[0].value)):
                    if (row.getValue(col2)) ==(str(self.params[1].value)):
                            Level2list.append (row.getValue(col3))
        for elem in Level2list:
                    if elem not in Level2list_uniq:
                        Level2list_uniq.append(elem)
        if self.params[2].value not in self.params[2].filter.list:  
              self.params[2].filter.list =Level2list_uniq
      ##________________level4_______________       
        cursor = arcpy.SearchCursor(fc)
        for row in cursor:
              if (row.getValue(col1)) ==(str(self.params[0].value)):

                    if (row.getValue(col3)) ==(str(self.params[2].value)):
                            Level3list.append (row.getValue(col4))
        for elem in Level3list:
                    if elem not in Level3list_uniq:
                        Level3list_uniq.append(elem)
        if self.params[3].value not in self.params[3].filter.list:  
              self.params[3].filter.list =Level3list_uniq
      ##________________level5_______________      
        cursor = arcpy.SearchCursor(fc)
        for row in cursor:
            if (row.getValue(col1)) ==(str(self.params[0].value)):
                    if (row.getValue(col4)) ==(str(self.params[3].value)):
                            Level4list.append (row.getValue(col5))
        for elem in Level4list:
                    if elem not in Level4list_uniq:
                        Level4list_uniq.append(elem)
        if self.params[4].value not in self.params[4].filter.list:  
              self.params[4].filter.list =Level4list_uniq

    return
Younes Idriss
fonte
Formate seu código inteiro corretamente.
Marcelo Villa
foi feito, está funcionando em 10.5.0
Younes Idriss
Parte do seu código é formatada, mas como você pode ver, outras linhas não são ( por exemplo, as instruções de importação do seu código). Use o { }botão para formatar corretamente seu código.
Marcelo Villa
obrigado pelo conselho
Younes Idriss
Também parece que você está perdendo a definição de uma classe.
Marcelo Villa