„Mapowanie pola” w ArcGIS 10 - ArcPy

13

Napisałem skrypt Pythona , który łączy przestrzennie i kilka prostych obliczeń. Mój problem polega na ustawieniu reguły scalania dla jednego określonego pola i pozostawieniu pozostałych pól bez zmian. Na przykład mam pole populacji, które po połączeniu przez lokalizację przestrzenną używa reguły scalania „Pierwszy”, która pobiera pierwsze wystąpienie liczby ludności. Chcę mieć możliwość ustawienia reguły scalania na „Suma”, aby dodać wartości populacji między wszystkimi wielokątami znajdującymi się w zasięgu przestrzennym innego wielokąta .

Zrobiłem intensywne majsterkowanie z mapami pól i obiektami mapowania pól, ale wydaje mi się, że nie działa poprawnie. W szczególności wypróbowałem metodę: popFieldMap.mergeRule = 'Sum', aby ustawić mergeRule, ale zawsze powraca ona do „First”.

Wszelkie pomysły, jak mogę programowo zmienić regułę scalania dla jednego pola w sprzężeniu przestrzennym?

Dzięki!

Oto mój kod (pamiętaj, że jest dość specyficzny dla moich danych i zawiera wiersze do testowania niektórych etapów skryptu):

import arcpy,sys,os

#Get the Files involved, set some variables.
SectorTable = sys.argv[1]
SectorShape = sys.argv[2]
MaxDev = sys.argv[3]
PopulationFC = sys.argv[4]
OutputFC = sys.argv[5]
DeviationField ="Angle_Deviation"
ID = "SectorID"
newID = "BP_ID"
mxd = arcpy.mapping.MapDocument('CURRENT')
df = arcpy.mapping.ListDataFrames(mxd)[0]

#Check to see if ID field types and name match
try:
    SectorShapeFields = arcpy.ListFields (SectorShape,ID)
    SectorTableFields = arcpy.ListFields (SectorTable,ID)
    arcpy.AddMessage("Finished Listing Fields")
    nameCheck = SectorShapeFields[0].name == SectorTableFields[0].name
    typeCheck = SectorShapeFields[0].type == SectorTableFields[0].type
except:
    arcpy.AddMessage("Failed to List Fields")

#If they do not match, add new fields to correct.
if not nameCheck:
    arcpy.AddMessage("Field Names do not match!  Adding new field to circumvent...")
if not typeCheck:
    arcpy.AddMessage("Field Types do not match!  Adding new field to circumvent...")
    if SectorShapeFields[0].type != SectorTableFields[0].type:
        try:
            arcpy.AddField_management(SectorShape, newID, SectorTableFields[0].type,10)
            arcpy.CalculateField_management(SectorShape, newID,"!"+ID+"!", "PYTHON")
            arcpy.RefreshTOC()
        except:
            arcpy.AddMessage("Error in Creating Field. Does it already exist?")


#Join the two together
arcpy.AddMessage("Performing Join")
arcpy.AddJoin_management( SectorShape, newID, SectorTable, ID)
arcpy.SelectLayerByAttribute_management (SectorShape,"NEW_SELECTION","Angle_Deviation>"+str(MaxDev))
df.zoomToSelectedFeatures()

#Field Mapping ...
myMap = arcpy.FieldMappings()
myMap.addTable(PopulationFC)
myMap.addTable(SectorShape)

#Verify the field merge rule for the pop10 field.
fIndex = myMap.findFieldMapIndex("POP10")
arcpy.AddMessage(str(fIndex))
popFieldMap = myMap.getFieldMap(fIndex)
arcpy.AddMessage(str(popFieldMap.mergeRule))
popFieldMap.mergeRule = 'Sum'
arcpy.AddMessage(str(popFieldMap.mergeRule))
popFieldMap2 = popFieldMap

##Test
fIndex = myMap.findFieldMapIndex("POP10")
arcpy.AddMessage(str(fIndex))
popFieldMap = myMap.getFieldMap(fIndex)
arcpy.AddMessage(str(popFieldMap.mergeRule))

#Perform Spatial Join
arcpy.AddMessage("Performing Spatial Join")
arcpy.SpatialJoin_analysis(SectorShape, PopulationFC, OutputFC,"JOIN_ONE_TO_ONE","",myMap,"INTERSECT")

#Add Result and Symbolize
arcpy.mapping.AddLayer(df,arcpy.mapping.Layer(OutputFC))
translayer = arcpy.mapping.ListLayers(mxd,"",df)[0]
translayer.transparency = 50

arcpy.RefreshActiveView()

EDYCJA - poniżej znajduje się kod z wdrożonym rozwiązaniem!

import arcpy,sys,os

#Get the Files involved, set some variables.
SectorTable = sys.argv[1]
SectorShape = sys.argv[2]
MaxDev = sys.argv[3]
PopulationFC = sys.argv[4]
OutputFC = sys.argv[5]
DeviationField ="Angle_Deviation"
ID = "SectorID"
newID = "BP_ID"
mxd = arcpy.mapping.MapDocument('CURRENT')
df = arcpy.mapping.ListDataFrames(mxd)[0]

#Check to see if ID field types and name match
try:
    SectorShapeFields = arcpy.ListFields (SectorShape,ID)
    SectorTableFields = arcpy.ListFields (SectorTable,ID)
    arcpy.AddMessage("Finished Listing Fields")
    nameCheck = SectorShapeFields[0].name == SectorTableFields[0].name
    typeCheck = SectorShapeFields[0].type == SectorTableFields[0].type
except:
    arcpy.AddMessage("Failed to List Fields")

#If they do not match, add new fields to correct.
if not nameCheck:
    arcpy.AddMessage("Field Names do not match!  Adding new field to circumvent...")
if not typeCheck:
    arcpy.AddMessage("Field Types do not match!  Adding new field to circumvent...")
    if SectorShapeFields[0].type != SectorTableFields[0].type:
        try:
            arcpy.AddField_management(SectorShape, newID, SectorTableFields[0].type,10)
            arcpy.CalculateField_management(SectorShape, newID,"!"+ID+"!", "PYTHON")
            arcpy.RefreshTOC()
        except:
            arcpy.AddMessage("Error in Creating Field. Does it already exist?")


#Join the two together
arcpy.AddMessage("Performing Join")
arcpy.AddJoin_management( SectorShape, newID, SectorTable, ID)
arcpy.SelectLayerByAttribute_management (SectorShape,"NEW_SELECTION","Angle_Deviation>"+str(MaxDev))
df.zoomToSelectedFeatures()

#Field Mapping ...
myMap = arcpy.FieldMappings()
myMap.addTable(PopulationFC)
myMap.addTable(SectorShape)

#Verify the field merge rule for the pop10 field.
fIndex = myMap.findFieldMapIndex("POP10")
arcpy.AddMessage(str(fIndex))
popFieldMap = myMap.getFieldMap(fIndex)
arcpy.AddMessage(str(popFieldMap.mergeRule))
popFieldMap.mergeRule = 'Sum'
arcpy.AddMessage(str(popFieldMap.mergeRule))

myMap.replaceFieldMap(fIndex,popFieldMap)

##Test
fIndex = myMap.findFieldMapIndex("POP10")
arcpy.AddMessage(str(fIndex))
popFieldMap = myMap.getFieldMap(fIndex)
arcpy.AddMessage(str(popFieldMap.mergeRule))

#Perform Spatial Join
arcpy.AddMessage("Performing Spatial Join")
arcpy.SpatialJoin_analysis(SectorShape, PopulationFC, OutputFC,"JOIN_ONE_TO_ONE","",myMap,"INTERSECT")

#Add Result and Symbolize
arcpy.mapping.AddLayer(df,arcpy.mapping.Layer(OutputFC))
translayer = arcpy.mapping.ListLayers(mxd,"",df)[0]
translayer.transparency = 50

arcpy.RefreshActiveView()
Piksel
źródło
1
Czy możesz opublikować swój skrypt?
blah238
Jasne, pozwól mi to opublikować. Pamiętaj, że niektóre części mojego kodu wstawiłem jako etapy testowania.
Pixel
Czy sprawdziłeś typ danych populationpola?
Alex Markov
moją pierwszą skłonnością jest to, że pole pop może być tekstem.
Brad Nesom
Typ pola to „Długi”, więc powinno być możliwe wykonanie sumowania matematycznego, prawda?
Pixel

Odpowiedzi:

14

Myślę, że musisz go użyć FieldMappings.replaceFieldMap, aby przetrwał. Przykład z tematu pomocy Mapowanie pól wejściowych na pola wyjściowe :

# First get the TRACT2000 fieldmap. Then add the TRACTCODE field
#   from Blocks2 as an input field. Then replace the fieldmap within
#   the fieldmappings object.
#
fieldmap = fieldmappings.getFieldMap(fieldmappings.findFieldMapIndex("TRACT2000"))
fieldmap.addInputField(fc2, "TRACTCODE")
fieldmappings.replaceFieldMap(fieldmappings.findFieldMapIndex("TRACT2000"), fieldmap)

Inna myśl jest taka, że ​​podczas testowania map pól lubię używać narzędzia skryptowego i niestandardowego zachowania narzędzia skryptowego, dzięki czemu mogę wizualnie sprawdzić mapę pola zamiast próbować dekodować wytwarzane przez nich szalone długie łańcuchy.

Przykładowa ToolValidatorklasa, z której wyciągnąłem wniosek, że tak, replaceFieldMapjest wymagana do utrwalenia wartości parametru:

class ToolValidator:
  """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."""
    import arcpy
    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 (not self.params[0].hasBeenValidated
    or not self.params[1].hasBeenValidated):
        targetFeatures = self.params[0].value
        joinFeatures = self.params[1].value
        fieldMappings = arcpy.FieldMappings()
        if targetFeatures:
            fieldMappings.addTable(targetFeatures)
            if joinFeatures:
                fieldMappings.addTable(joinFeatures)
                idx = fieldMappings.findFieldMapIndex("PRIORITY")
                fieldMap = fieldMappings.getFieldMap(idx)
                fieldMap.mergeRule = 'Sum'
                fieldMappings.replaceFieldMap(idx, fieldMap) # if this line is commented out, the merge rule reverts to 'First'
        self.params[3].value = fieldMappings.exportToString()
    return

  def updateMessages(self):
    """Modify the messages created by internal validation for each tool
    parameter.  This method is called after internal validation."""
    return
blah238
źródło
Fajna myśl, pozwól mi zajrzeć i zobaczyć, gdzie zastosuję to w moim skrypcie. Wrócę z moimi ustaleniami
Pixel
2
To była świetna odpowiedź, która rozwiązała problem. Dziękujemy również za podanie szczegółowych informacji na temat przyczyny problemu! :)
Pixel