3 votos

¿Código Python para comparar dos campos en diferentes capas de características?

Tengo dos archivos shape que abarcan 3897 características cada uno. Los shapefiles correspondientes (pueblo y cuenca que desemboca en él) tienen el mismo ID (ws_id en uno, OBJECTID en el otro). Muchas cuencas hidrográficas se solapan. Debido a los errores en la capa de la cuenca, quiero comparar las áreas de cada cuenca con su pueblo correspondiente (settelment_area para los pueblos y Shape_Area para las cuencas). Si la cuenca tiene una superficie menor que la del pueblo en el que desemboca, hay que eliminarla y añadir los datos del pueblo correspondiente a los del pueblo en el que desemboca la siguiente cuenca (los datos incluyen el área urbana y la población).

He intentado hacer esto usando cursores y tablas temporales, pero mis conocimientos de python no son muy buenos y parece que pierdo muchos de los datos relacionados por el camino (terminando con listas vacías).

utilizando arcgis desktop 10.2 con licencia avanzada

Código

#the aim of this code is to get rid of erroneous data by creating a new serviceshed_v0 shapefile which would contain only serviceshed which are larger than the settlement they run into.
#it could then be extended to have different minium size requirements for servicesheds

import arcpy
arcpy.CheckOutExtension("spatial")
arcpy.env.overwriteOutput = True

workdir = r'C:\Users\xxx\beneficiarylayers.gdb'
arcpy.env.workspace = workdir
fc1 = workdir + r'\servicesheds_v0'
fc2 = workdir + r'\miyun_settlements'
fc1table = arcpy.CreateTable_management(workdir, 'fc1table')
fc2table = arcpy.CreateTable_management(workdir, 'fc2table')
template = workdir + r'\template'
arcpy.CreateTable_management(workdir, 'servicesheds_v1', template)
newservicesheds = workdir + r'\servicesheds_v1'

rows = arcpy.SearchCursor(fc1)
for row in rows:
    arcpy.Append_management('Shape_Area', fc1table)

del row, rows

rows = arcpy.SearchCursor(fc2)
for row in rows:
    arcpy.Append_management('settlement_area', fc2table)

del row, rows

rows = arcpy.SearchCursor(fc1table)
for row in rows:
    if fc1table > fc2table:
        arcpy.Append_management(row, newservicesheds)

del row, rows

es un primer intento. El problema es que me doy cuenta de que las tablas no son el camino a seguir porque los datos que relacionan cada tupla con un polígono se pierden. me gustaría conseguir algo como esto para trabajar (abajo), pero no estoy seguro de si se permite en python synthax

arcpy.CreateTable_management(workdir, 'servicesheds_v1')
newservicesheds = workdir + r'\servicesheds_v1'

cursor1=arcpy.da.SearchCursor(fc1, "Shape_Area")
cursor2=arcpy.da.SearchCursor(fc2, "settlement_area")

for row in cursor1:
    if 'Shape_Area' in cursor1 > 'settlement_area' in cursor2:
        arcpy.Append_management(row, newservicesheds)

CÓDIGO FINAL He aquí un método que permite crear rápidamente una lista con todos los polígonos que cumplen la función de ser demasiado pequeños.

import arcpy
arcpy.CheckOutExtension("spatial")
arcpy.env.overwriteOutput = True

workdir = r'C:\Users\xx\beneficiarylayers.gdb'
arcpy.env.workspace = workdir
fc1 = workdir + r'\servicesheds_v0'
fc2 = workdir + r'\miyun_settlements'

#set up cursors
cursor1 = arcpy.da.SearchCursor(fc1, ["ws_id", "Shape_Area"])
cursor2 = arcpy.da.SearchCursor(fc2, ["OBJECTID", "settlement_area"])
wrongsheds = []
#make a dictionary and store values from watershed table
serviceshed_area = {}
for row in cursor1:
  serviceshed_areas[row[0]] = row[1]

#loop through other table
for row in cursor2:
  if row[1] > serviceshed_areas[row[0]]:
    # if serviceshed_areas < village_Areas add to list and print
    wrongsheds.append(row[0])
    print "serviceshed {} is wrong".format(row[0])

5voto

Trevor Johns Puntos 126

Parece que hay una pequeña confusión sobre qué es mayor/menor que qué pero lo dejaré para que lo manipules. Esta solución iterará UNA SOLA VEZ a través de cada tabla lo que no confundirá los cursores y le ahorrará 10 millones de iteraciones(de bucle en una iteración de bucle). Usar un diccionario de búsqueda es tan rápido que se considera 'gratis'. Así que poblar un diccionario en un bucle y hacer referencia a él en otro bucle (que NO está dentro del primer bucle). No puedo hablar de la exactitud/sintaxis ya que no lo he ejecutado.

#set up cursors
cursor1 = arcpy.da.SearchCursor(fc1, ["OBJECTID", "Shape_Area"])
cursor2 = arcpy.da.SearchCursor(fc2, ["ws_id", "settlement_area"])

#make a dictionary and store values from watershed table
watershed_areas = {}
for row in cursor1:
  watershed_areas[row[0]] = row[1]

#loop through other table
for row in cursor2:
  if row[1] > watershed_areas[row[0]]:
    # if watershed_area < village_Area
    print "watershed {} is smaller".format(row[0])

5voto

alasdairg Puntos 1518

Necesitas anidar tus bucles de cursor de búsqueda para iterar a través de ambos al mismo tiempo, mientras relacionas las filas de alguna manera (para que arcpy sepa cuando está en la correcta, y detenga el bucle para comparar el valor). Por suerte ya tienes esos campos de ID que coinciden.

Esto debería servir para empezar a comparar los valores de la zona. Avísame si no funciona o si he puesto un error tipográfico.

cursor1 = arcpy.da.SearchCursor(fc1, ["OBJECTID", "Shape_Area"])
cursor2 = arcpy.da.SearchCursor(fc2, ["ws_id", "settlement_area"])

for row1 in cursor1:
    for row2 in cursor2:
        if row2[0] == row1[0]:  # if ws_id = OBJECTID, then check area
            if row2[1] < row1[1]:
                # if settlement_area < Shape_Area, print ID number
                print "settlement {} is larger".format(row2[0])

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