7 votos

¿Valores espaciales Únete rendimiento nulo en ArcPy?

Estoy escribiendo un script automatizado para hacer algo de procesamiento de datos de puntos de dirección. Una etapa del proceso es recuperar 19 campos de información de diversas polígono capas que los Puntos de Dirección, y rellenar pre-creados los campos en la Dirección de la clase de entidad. De los 19 campos, la mayoría son de Texto, pero un par de Dobles.

En lugar de codificar todos los 19, estoy usando un SearchCursor para hacer un ciclo a través de una tabla de todos los 19 campos, cada uno con su tipo, la longitud, la característica de origen de clase, y el nombre de campo de origen. El SearchCursor primero se crea el campo a las especificaciones y, a continuación, ejecuta el código (abajo) para recuperar el campo de la fuente de datos. La característica de origen de las clases se propagan a través de un SDE y una geodatabase construidos a propósito para este proceso.

De estos 19 campos me estoy uniendo, 9 campos están fallando, y todos están fallando en la misma manera - la inicial de unión Espacial es devolver un valor Null. Esto debería devolver una clase de entidad de punto con la dirección del punto de FID y el campo de destino valor en un campo llamado "Scratch_Da". Sobre el problema de los campos de la unión Espacial de las salidas, "Scratch_Da" es NULO todo el camino hacia abajo. La mayoría de los datos del problema de las fuentes están en el origen de la SDE, pero que se muevan a la geodatabase no resolver los problemas, y dos problema son los campos que vienen de la misma fuente de datos como un campo que funciona bien. He comprobado que la mayoría de la dirección de los puntos están dentro de la asignatura de polígonos y todos los nombres de campo y tipos son correctos.

Alguien ha visto a un ArcPy Espacial Unirse a actuar de esta manera antes?

Aquí está el Campo Espacial bucle de Recuperación:

with arcpy.da.SearchCursor("X:\AddressStage.gdb\SFRFields", SFRList) as cursor:
    for row in cursor:
            fname = row[0]
            ftype = row[1]
            fleng = row[2]
            fscal = row[3]
            fsrc = row[4]
            lyr = row[5]
            fsfld = row[6]
            #create fields with parameters given
            arcpy.AddField_management("CPLayer", fname, ftype, fleng, fscal, fleng)
            #if field source value is PARSE:
            if fsrc == "PARSE":
                #use continue to start next iteration
                continue
            elif fsrc!= "BLANK":
                #Begin spatial field retrieval code
                #Start by selecting CPLayer features with proper spatial relationship
                arcpy.SelectLayerByLocation_management("CPLayer", "WITHIN", fsrc)
                loopStart = time.time()
                runTime = loopStart - startTime
                log.write("{0}:\n".format(fname))
                log.write("{0} seconds elapsed in script.\n".format(runTime))
                print("Beginning retrieval of field {0}. {1} seconds elapsed in script.".format(fname, runTime))
                #perform SFR on nested field, using parameters in SFRFields
                #Layer to be calculated
                InLayer = "CPLayer"
                #InField: Layer which will receive final data
                InField = fname
                #SourceLayer: Layer which contributes data.
                SourceLayer = fsrc
                #SourceField: source field
                SourceField = fsfld
                #SpatShip = spatial relationship - same as Spatial Join tool
                SpatShip = "WITHIN"
                #MergeRule: How to handle one-to-many relationships
                if ftype == "TEXT":
                    MergeRule = "FIRST"
                elif ftype == "DOUBLE":
                    MergeRule = "SUM"
                #SearchDist: search distance
                SearchDist = 0

                #parse name of SJ features
                SJFeat = str("SJ_" + lyr + "_" + fname)
                log.write("Output feature class: {0}\n".format(SJFeat))

                #Create a field map that changes the InField name to Scratch_Da, and
                #uses Sourcefield as input.
                #This is so the eventual spatial join features have only the TARGET_FID
                #and the target data.
                InpFM = arcpy.FieldMap()
                ScratchFMS = arcpy.FieldMappings()

                InFieldList = arcpy.ListFields(InLayer)
                for field in InFieldList:
                    if field.name == InField:
                        InpFM.addInputField(SourceLayer, SourceField)
                        InpFM.mergeRule = MergeRule
                        #set output field name to Scratch_Data
                        scratch_name = InpFM.outputField
                        scratch_name.name = "Scratch_Da"
                        InpFM.outputField = scratch_name
                        ScratchFMS.addFieldMap(InpFM)

                #spatial join to scratch features
                sjTime = time.time()
                arcpy.SpatialJoin_analysis(InLayer, SourceLayer, SJFeat, "JOIN_ONE_TO_ONE",
                                          "KEEP_ALL", ScratchFMS, SpatShip, SearchDist)
                runTime = time.time() - sjTime
                log.write("Spatial join completed. {0} seconds elapsed in spatial join.\n".format(runTime))

                #create dictionary object for join purposes.
                #the key will be the Target FID, and the value is the target field value.
                JoinDict = {}
                noneCount = 0
                with arcpy.da.SearchCursor(SJFeat, ("TARGET_FID","Scratch_Da")) as cursor:
                    for row in cursor:
                        fid = row[0]
                        val = row[1]
                        if val == None and ftype == "DOUBLE":
                            val = 0
                            noneCount += 1
                        elif ftype == "DOUBLE" and val <> None:
                            val = float(row[1])
                        elif ftype == "TEXT" and val <> None:
                            val = str(row[1])[:fleng]
                        elif ftype == "TEXT" and val == None:
                            val = "FAIL"
                            noneCount += 1
                        JoinDict[fid] = val

                #Update cursor, hinges on dictionary
                with arcpy.da.UpdateCursor(InLayer, ("OID@", InField)) as cursor:
                    #reach into dictionary using FID values
                    for row in cursor:
                        #Search for dictionary item with feature's FID as key
                        val = JoinDict[row[0]]
                        row[1] = str(val)
                        cursor.updateRow(row)

                #delete ScratchSJ file.
                #arcpy.Delete_management("ScratchSJ")
                loopTime = time.time() - loopStart
                log.write("Field retrieval completed. {0} seconds elapsed in loop.\n".format(loopTime))
                log.write("{0} None values retrieved.\n\n".format(noneCount))
                #end of SFR loop

Actualización 03/21/2016: El script se sigue produciendo la NULA comportamiento. El problema de los campos:

  • 4 son de texto, de longitudes de 4 a 20 caracteres. La entrada y salida de las longitudes de partido.
  • 4 son dobles. Longitud y precisión partido especificaciones de salida, pero las entradas son enteros cortos y no puedo cambiar eso. Sin embargo, la inclusión de los campos de texto entre el campo de problema me llevan a creer que el tipo de campo o la longitud no es un problema.
  • 2 campos de texto, vienen de la misma fuente de datos como otro campo de texto que funciona a la perfección.
  • He exportado un solo problema de los campos de fila de la tabla que controla el Campo Espacial bucle de Recuperación, y corrió a través del mismo código. El NULO comportamiento persistió cuando hice esto con tanto Texto y haga Doble campos.

4voto

orca Puntos 6807

Recientemente he tenido algunos problemas para conseguir mi espacial se unen para trabajar, en temas similares a los que fueron. Yo no estoy familiarizado con el campo de asignación suficiente para saber si la forma en que son la asignación de campos es posible o no. Todo lo que sé es que esta es la manera que tengo de asignación de campo (con una regla de combinación en varios campos) a trabajar para mí.

    # Copy features to a new layer
    arcpy.CopyFeatures_management(target,outputfeatureAPT,config_keyword="#",spatial_grid_1="0",spatial_grid_2="0",spatial_grid_3="0")
    arcpy.CopyFeatures_management(joinFeatureSTUD,outputfeatureSTUD,config_keyword="#",spatial_grid_1="0",spatial_grid_2="0",spatial_grid_3="0")

    # Delete fields in copy features before you spatial join
    arcpy.DeleteField_management(outputfeatureAPT,drop_field="APT;ADDRESS;PA;TYPE;STATUS;LIU;MRU;UNITS;CLASS;LOW_INCOME;APP_NUM;ELEM;INT_;MID;HIGH;ELEM_STUD;INT_STUD;MID_STUD;HIGH_STUD;TOT_STUD;ELEM_YLD;INT_YLD;MID_YLD;HIGH_YLD;TOT_YLD;LAST_EDIT;NOTES")

    # The following inputs are layers or table views: "stud_0915_1"
    arcpy.DeleteField_management(outputfeatureSTUD,drop_field="Loc_name;Status;Score;Match_type;X;Y;Match_addr;Side;Pct_along;ARC_Street;ARC_Zip;ARC_City;ARC_Postal;ISD;STUD_ID;NAME;F_NAME;L_NAME;ADDRESS;ZIP;CITY;CAMPUS_ID;SCHOOL;GRADE;ETHNICITY;ED;BIL;PA;RESIDE;CLASS;SUB;EE_PK;EE;PK;KG;GRD1;GRD2;GRD3;GRD4;GRD5;GRD6;GRD7;GRD8;GRD9;GRD10;GRD11;GRD12;AMER_IND;ASIAN;BLACK;HISPANIC;WHITE;PACIFIC;MULTI;BIL_EE;BIL_PK;BIL_KG;BIL_GRD1;BIL_GRD2;BIL_GRD3;BIL_GRD4;BIL_GRD5;BIL_GRD6;BIL_ELEM;BIL_INT;BIL_MID;BIL_HIGH;ED_ELEM;ED_INT;ED_MID;ED_HIGH;AMER_IND_ELEM;AMER_IND_INT;AMER_IND_MID;AMER_IND_HIGH;ASIAN_ELEM;ASIAN_INT;ASIAN_MID;ASIAN_HIGH;BLACK_ELEM;BLACK_INT;BLACK_MID;BLACK_HIGH;HISPANIC_ELEM;HISPANIC_INT;HISPANIC_MID;HISPANIC_HIGH;WHITE_ELEM;WHITE_INT;WHITE_MID;WHITE_HIGH;PACIFIC_ELEM;PACIFIC_INT;PACIFIC_MID;PACIFIC_HIGH;MULTI_ELEM;MULTI_INT;MULTI_MID;MULTI_HIGH;SF;MF;EXEMPT_65;RENTER")

    # Create a new fieldmappings and add the two input feature classes.
    fms = arcpy.FieldMappings()
    fms.addTable(outputfeatureAPT)
    fms.addTable(outputfeatureSTUD)
    ELEMSumIndex = fms.findFieldMapIndex("ELEM")
    INT_SumIndex = fms.findFieldMapIndex("INT_")
    MIDSumIndex = fms.findFieldMapIndex("MID")
    HIGHSumIndex = fms.findFieldMapIndex("HIGH")
    TOT_STUDSumIndex = fms.findFieldMapIndex("TOT_STUD")

    # Create the required FieldMap and FieldMappings objects
    fm_apt_poly_APT_ID = arcpy.FieldMap()
    fm_stud_ELEM = fms.getFieldMap(ELEMSumIndex)
    fm_stud_INT_ = fms.getFieldMap(INT_SumIndex)
    fm_stud_MID = fms.getFieldMap(MIDSumIndex)
    fm_stud_HIGH = fms.getFieldMap(HIGHSumIndex)
    fm_stud_TOT_STUD = fms.getFieldMap(TOT_STUDSumIndex)
    fms = arcpy.FieldMappings()

    # Create the required FieldMap and FieldMappings objects
    fm_apt_poly_APT_ID = arcpy.FieldMap()
    fm_stud_ELEM = arcpy.FieldMap()
    fm_stud_INT_ = arcpy.FieldMap()
    fm_stud_MID = arcpy.FieldMap()
    fm_stud_HIGH = arcpy.FieldMap()
    fm_stud_TOT_STUD = arcpy.FieldMap()
    fms = arcpy.FieldMappings()

    # Get the field names for both original files
    apt_poly_APT_ID = "APT_ID"
    stud_ELEM = "ELEM"
    stud_INT_ = "INT_"
    stud_MID = "MID"
    stud_HIGH = "HIGH"
    stud_TOT_STUD = "TOT_STUD"

    # Add fields to their corresponding FieldMap objects
    fm_apt_poly_APT_ID.addInputField(outputfeatureAPT, "APT_ID")
    fm_stud_ELEM.addInputField(outputfeatureSTUD, "ELEM")
    fm_stud_INT_.addInputField(outputfeatureSTUD, "INT_")
    fm_stud_MID.addInputField(outputfeatureSTUD, "MID")
    fm_stud_HIGH.addInputField(outputfeatureSTUD, "HIGH")
    fm_stud_TOT_STUD.addInputField(outputfeatureSTUD, "TOT_STUD")

    # Set the output field properties for both FieldMap objects
    apt_poly_APT_ID = fm_apt_poly_APT_ID.outputField
    apt_poly_APT_ID.name = "APT_ID"
    fm_apt_poly_APT_ID.outputField = apt_poly_APT_ID

    stud_ELEM = fm_stud_ELEM.outputField
    stud_ELEM.name = "ELEM"
    stud_ELEM.aliasName = "ELEM"
    fm_stud_ELEM.outputField = stud_ELEM

    stud_INT_ = fm_stud_ELEM.outputField
    stud_INT_.name = "INT_"
    stud_INT_.aliasName = "INT_"
    fm_stud_INT_.outputField = stud_INT_

    stud_MID = fm_stud_MID.outputField
    stud_MID.name = "MID"
    stud_MID.aliasName = "MID"
    fm_stud_MID.outputField = stud_MID

    stud_HIGH = fm_stud_HIGH.outputField
    stud_HIGH.name = "HIGH"
    stud_HIGH.aliasName = "HIGH"
    fm_stud_HIGH.outputField = stud_HIGH

    stud_TOT_STUD = fm_stud_TOT_STUD.outputField
    stud_TOT_STUD.name = "TOT_STUD"
    stud_TOT_STUD.aliasName = "TOT_STUD"
    fm_stud_TOT_STUD.outputField = stud_TOT_STUD

    # Set the merge rule to sum and then replace the old field map in the mappings object with the updated one
    fm_stud_ELEM.mergeRule = "SUM"
    fm_stud_INT_.mergeRule = "SUM"
    fm_stud_MID.mergeRule = "SUM"
    fm_stud_HIGH.mergeRule = "SUM"
    fm_stud_TOT_STUD.mergeRule = "SUM"
    fms.addFieldMap(fm_apt_poly_APT_ID)
    fms.addFieldMap(fm_stud_ELEM)
    fms.addFieldMap(fm_stud_INT_)
    fms.addFieldMap(fm_stud_MID)
    fms.addFieldMap(fm_stud_HIGH)
    fms.addFieldMap(fm_stud_TOT_STUD)

    # Spatial Join Sample Code
    # SpatialJoin_analysis (target_features, join_features, out_feature_class, {join_operation}, {join_type}, {field_mapping}, {match_option}, {search_radius}, {distance_field_name})
    # Process: Spatial Join
    arcpy.AddMessage("Performing Student Spatial Join")
    arcpy.SpatialJoin_analysis(outputfeatureAPT, outputfeatureSTUD, output2, "JOIN_ONE_TO_ONE", "KEEP_ALL", fms, "INTERSECT", "", "")
    arcpy.AddMessage("Just performed Student Spatial Join")

    # Join the output to your apt_poly_xxxx by the APT_ID field
    # JoinField_management Sample Code
    # arcpy.JoinField_management(Input Feature, "Field Name", "join table", "join field", {["fields"]})
    arcpy.AddJoin_management(target, "APT_ID", output2, "APT_ID","")
    arcpy.AddMessage("Just performed Student Table Join")

    # Calculate Field_management Sample Code
    # arcpy.CalculateField_management(Input Feature, "Field Name", expression, "expression type", code block)

    # Process: Calculate Field, with a string index in the expression used to isolate the feature class name
    arcpy.CalculateField_management(target, targetname + ".ELEM_STUD", '!'+output2[74:]+'.ELEM!', "PYTHON_9.3")
    # Process: Calculate Field (2)
    arcpy.CalculateField_management(target, targetname + ".INT_STUD", '!'+output2[74:]+'.INT_!', "PYTHON_9.3")
    # Process: Calculate Field (3)
    arcpy.CalculateField_management(target, targetname + ".MID_STUD", '!'+output2[74:]+'.MID!', "PYTHON_9.3")
    # Process: Calculate Field (4)
    arcpy.CalculateField_management(target, targetname + ".HIGH_STUD", '!'+output2[74:]+'.HIGH!', "PYTHON_9.3")
    # Process: Calculate Field (5)
    arcpy.CalculateField_management(target, targetname + ".TOT_STUD", '!'+output2[74:]+'.TOT_STUD!', "PYTHON_9.3")

    # Remove the Join
    arcpy.RemoveJoin_management(target, "")

Yo eneded borrar todos los campos de mi destino y unirse a la característica de exepto el onese que necesitaba, y luego manualmente campo asignado el resto. Yo estaba trabajando con 6 campos y era un dolor, por lo que entiendo la idea de tratar de evitar hacerlo de esta forma, con 19 de los campos. Pero he aquí cómo se trabajó para mí.

0voto

Andy Bradford Puntos 120

El éxito de este código se inspira en el código publicado por @forrestchev en su respuesta. Por favor, dirija cualquier upvotes su respuesta-tengo la intención de esta respuesta como un comentario de los suyos, en lugar de una respuesta en sí misma; yo no podía tener un multi-línea fragmento de código para ser legible en un comentario.

Yo todavía no entiendo exactamente por qué esto funcionó correctamente, pero este código, reemplazando el 17 de líneas de código siguientes #Create a field map... en mi pregunta del código, rellena el campo con éxito y sin valores null:

#Create field map à la forrestchev
ScratchFMS = arcpy.FieldMappings()
ScratchFMS.addTable(SourceLayer)
SourceIndex = ScratchFMS.findFieldMapIndex(SourceField)
SourceFM = ScratchFMS.getFieldMap(SourceIndex)
ScratchFMS = arcpy.FieldMappings()
SourceFM.addInputField(SourceLayer, SourceField)
SourceFM.mergeRule = MergeRule

ScratchFMS.addFieldMap(SourceFM)

Y la unión espacial de código:

arcpy.SpatialJoin_analysis(
    InLayer,
    SourceLayer,
    SJFeat,
    "JOIN_ONE_TO_ONE",
    "KEEP_ALL",
    ScratchFMS,
    SpatShip,
    SearchDist
)

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