wybierając procent (75%) grupy punktów na podstawie odległości od jednego oddzielnego punktu w ArcGIS?

9

Jest to specyficzne dla ArcGIS.

Mam 2 Shapefiles punktów Ai B, pierwszym ( A) to jeden punkt, który zawiera szer długości, druga ( B) jest wielopunktowo (ponad 12k), z których każdy zawiera lat i ich długości. Usiłuję zautomatyzować wybór 75% punktów pliku kształtu na Bpodstawie odległości od pliku kształtu A. Innymi słowy, chcę wybrać najbliższe 75% Bpunktów shapefile do Ajednego punktu shapefile .

Furlong
źródło
Czy możliwe jest rozwiązanie programowe?
Kirk Kuykendall
BTW, poprosiłem Esri o zezwolenie na użycie Shapefield w niestandardowym ITableSortCallback, ale powiedziano mi, że nie ma uzasadnienia. Ten przypadek użycia pokazuje inaczej.
Kirk Kuykendall
@Kirk Kuykendall Tak, tak naprawdę byłoby preferowane rozwiązanie programistyczne, ponieważ jest to proces, który będę musiał powtórzyć ponad 1 000 razy. Mam około 1200 oddzielnych punktów i każdy z tych punktów ma inny plik kształtu ze średnio 12 000 punktów wokół niego. Muszę znaleźć sposób na łatwe wybranie dla nich wszystkich najbliższych 75% punktów otaczających. Robienie tego ręcznie jest po prostu wykluczone.
Furlong
Być może ten komentarz jest poza właściwym zakresem komentarza, ale kiedy i dlaczego taka analiza byłaby przydatna? To dla mojego własnego wyjaśnienia; wybacz moją powolność.
Nathanus
1
Rozważ użycie oprogramowania statystycznego. Jeśli miałbyś scalić wszystkie 1200 plików kształtów, tworząc pole identyfikatora źródłowego podczas scalania, możesz dołączyć do niego odpowiednie współrzędne centralnego punktu i obliczyć wszystkie odległości 1200 * 12k = 14,4M. Potrzebna jest zatem lista 75 percentyli odległości według identyfikatora źródła: zajęłoby to około 10 sekund w przypadku Stata (reklama) lub R (oprogramowanie open source). (Jeśli używasz do tego ArcGIS, daj nam znać, ile czasu zajmuje obliczenie. :-)
whuber

Odpowiedzi:

5

Możesz utworzyć bufor wielokrotnego pierścienia na pliku kształtu A, a następnie wykonać przestrzenne połączenie bufora z plikiem kształtu B. Gdy wykonasz połączenie przestrzenne wielokątów i punktów, otrzymasz liczbę punktów w każdym wielokącie w atrybucie tabela sprzężenia. Następnie, badając całkowitą liczbę punktów w buforach, możesz uzyskać do 75% punktów w pliku kształtu B.

Nieco innym podejściem byłoby napisanie skryptu w Pythonie i sprawdzenie 75% w pętli, ale jeśli jest to jednorazowe obliczenie, możesz tego nie potrzebować.

djq
źródło
4
Byłoby łatwiej, szybciej i dokładniej wykonać połączenie przestrzenne od A do B, obliczyć trzeci kwartyl wynikowego pola [odległość] i wybrać wszystkie rekordy mniejsze niż ta odległość.
whuber
Nie wiedziałem, że można przestrzennie łączyć punkty! Zgadzam się, byłby to o wiele lepszy sposób.
djq
@Andy Przeciwnie, połączenie jest relacją najbliższego punktu. W ogóle nie jest oparty na żadnych tabelarycznych atrybutach. Ponadto w oprogramowaniu Arc * (powrót do ArcView 2) odległość jest automatycznie obliczana w wyniku połączenia.
whuber
1
@ whuber, wiem! Stąd wycofana (usunięta instrukcja!) Zakładam, że można to zrobić za pomocą złączeń tabeli atrybutów (i samemu obliczając odległość), ale byłoby to niepotrzebne, biorąc pod uwagę kontekst. Chyba chciałbym powtórzyć, że po prostu oblicza odległość między 1 punktem, nie są potrzebne żadne pętle, bufory ani procedury iteracyjne.
Andy W
1
@ Furlong Jeśli przeczytasz przykład łączenia przestrzennego: help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//… , możesz dowiedzieć się, jak uruchomić to w pythonie. Następnie należy przejrzeć tabelę atrybutów i wybrać wartości spełniające podane kryteria
djq
4

Do 1200 punktów (lub nawet powiedzieć punktów 12M?) Ja po prostu umieścić je w pamięci jako Generic Collection - w tym przypadku SortedList z list . Można to uprościć, pomijając punkty, gdy napotkasz sytuację, w której wiele punktów znajduje się w tej samej odległości od punktu początkowego. Również pod kątem wydajności, należy rozważyć użycie hashtable zamiast SortedList i sortowania raz po włożeniu wszystkich dystansach. To zajmie jeszcze kilka linii kodu (?).

Nie miałem czasu, aby to przetestować, ale ten c # może zacząć:

private void SelectNTile(string layer1, string layer2, double nTile)
{
    var fLayer1 = FindLayer(ArcMap.Document.FocusMap, "LayerWithLotsofPoints");
    var fLayer2 = FindLayer(ArcMap.Document.FocusMap, "LayerWithOneSelectedPoint");
    IFeature feat = GetSingleFeature(fLayer2);
    var distList = MakeDistList(fLayer1.FeatureClass,(IPoint)feat.ShapeCopy);
    // assume not many points exactly same distance
    var nRecs = (int)(distList.Count * nTile); // nTile would be 0.75 for 75%
    var Oids = new List<int>();
    foreach (KeyValuePair<double, List<int>> kvp in distList)
    {
        Oids.AddRange(kvp.Value);
        if (Oids.Count > nRecs)
            break;
    }
    var fSel = fLayer1 as IFeatureSelection;
    var OidArray = Oids.ToArray();
    fSel.SelectionSet.AddList(Oids.Count, ref OidArray[0]);                
}

private SortedList<double, List<int>> MakeDistList(IFeatureClass fc, IPoint pnt)
{
    var outList = new SortedList<double, List<int>>();
    var proxOp = pnt as IProximityOperator;
    IFeatureCursor fCur = null;
    try
    {
        fCur = fc.Search(null, true); // recycling is faster, we just need OIDs
        IFeature feat;
        while ((feat = fCur.NextFeature()) != null)
        {
            double dist = proxOp.ReturnDistance(feat.Shape);
            if (!outList.ContainsKey(dist))
                outList.Add(dist, new List<int> { feat.OID });
            else
                outList[dist].Add(feat.OID);  // this should rarely happen
        }
    }
    catch
    {
        throw;
    }
    finally
    {
        if (fCur != null)
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fCur);
    }
    return outList;
}
private IFeature GetSingleFeature(IFeatureLayer fLayer)
{
    var fSel = fLayer as IFeatureSelection;
    if (fSel.SelectionSet.Count != 1)
        throw new Exception("select one feature in " + fLayer.Name + " first");
    var enumIDs = fSel.SelectionSet.IDs;
    enumIDs.Reset();
    IFeature feat = fLayer.FeatureClass.GetFeature(enumIDs.Next());
    return feat;
}
private IFeatureLayer FindLayer(IMap map, string name)
{
    throw new NotImplementedException();
}
Kirk Kuykendall
źródło
4

Skrypt geoprzetwarzania Pythona jest oczywistym wyborem:

  1. Użyj narzędzia Odległość punktu , aby obliczyć odległość od operacji w klasie obiektów B (parametr „Funkcje wejściowe” narzędzia) do punktu w klasie obiektów A (parametr „Blisko operacji” narzędzia).
  2. Posortuj tabelę według obliczonej odległości.
  3. Wybierz pierwsze 75% ObjectID w tabeli wyjściowej (kolumna „Input_FID”) i użyj tych, aby dokonać wyboru spośród oryginalnych operacji w klasie obiektów B.
Philip
źródło
2

Miałem ten problem kilka lat temu. Uznałem, że łatwiej jest przechowywać dane jako „dane płaskie”, przeglądając wszystkie dane i ręcznie obliczając odległość, a następnie biorąc górne 75% (faktycznie zachowałem górne 10%). Następnie zrobiłem to samo w ArcIMS, korzystając z ich obliczeń odległości i zajęło to znacznie więcej czasu.

Buforowanie jest ogromnym obciążeniem, ale obliczenia matematyczne są mocną stroną. Jeśli buforujesz 12 000 punktów, myślę, że będziesz mieć problemy z wydajnością.

Włochaty
źródło
Ja [@Mapperz] usunąłem komentarze - wytyczne mod mod oflagowały ten post, ponieważ przerodziły się w bezsensowną sprzeczkę ...
Mapperz