ArcPy ile çokgenleri * n * eşit sayıdaki gruplara bölmek?


10

İş için görevlerimden biri, parselleri gruplara ayırmak. Bu gruplar aracılar tarafından mülk sahipleriyle konuşmak için kullanılacaktır. Amaç, birbirine yakın olan parselleri birlikte gruplayarak acentenin işini kolaylaştırmak ve işlerin eşit olarak dağıtılması için parselleri eşit sayılara bölmektir. Ajan sayısı birkaçdan 10'a kadar değişebilir.

Şu anda bu görevi manuel olarak gerçekleştiriyorum, ancak mümkünse süreci otomatikleştirmek istiyorum. Çeşitli ArcGIS araçlarını keşfettim, ancak hiçbiri ihtiyacıma uygun görünmüyor. near_analysisÇokgenleri kullanan ve seçen bir komut dosyası (python) denedim , ancak oldukça rastgele ve daha sonra düzeltmek için beni daha uzun sürdüğünden daha uzun süren yarı doğru bir sonuç elde etmek sonsuza kadar sürüyor.

Bu görevi otomatikleştirmek için güvenilir bir yöntem var mı?

Sonuç örneği (umarım sarı gördüğümüz bölünme olmadan):

Bölünmüş Parseller


Konum tahsisi analizine baktınız mı? help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/...
floem

Gruplama Analizini (Mekansal İstatistikler) denediniz mi?
FelixIP

Ayrıca kullandığım gerçek prosedürün sahte bir kodunu gönderdim, bkz. Gis.stackexchange.com/questions/123289/…
FelixIP

@crmackey Cevabımın bağlantısını takdir ediyorum, ancak bağlantılı kodu (çokgenleri bölmek) bu soruna (çokgenleri gruplamak) uyacak şekilde nasıl ayarlayabileceğinizden emin değilim.
phloem

Yanıtlar:


4

Orijinal set:

resim açıklamasını buraya girin

Pseudo-copy (TOC içinde CNTRL-drag) oluşturun ve klonla mekansal bire birleştirme yapın. Bu durumda 500m mesafe kullandım. Çıktı tablosu:

resim açıklamasını buraya girin

  1. PAR_ID = PAR_ID_1 - kolay olan bu tablodan kayıtları kaldırın.

  2. Tabloda yineleme yapın ve üzerindeki kayıtları (PAR_ID, PAR_ID_1) = (PAR_ID_1, PAR_ID) burada kaldırın. O kadar kolay değil, acrpy kullanın.

Havza sentroidlerini hesaplayın (UniqID = PAR_ID). Bunlar düğüm veya ağdır. Uzamsal birleştirme tablosu kullanarak bunları çizgilerle bağlayın. Bu, kesinlikle bu forumda bir yerde ele alınan ayrı bir konudur.

resim açıklamasını buraya girin

Aşağıdaki komut dosyası düğüm tablosunun şöyle göründüğünü varsayar: resim açıklamasını buraya girin

MUID'nin parsellerden geldiği yerde, P2013 özetlenecek bir alandır. Bu durumda sadece sayım için = 1. [rcvnode] - tanımlanan grup / kümedeki ilk düğümün grup kimliğine eşit NODEREC'i depolayan komut dosyası çıktısı.

Önemli tabloların vurgulandığı bağlantılar tablosu yapısı

resim açıklamasını buraya girin

Times, bağlantı / kenar ağırlığını, yani düğümden düğüme seyahat maliyetini depolar. Bu durumda 1'e eşittir, böylece tüm komşulara seyahat maliyeti aynıdır. [fi] ve [ti] bağlı düğümlerin sıralı sayısıdır. Bu tabloyu doldurmak için, bağlantı kurmak için düğümlerden ve düğümlere nasıl atayacağınız konusunda bu forumda arama yapın.

Kendi tezgah mxd için özelleştirilmiş komut dosyası. Alanlar ve kaynaklar isimlendirilmeniz için değiştirilmeli, kodlanmalıdır:

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)

DÜĞÜM KATMANI BUL

theNodesLayer = COMMON.getInfoFromTable(theT,1)
theNodesLayer = COMMON.isLayerExist(mxd,theNodesLayer)

LAYKS LAYER ALIN

    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()

6 grup için çıktı örneği:

resim açıklamasını buraya girin

NETWORKX site paketine ihtiyacınız olacak http://networkx.github.io/documentation/development/install.html

Komut dosyası gerekli sayıda kümeyi parametre olarak alır (yukarıdaki örnekte 6). Eşit ağırlık / seyahat kenarları mesafesine sahip bir grafik yapmak için düğümler ve bağlantı tabloları kullanır (Times = 1). Tüm düğümlerin kombinasyonunu 2 ile ele alır ve iki komşu grupta [P2013] toplamını hesaplar. Gerekli oran elde edildiğinde, örneğin ilk yinelemede (6-1) / 1, oran 1, yani 4 vb. İle 1'e kadar devam eder. Başlangıç ​​noktaları çok önemlidir, bu yüzden 'uç' düğümlerinizin üstte oturduğundan emin olun (sıralama?) Örnek çıktıdaki ilk 3 gruba bakın. Bir sonraki yinelemede 'dal kesmeyi' önlemeye yardımcı olur.

MXD'den çalışmak için komut dosyası özelleştirme:

  1. ithalat COMMON gerekmez. Bu benim kendi şeyim, burada kendi ortam tabloumu okuyan, buradaNodesLayer, theLinksLayer, linksFromI, linksToI belirtildi. İlgili satırları kendi düğüm ve bağlantı katmanları adınızla değiştirin.
  2. P2013 alanının, kiracı sayısı veya parsel alanı gibi her şeyi saklayabileceğini unutmayın. Öyleyse çokgenleri yaklaşık eşit sayıda kişi vb. Alacak şekilde kümeleyebilirsiniz.

Gerçekte düğümler ve bağlantılar katmanlar sadece görsel şeylerdir. Uzamsal birleştirmenin temizlenmiş tablosu, bağlantı tablosunun yerini kolayca alabilir, çünkü ve'den düğümlere zaten atanmıştır. Çokgenler tablosu, kolayca düğüm tablosu olarak hizmet edebilir, sadece ReceivingNode alanını ekleyin ve ondan sıralı sayıları 'bağlantılar' [FromI] ve [ToI] 'ye geri aktarın.
FelixIP

Bu iyi görünüyor. Cevabınız için çok teşekkürler. Sadece nasıl olduğunu değil, nedenini daha fazla açıklayabilir misiniz? Kodunuzdaki yorumlar çok büyük olurdu.
Emil Brundage

Lütfen sorunuzun önceki yorumunda köprüyü takip edin. Bu yaklaşımı açıklamaya çalıştım, eğer 'neden' demekse. Düğümün başlatılmasının önemi hakkındaki yorumumu geri çekiyorum, çünkü Q'nuza cevap gönderdikten sonra, senaryoyu öldürmeye çalışan kayıt sırasını rastgele değiştirdim. Hiçbir şey olmadı, hala makul sonuçlar verdi.
FelixIP

Uzamsal birleştirme tablosunu temizlemek için NETWORKX eşit kenar [2,0] 'nın yönlendirilmemiş grafiğindeki kenar / bağlantı [0,2] olduğundan PAR_ID = PAR_ID_1 silmek yeterlidir. Güncellenmiş komut dosyası gönderebilirim, itibarımı etkileyip etkilemeyeceğinden emin değilim
FelixIP

@EmilBrundage bir göz atın, neden soru gis.stackexchange.com/questions/165057/…
FelixIP

2

Hedefinize ulaşmak için "Grup Analizi" aracını kullanmalısınız. Bu araçlar @ phloem'in işaret ettiği gibi "mekansal istatistikler" araç kutusundan harika bir araçtır. Ancak, verilerinize ve sorununuza uyum sağlamak için araca ince ayar yapmalısınız. Gönderdiğinize benzer bir senaryo oluşturdum ve yanıtı hedefinize yakın buldum.

İpucu: Aracı çalıştırdığımda ArcGIS 10.2 kullanarak eksik python paketi olan "altı" dan şikayetçiydi. Bu yüzden önce yüklediğinizden emin olun Link

Adımlar:

  1. Benzersiz bir değeri tutmak için çokgen sınıfınıza bir alan ekleyin
  2. Kısa türünde başka bir alan ekleyin, örneğin "SameGroup"
  3. tüm satırlar için bu alana 1 atamak için alan hesap makinesi. bir satırı 2 olarak değiştirin. Eklenen Alan

  4. "Grup Analizi" araç parametrelerini şu şekilde ayarlayın: Grup Analizi

"Komşu Sayısı" parametresini ihtiyacınıza göre değiştirmeye çalışın.

Sonuç Anlık Görüntüler:

Örnek Giriş Çokgenleri

Grup Analizinin Sonucu


2
Daha önce Grup Analizine baktım. Mekânsal ile ilgilenir, ancak söyleyebildiğim kadar sayılmaz. Belgeleri okumaktan, örneğinize bakmaktan ve kendi testlerimi yapmaktan elde ettiğim tüm tecrübelerim eşit sayıda çokgene göre gruplandırmaya izin vermiyor.
Emil Brundage

Neden eşit olmanız gerekiyor (ajanlar için rota dışı)? Ama bu kısıtlamayı eklersek, o zaman neden verileri uzamsal ilişkiye göre kümelemek (gruplamak)!
Farid Cheraghi

1
Çünkü patron böyle söylüyor. Ayrıca seyahat süresini de en aza indirin.
Emil Brundage

1

temel olarak eşit boyutta bir kümeleme yöntemi istiyorsunuz, böylece web'deki bu anahtar kelimelerle arama yapabilirsiniz. Benim için istatistiklerde iyi bir cevap var . Cevaplardan birinde bir Python uygulaması ile SE . Arcpy'yi biliyorsanız, verilerinizle birlikte kullanabilmeniz gerekir.

Önce çokgenlerin sentroidlerinin X ve Y değerlerini hesaplamanız gerekir, daha sonra bu koordinatları komut dosyasına girebilir ve bir .da imleci kullanarak nitelik tablolarını güncelleyebilirsiniz.


Sağladığınız bağlantı doğru yolda görünüyor, ancak temelde anlamadığım bir dilde. Senaryo için girdilerin ne olduğunu bilmiyorum ve tam olarak ne olduğunu anlamak için kodlamanın herhangi birini deşifre edemiyorum. Çok az açıklama var.
Emil Brundage

0

Merhaba ben daha önce bu gibi benzer bir sorunu vardı, bu yüzden biraz vermişti, asla başka bir başladı var, ama sadece thoery tarafında düşünüyorum

GİRİŞ ŞEKLİ

Giriş şekli

giriş şekli üzerinde bir file oluşturabileceğinizi düşünüyordum

ağ giriş şeklinin kesiştiği balık ağı

alana giriş

Daha sonra, yeni işlenmiş çokgen içindeki bu parsellerin alanını hesaplayabilirsiniz

Komut dosyanızın başlangıcında istenen çokgen / n. Miktar eşit boyutta alan girişi

Daha sonra parselleri ilişkilendirmenin bir yoluna ihtiyacınız olacak, böylece sınırlananların farkında olacaklar.

Sonra parselleri özetlemek için bir satır imleci geçebilir

Kurallar

* Son bir yaz için bir sınır paylaşıyor * Toplanmadı * Eşit alan olarak hesaplanan değerin üzerine çıktığında, geri çekilecek ve bu bir grup olacak * Süreç yeniden başlayacak * son grup olabilir kalan parsellerin toplamı

Ben parseller bewteen ilişkisi kurmak düşünüyorum zor bir şey olabilir ama bir kez bu yapıldığında ben bunu otomatikleştirmek mümkün olabileceğini düşünüyorum


Korkarım bunun benim sorunumla ne ilgisi olduğunu anlamıyorum. Bir poligonun bir balık ağı ile kesilmesi, çokgenleri mekansal ve eşit sayılarla gruplandırmakla ne ilgisi var? Sayıya değil, alana odaklanmış görünüyorsunuz. Koli poligonlarının alanı (boyutu) bir faktör değildir. Bir parselin büyüklüğü ne kadar büyük olursa olsun, konuşmak için hala sadece bir mülk sahibi. Kırmızının kırsal bir alan olduğu ve geniş yayıldığı, turuncu kentli olduğu ve dolayısıyla daha küçük bir toplam alanı kapsadığı örneğime bakın.
Emil Brundage

merhaba orada, üzgünüm ben toplam yanlış sorunuzu okuyun. Ben radouxju yazı gitmek için bir yol olabilir, ama bağlantı biraz kafamın üstünde olduğunu düşünüyorum. Çokgenleri noktalara dönüştürmek mantıklı görünüyor ve sonra bunları gruplıyor. Yol sistemini noktadan yola uzaklık olarak tanıtmanın bir yolu olabilir ve bir sonraki nokta mekansal unsuru tanımlayabilir
Jack Walker


0

Bu nokta olayları için benim çözümüm. Her zaman çalışacağının garantisi yok ...

  1. Point event katmanınıza (call layer1) x (double), y (double) ve uniqueid (long integer) sütunları ekleyin
  2. Katman 1 için öznitelik tablosunu açın. X için x koordinat noktasını, y için y koordinat noktasını ve benzersiz kimlik için FID değerini hesaplayın
  3. Uzamsal İstatistikleri Yürütme Aracı> Kümeleri Eşleme> Gruplama Analizi
    • layer1'i giriş özellikleri olarak ayarla
    • uniqueid'i Benzersiz Alan Kimliği olarak ayarla
    • Grup sayısını tanımlayın (10 diyelim)
    • Analiz alanları için x ve y'yi seçin
    • Uzamsal Kısıtlamalar için "NO_SPATIAL_CONSTRAINT" öğesini seçin
    • Tamam'ı tıklayın
  4. Mekansal İstatistikleri Yürütme Araçları> Coğrafi Dağılımları Ölçme> Ortalama Merkez
    • Giriş Özellikleri Sınıfı olarak # 3'ten Çıktı'yı seçin
    • Vaka Alanı olarak SS_Group'u seçin
    • Tamam'ı tıklayın
  5. Ağ Analisti'ni Aç> Konum Ayırma Aracı
    • Tesis olarak # 4 yük çıkışı
    • Katman1'i Talep Puanı olarak yükle
    • Öznitelikleri aç ve ayarla
      • Kapasitans Kapsamını En Üst Düzeye Çıkarırken Sorun Türü
      • 10 olarak Seçilecek Olanaklar (yukarıdaki # 3'ten)
      • Katman1'deki toplam özellik sayısının yuvarlatılmış olarak seçilecek tesislere bölünmesi olarak Varsayılan Kapasite (145 özellik ve 10 tesis / alan 15 olarak ayarlanmışsa)
      • Tamam'ı tıklayın
        • çözmek
        • Talep noktalarınız aşağı yukarı 10 coğrafi kümeye eşit olarak dağıtılmalıdır

Metodunuzun beşinci adımında takılı kaldım. Network Analyst uzantısını kontrol ettim ve Network Analyst araç çubuğunu ekledim. Ama çoğu gri ve "Konum Ayırma Aracı" görmüyorum. 10.1 kullanıyorum.
Emil Brundage

0

Önce sokaklarınızı kullanarak bir Ağ Veri Kümesi oluşturmanız gerekir. Bu önerilen yöntemi denedim ve giriş alanları için X, Y koordinatları ve k-araçlarını kullanarak (mükemmel değil, ama daha hızlı ve daha yakın olduğum için daha yakın, Şimdiye kadar aynı şeyi Gruplama (adım 3) tek başına yapmak daha iyi şansım oldu ) gerek. Başkalarının yorumlarına ve geri bildirimlerine açığım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.