Oryginalny zestaw:
Utwórz jego pseudo-kopię (przeciągnij CNTRL w TOC) i połącz przestrzennie jeden do wielu za pomocą klonowania. W tym przypadku użyłem odległości 500m. Tabela wyników:
Usuń rekordy z tej tabeli, gdzie PAR_ID = PAR_ID_1 - łatwe.
Iteruj przez tabelę i usuwaj rekordy, gdzie (PAR_ID, PAR_ID_1) = (PAR_ID_1, PAR_ID) dowolnego rekordu powyżej. Nie tak łatwo, użyj acrpy.
Oblicz centroidy zlewni (UniqID = PAR_ID). Są węzłami lub siecią. Połącz je liniami za pomocą przestrzennej tabeli łączenia. To jest osobny temat z pewnością omawiany gdzieś na tym forum.
Poniższy skrypt zakłada, że tabela węzłów wygląda następująco:
gdzie MUID pochodzi z paczek, P2013 jest polem do podsumowania. W tym przypadku = 1 tylko do zliczania. [rcvnode] - wyjście skryptu do przechowywania identyfikatora grupy równego NODEREC pierwszego węzła w zdefiniowanej grupie / klastrze.
Łączy strukturę tabeli z wyróżnionymi ważnymi polami
Times przechowuje wagę łącza / krawędzi, tj. Koszt podróży od węzła do węzła. W tym przypadku równa się 1, dzięki czemu koszt podróży do wszystkich sąsiadów jest taki sam. [fi] i [ti] to kolejna liczba połączonych węzłów. Aby zapełnić tę tabelę, przeszukaj to forum na temat przypisywania zi do węzłów do połączenia.
Skrypt dostosowany do mojego własnego środowiska roboczego MXD. Musi zostać zmodyfikowany, na stałe wpisując nazwy pól i źródeł:
import arcpy, traceback, os, sys,time
import itertools as itt
scriptsPath=os.path.dirname(os.path.realpath(__file__))
os.chdir(scriptsPath)
import COMMON
sys.path.append(r'C:\Users\felix_pertziger\AppData\Roaming\Python\Python27\site-packages')
import networkx as nx
RATIO = int(arcpy.GetParameterAsText(0))
try:
def showPyMessage():
arcpy.AddMessage(str(time.ctime()) + " - " + message)
mxd = arcpy.mapping.MapDocument("CURRENT")
theT=COMMON.getTable(mxd)
ZNAJDŹ WARSTWĘ WĘZŁÓW
theNodesLayer = COMMON.getInfoFromTable(theT,1)
theNodesLayer = COMMON.isLayerExist(mxd,theNodesLayer)
POBIERZ WARSTWĘ
theLinksLayer = COMMON.getInfoFromTable(theT,9)
theLinksLayer = COMMON.isLayerExist(mxd,theLinksLayer)
arcpy.SelectLayerByAttribute_management(theLinksLayer, "CLEAR_SELECTION")
linksFromI=COMMON.getInfoFromTable(theT,14)
linksToI=COMMON.getInfoFromTable(theT,13)
G=nx.Graph()
arcpy.AddMessage("Adding links to graph")
with arcpy.da.SearchCursor(theLinksLayer, (linksFromI,linksToI,"Times")) as cursor:
for row in cursor:
(f,t,c)=row
G.add_edge(f,t,weight=c)
del row, cursor
pops=[]
pops=arcpy.da.TableToNumPyArray(theNodesLayer,("P2013"))
length0=nx.all_pairs_shortest_path_length(G)
nNodes=len(pops)
aBmNodes=[]
aBig=xrange(nNodes)
host=[-1]*nNodes
while True:
RATIO+=-1
if RATIO==0:
break
aBig = filter(lambda x: x not in aBmNodes, aBig)
p=itt.combinations(aBig, 2)
pMin=1000000
small=[]
for a in p:
S0,S1=0,0
for i in aBig:
p=pops[i][0]
p0=length0[a[0]][i]
p1=length0[a[1]][i]
if p0<p1:
S0+=p
else:
S1+=p
if S0!=0 and S1!=0:
sMin=min(S0,S1)
sMax=max(S0,S1)
df=abs(float(sMax)/sMin-RATIO)
if df<pMin:
pMin=df
aBest=a[:]
arcpy.AddMessage('%s %i %i' %(aBest,sMax,sMin))
if df<0.005:
break
lSmall,lBig,S0,S1=[],[],0,0
arcpy.AddMessage ('Ratio %i' %RATIO)
for i in aBig:
p0=length0[aBest[0]][i]
p1=length0[aBest[1]][i]
if p0<p1:
lSmall.append(i)
S0+=p0
else:
lBig.append(i)
S1+=p1
if S0<S1:
aBmNodes=lSmall[:]
for i in aBmNodes:
host[i]=aBest[0]
for i in lBig:
host[i]=aBest[1]
else:
aBmNodes=lBig[:]
for i in aBmNodes:
host[i]=aBest[1]
for i in lSmall:
host[i]=aBest[0]
with arcpy.da.UpdateCursor(theNodesLayer, "rcvnode") as cursor:
i=0
for row in cursor:
row[0]=host[i]
cursor.updateRow(row)
i+=1
del row, cursor
except:
message = "\n*** PYTHON ERRORS *** "; showPyMessage()
message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
message = "Python Error Info: " + str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()
Przykład wyjścia dla 6 grup:
Będziesz potrzebował pakietu witryny NETWORKX
http://networkx.github.io/documentation/development/install.html
Skrypt przyjmuje wymaganą liczbę klastrów jako parametr (6 w powyższym przykładzie). Wykorzystuje tabele węzłów i łączy, aby utworzyć wykres z jednakową wagą / odległością krawędzi przesuwu (Times = 1). Rozważa połączenie wszystkich węzłów o 2 i oblicza sumę [P2013] w dwóch grupach sąsiadów. Gdy osiągnięty jest wymagany stosunek, np. (6-1) / 1 przy pierwszej iteracji, kontynuuje się ze zmniejszonym stosunkiem docelowym, tj. 4 itd. Do 1. Punkty początkowe mają ogromne znaczenie, więc upewnij się, że twoje „końcowe” węzły siedzą na górze tabeli węzłów (sortowanie?) Zobacz pierwsze 3 grupy w przykładowym wyniku. Pomaga uniknąć „ścinania gałęzi” przy każdej kolejnej iteracji.
Dostosowanie skryptu do pracy z MXD:
- nie musisz importować WSPÓLNIE. To moja własna rzecz, która odczytuje moją własną tabelę środowiska, w której określono węzełNodesLayer, theLinksLayer, linksFromI, linksToI. Zamień odpowiednie linie na własne nazwy węzłów i warstw łączy.
- Pamiętaj, że pole P2013 może przechowywać wszystko, np. Liczbę najemców lub powierzchnię działki. Jeśli tak, możesz grupować wielokąty, aby pomieścić w przybliżeniu taką samą liczbę osób itp.