Suite

Sélection de caractéristiques croissantes par région à l'aide d'arcpy

Sélection de caractéristiques croissantes par région à l'aide d'arcpy


J'ai une classe d'entités surfaciques composée de parcelles se touchant les unes les autres et pour lesquelles les zones sont calculées dans la table attributaire (Figure a). Je souhaite sélectionner des polygones de manière itérative jusqu'à ce qu'un seuil de surface donné soit atteint.

Dans mon système, je souhaite sélectionner l'une des parcelles (par exemple, la plus petite) dans un premier temps (Figure b). Dans un deuxième temps, je souhaite appliquer une approche de croissance de région qui sélectionnera une parcelle voisine et l'ajoutera à la sélection actuelle (Figure c et d). Cependant, lorsque les trois premières parcelles sont sélectionnées, leur superficie totale équivaut à 1234 unités. Je veux que mon algorithme s'arrête lorsque la zone atteint, par exemple, 942 unités. Pour cela, je souhaite fractionner la dernière parcelle sélectionnée pour égaliser le seuil (figure e).

Je suis familier avec les trucs de base de pyhton et arcpy. Si quelqu'un pouvait me donner le cadre pour le mettre en œuvre.

data = "C:Usersln88615DocumentsGIS_datacadastral_computationmask2.shp" CadastreOut = "C:Usersln88615DocumentsGIS_datacadastral_computation" mask_layer = "mask_layer" arcpy. MakeFeatureLayer_management(data, mask_layer) field = "Matr" cursor = arcpy.SearchCursor(mask_layer) pour la ligne dans le curseur : geometry = row.getValue("Shape") out = str(row.getValue(field)) arcpy.SelectLayerByLocation_management (mask_layer , "BOUNDARY_TOUCHES",geometry) arcpy.CopyFeatures_management(mask_layer, CadastreOut + "Cadastre_" + out + ".shp")

Je viens de terminer de travailler sur un problème très similaire au vôtre pour développer une région. Étant donné une zone d'étude pleine de parcelles, j'avais besoin de créer des polygones couvrant la zone d'étude en combinant les parcelles en groupes d'au moins 1000 et pas plus de 5000. Le code n'est pas nécessairement le plus efficace mais il fait le travail et peut être utile à toi.

Dans le code ci-dessous, Join_Count serait analogue à votre zone de forme. L'idée générale est de sélectionner les voisins qui se touchent, puis si le montant de la somme dépasse le seuil, vous commencez à supprimer des fonctionnalités pour revenir sous le seuil.

Dans votre situation, une fois que vous revenez sous le seuil, vous déterminerez alors combien vous devez couper le polygone pour rajouter la zone pour atteindre votre seuil.

Je devrais également ajouter que le code ci-dessous est complètement automatisé sans interaction de l'utilisateur. Je commence simplement par le nombre le plus bas et je travaille.

#------------------------------------------------- -------------------------------------------------- ------ # Nécessité d'agréger des polygones avec de petits comptes aux voisins. # Étant donné que la classe d'entités doit être mise à jour en même temps que nous la parcourons, nous allons # continuellement ouvrir et fermer les curseurs pour obtenir le plus petit nombre, puis supprimer les entités qui y sont fusionnées. #------------------------------------------------- -------------------------------------------------- ------ geom = arcpy.Geometry() flds = ['[email protected]', '[email protected]', ​​'Join_Count'] wcCount = '"Join_Count" < ' + str(minThreshold) arcpy.MakeFeatureLayer_management(fcSJ, lyrSJ ) avec arcpy.da.SearchCursor(fcSJ, flds, wcCount) comme cur : pour la ligne dans trié(cur, key=operator.itemgetter(2)): #--------------- --------------- # Obtenez les fonctionnalités qui touchent. #------------------------------ oidsmall = row[1] arcpy.SelectLayerByLocation_management(lyrSJ, 'SHARE_A_LINE_SEGMENT_WITH', row[0 ]) Pause #---------------------------------------------- ----------------- # Assurez-vous que le nombre est inférieur au seuil maximum. S'il est trop élevé, supprimez les éléments en contact dans l'ordre décroissant. #------------------------------------------------- -------------- dictSelected = {} avec arcpy.da.SearchCursor(lyrSJ, ['[email protected]', ​​'Join_Count']) comme cur : pour la ligne dans cur : dictSelected[row[ 0]] = row[1] count = sum(dictSelected.values()) if count > maxThreshold : tandis que count > maxThreshold : s = trié(dictSelected.items(), key=operator.itemgetter(1), reverse=True ) del dictSelected[s[0][0]] count = sum(dictSelected.values()) #--------------------------- ---- # Resélectionnez les fonctionnalités à utiliser. #------------------------------- wcOID = 'OBJECTID dans (' pour k dans dictSelected.keys() : wcOID = wcOID + str(k) + ',' wcOID = wcOID[0:-1] + ')' arcpy.MakeFeatureLayer_management(fcSJ, lyrSJ, wcOID) #---------------- -------------- # Fusionner les fonctionnalités ensemble. #------------------------------ geomList = arcpy.Dissolve_management(lyrSJ, geom) #-------- ----------------------- # Maintenant, mettez à jour la classe d'entités. #------------------------------- avec arcpy.da.UpdateCursor(lyrSJ, flds) comme cur : pour la ligne dans cur : if row[1] == oidsmall: row[0] = geomList[0] row[2] = count cur.updateRow(row) else: cur.deleteRow()

J'ai décrit un processus et donné du code bâclé (je vous suggère de le terminer, de le déboguer et de le publier comme réponse lorsque vous avez terminé). Je pense à cela en trois étapes principales, (1) itérer à travers les parcelles (2) itérer à travers les voisins de la parcelle (3) diviser la dernière parcelle si nécessaire. La troisième étape est la plus difficile et je n'ai pas encore de solution à cela. Voici ce que j'ai pour l'instant :

import os import arcpy from arcpy import da #da.SearchCursor est nouveau à partir de 10.1 et est plus rapide parcels = "C:Usersln88615DocumentsGIS_datacadastral_computationmask2.shp" parcels2 = path + "cpymask2.shp" path = os.path.dirname(parcels) parcelPoints = path + "tempPnts.shp" outPnt = path + "tempPnt.shp" pnts_layer = "points" parcel_layer = "parcel" distanceTable = "distance" #J'ai supposé que c'était votre area field area_field = "Matr" thresholdArea = 1234 arcpy.FeatureToPoint_management(parcels_layer, parcelPoints)

Les points centraux doivent déterminer les voisins plus tard. La sélection par emplacement ne fonctionne pas aussi bien car elle vous limitera à ceux qui bordent et vous souhaitez également ordonner votre liste, pour laquelle la distance est un bon critère. Vous êtes maintenant prêt à parcourir les colis

avec arcpy.da.SearchCursor(parcels, ["FID", "area_field"]) comme curseur : pour la ligne dans le curseur : zone = ligne[1] si int(zone) 

Vous souhaitez joindre les distances aux parcelles d'origine. Votre table a les identifiants des points qui doivent toujours correspondre à ceux des colis. Selon la façon dont ceux-ci sont stockés (il ne semblait pas que vous utilisiez un gbd), vous pouvez ou non pouvoir vous fier à la correspondance de l'ID. Regardez vos données et envisagez d'ajouter un "parcel_ID" aux points si besoin est.

JoinField_management(parcels, "FID", distanceTable, "FID", "DISTANCE") #Trier les parcelles par distance, le curseur de recherche peut le faire arcpy.Sort_management(parcels, parcels2, "DISTANCE") voisinList = arcpy.da.SearchCursor (parcels2, ["DISTANCE", "area_field"]) pour le voisin dans la liste des voisins : si TotalAreaseuilArea: # (3) Do Split Function # en dehors de la boucle voisine supprimez la jointure arcpy.RemoveJoin_management (parcels) elseif int(area) > thresholdArea: # (3) Do Split Function