5 votos

¿Script de calculadora de campos para calcular los 5 primeros campos de área dominante?

Tengo 5 campos de diferentes tipos de cubierta vegetal con áreas de cada uno y se encuentran a continuación:

> PRC_Water| PRC_Bare| PRC_Urban| PRC_LVeg| PRC_LVeg|
>     5        20         40        20         15

Tengo otros 5 campos de dominancia [Dom1, Dom2, Dom3, Dom4, Dom5] que me gustaría rellenar con el nombre_campo del tipo de cobertura del suelo. Me gustaría saber si es posible escribir un script/afirmación condicional en la calculadora de campos para que devuelva el nombre de campo de la '#ésima' área más grande, y si hay alguna forma de devolver ambos nombres si las áreas son iguales?

enter image description here

Tengo conocimientos limitados de python, pero estoy perplejo ¿cómo puedo clasificar estas áreas devolviendo un nombre de campo?

6voto

Roy Puntos 2884

Si utilizaras un script podría calcular todos los campos a la vez. Si utilizaras la calculadora de campos, tendrías que ejecutarla en cada campo que quisieras actualizar (5x).

El siguiente script actualizará sus campos Dom en el orden de los valores de sus campos de cobertura terrestre. Si varios campos tienen el mismo valor, se añadirá el nombre de cada campo según su ejemplo. He probado el script con los datos de dumby y me funciona. Dicho esto, puede que no sea el método más eficiente.

EDITAR: Ahora el script extrae dinámicamente los nombres de los campos del conjunto de datos. Busca "PRC" en el nombre del campo para denotar un tipo de cubierta terrestre y "Dom" para un campo dominante. Sólo se escriben los campos con valores superiores a cero, dejando en blanco los campos Dom restantes.

Hay bastantes decimales, por lo que los únicos valores repetidos (según los datos ficticios que has enviado) son ceros. Tal vez esto es diferente en todo el conjunto de datos, así que no pude probar la sección que escribe múltiples nombres de campo en una columna.

import arcpy

# Put the absolute path to your table / feature class
theData = r"C:YourPathHere" 

# Create empty Python list, and a list of field names
values = []
fields = []
domFields = []

# Get all landcover and Dom field names dynamically
for field in arcpy.ListFields(theData):
    if 'PRC' in field.name: 
        fields.append(field.name) # Grab all fields names that contain "PRC"
    elif 'Dom' in field.name:
        domFields.append(field.name)

# Arcpy Update cursor
rows = arcpy.UpdateCursor(theData)

# Loop through each row in your attribute table
for row in rows:
    i = 0
    while i < len(fields):
        # Store the fieldname and value in a tuple, add to list ex. [("PRC_Water", 5), ("PRC_Bare", 10), etc.]
        values.append((fields[i], row.getValue(fields[i])))
        i += 1 # iterate counter
    # Sort the list of tuples based on the integer value in descending order
    values =  sorted(values, key=lambda value: value[1], reverse=True)
    sortedFields = [x[0] for x in values] # Grab the ordered field names
    sortedValues = [x[1] for x in values] # Grab the ordered field values

    # Set the values of Dominance fields based on the order of the list
    j = 0
    while j < len(domFields):
        if sortedValues[j] > 0:
            row.setValue(domFields[j], sortedFields[j])
        else: # if the next greatest value is zero, leave the field blank
            row.setValue(domFields[j], "")
        j += 1 # iterate counter
    rows.updateRow(row)

    # This section handles cases where multiple landuse values are equal
    k=0
    while k < len(fields):
        fieldsEqual = ""
        startRepeat = 0
        numRepeat = 0
        # If two fields contain the same value...
        if sortedValues.count(sortedValues[k]) > 1:
            # Find the position in the list where they begin to repeat (repeated values will occur back-to-back)
            startRepeat = sortedValues.index(sortedValues[k])
            # Find the number of times the value is repeated
            numRepeat = sortedValues.count(sortedValues[k])
            l = 0
            # While the counter is less than the number of repeated values, append the field name to a string
            while l < numRepeat:
                fieldsEqual += sortedFields[startRepeat + l]
                # Add a comma and space to each value except the last one
                if l < numRepeat - 1:
                    fieldsEqual += ", "
                l += 1 # iterate counter

            # Write the fields with equal values into the Dom fields
            m = 0
            while l < numRepeat:
                row.setValue(domFields[startRepeat + m] , fieldsEqual)
                rows.updateRow(row)
                m += 1 # iterate counter
        k += 1 # iterate counter

    # Clear the list for the next row of data
    values = []

# Delete cursor objs
del row, rows

1 votos

+1 - buen punto sobre 5 x cálculos de campo frente a una sola ejecución de script Python y código agradable.

0voto

georg Puntos 116

Intenté Respuesta de @Roy en los datos ficticios y ¡funcionó perfectamente!

Sin embargo, los datos reales tienen 11 campos y 5 campos dominantes. Esto crea un error en tiempo de ejecución y decir "índice de la lista fuera de rango".

Aquí está el script ajustado (desde mi ventana de python) para los datos reales y el error que sigue, no estoy muy seguro de donde se podría ajustar el script para incluir más campos y aún así tener sólo 5 clases dominantes? Por favor, eche un vistazo a la secuencia de comandos y aconsejar cómo ajustarlo para los datos reales. Muchas gracias por su tiempo.

>>> import arcpy
>>> theData = r"J:\Jens\Leeuwfontein (Ben Breedlove)\Fixed_LC and Seg\Pythontest\test2.dbf"
>>> values = []
... fields = ["PRC_Water", "PRC_Bare", "PRC_Urban", "PRC_Lveg", "PRC_Hveg", "PRC_Trans", "PRC_BLSVeg", "PRC_Wetlnd", "PRC_ImpGrd", "PRC_Cloud", "PRC_Cldshd"]
... domFields = ["Dom1", "Dom2", "Dom3", "Dom4", "Dom5"]
... 
>>> rows = arcpy.UpdateCursor(theData)
>>> for row in rows:
...     i = 0
...     while i < len(fields):
...         values.append((fields[i], row.getValue(fields[i])))
...         i += 1
...     values =  sorted(values, key=lambda value: value[1], reverse=True)
...     sortedFields = [x[0] for x in values]
...     sortedValues = [x[1] for x in values]
...     j = 0
...     while j < len(fields):
...         row.setValue(domFields[j], sortedFields[j])
...         j += 1
...     rows.updateRow(row)
...     k=0
...     while k < len(fields):
...         fieldsEqual = ""
...         startRepeat = 0
...         numRepeat = 0
...         if sortedValues.count(sortedValues[k]) > 1:
...             startRepeat = sortedValues.index(sortedValues[k])
...             numRepeat = sortedValues.count(sortedValues[k])
...             l = 0
...             while l < numRepeat:
...                 fieldsEqual += sortedFields[startRepeat + l]
...                 if l < numRepeat - 1:
...                     fieldsEqual += ", "
...                 l += 1
...             l = 0
...             while l < numRepeat:
...                 row.setValue(domFields[startRepeat + l] , fieldsEqual)
...                 rows.updateRow(row)
...                 l += 1
...         k += 1
...     values = []
...     
Runtime error <type 'exceptions.IndexError'>: list index out of range
>>>

0 votos

Un comentario o petición más Roy; ¿es posible devolver un nombre de campo sólo si su valor es mayor que cero? De forma que si el valor es cero, entonces devuelva un espacio en blanco. Ejemplo: Si los valores en ID 1 = 0,20,40,20,0 para PRC_Water| PRC_Bare| PRC_Urban| PRC_LVeg| PRC_LVeg| respectivamente me gustaría que devolviera "Dom1=PRC_Urban|Dom2=PRC_Bare,PRC_LVeg|Dom3=PRC_Bare,PRC_LVeg|Dom4= |Dom5= | ¿Sería posible? No puedo agradecerte lo suficiente tu ayuda, ¡esto me está ayudando mucho!

0 votos

Tal vez usted podría publicar su .dbf a Dropbox o Pastebin para que pueda echar un vistazo más de cerca.

0 votos

También tengo curiosidad por saber dónde se produjo el error. Sospecho que fue en la línea 29 row.setValue(domFields[j], sortedFields[j]) . ¿Puede facilitarnos el número de línea?

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X