Auswählen eines Prozentsatzes (75%) einer Gruppe von Punkten basierend auf der Entfernung von einem separaten Punkt in ArcGIS?

9

Dies ist ArcGIS-spezifisch.

Ich habe 2 Punkt-Shapefiles Aund Bdas erste ( A) ist ein einzelner Punkt, der eine Lat-Länge enthält, das zweite ( B) ist eine Vielzahl von Punkten (über 12 KB), die jeweils ihre Lat- und Long-Punkte enthalten. Ich versuche, die Auswahl von 75% der Shapefile B-Punkte basierend auf dem Abstand zum Shapefile zu automatisieren A. Mit anderen Worten, ich möchte die 75% der Shapefile- BPunkte auswählen, die dem Aeinen Punkt des Shapefiles am nächsten kommen .

Achtelmeile
quelle
Ist eine programmatische Lösung akzeptabel?
Kirk Kuykendall
Übrigens habe ich Esri gebeten, die Verwendung des Shapefield in einem benutzerdefinierten ITableSortCallback zuzulassen, aber es wurde mir mitgeteilt, dass dies nicht gerechtfertigt ist. Dieser Anwendungsfall zeigt etwas anderes.
Kirk Kuykendall
@Kirk Kuykendall Ja, eine programmatische Lösung wäre eigentlich vorzuziehen, da dies ein Prozess ist, den ich über 1k Mal wiederholen muss. Ich habe ungefähr 1200 separate Punkte und jeder dieser Punkte hat ein anderes Shapefile mit durchschnittlich 12.000 Punkten. Ich muss einen Weg finden, um auf einfache Weise die nächsten 75% der umgebenden Punkte für alle auszuwählen. Manuelles Handeln kommt nicht in Frage.
Furlong
Vielleicht liegt dieser Kommentar außerhalb des eigentlichen Rahmens eines Kommentars, aber wann und warum wäre eine solche Analyse nützlich? Dies ist zu meiner eigenen Erläuterung; vergib mir meine Langsamkeit.
Nathanus
1
Erwägen Sie die Verwendung einer Statistiksoftware. Wenn Sie alle 1200 Shapefiles zusammenführen und während des Zusammenführens ein Quell-ID-Feld erstellen, können Sie die entsprechenden zentralen Punktkoordinaten damit verbinden und alle 1200 * 12k = 14,4 M Entfernungen berechnen. Was Sie dann brauchen, ist eine Liste der 75. Perzentile der Entfernung nach Quell-ID: Dies würde mit Stata (kommerziell) oder R (Open Source) ungefähr zehn Sekunden dauern. (Wenn Sie ArcGIS dafür verwenden,
teilen

Antworten:

5

Sie können einen Mehrfachringpuffer für Shapefile A erstellen und dann eine räumliche Verknüpfung des Puffers mit Shapefile B durchführen. Wenn Sie eine räumliche Verknüpfung von Polygonen und Punkten durchführen, erhalten Sie eine Anzahl der Punkte in jedem Polygon im Attribut Tabelle des Joins. Wenn Sie dann die Gesamtzahl der Punkte in den Puffern untersuchen, können Sie 75% der Punkte in Shapefile B erreichen.

Ein etwas anderer Ansatz wäre, dies in Python zu skripten und in einer Schleife nach 75% zu suchen. Wenn es sich jedoch um eine einmalige Berechnung handelt, benötigen Sie diese möglicherweise nicht.

djq
quelle
4
Es wäre einfacher, schneller und genauer, eine räumliche Verknüpfung von A mit B durchzuführen, das dritte Quartil des resultierenden Felds [Entfernung] zu berechnen und alle Datensätze auszuwählen, die kleiner als diese Entfernung sind.
whuber
Ich wusste nicht, dass es möglich ist, Punkte räumlich zu verbinden! Ich stimme zu, dies wäre ein viel besserer Weg, dies zu tun.
DJQ
@Andy Im Gegenteil, die Verknüpfung ist eine Beziehung zum nächsten Punkt. Es basiert überhaupt nicht auf tabellarischen Attributen. In der Arc * -Software (zurück zu ArcView 2) wird die Entfernung automatisch als Ergebnis des Joins berechnet.
whuber
1
@whuber, ich weiß! Daher die zurückgezogene (gelöschte Anweisung!) Ich nehme an, Sie könnten dies durch Attributtabellenverknüpfungen tun (und die Entfernung selbst berechnen), aber das wäre angesichts des Kontexts unnötig. Ich denke, der Punkt, den ich wiederholen möchte, ist, dass einfach der Abstand zwischen 1 Punkt berechnet wird, keine Schleifen oder Puffer oder iterative Prozeduren erforderlich sind.
Andy W
1
@Furlong Wenn Sie das Beispiel für Spatial Join lesen: help.arcgis.com/de/arcgisdesktop/10.0/help/index.html#//… , können Sie sich ein Bild davon machen, wie dies in Python ausgeführt wird. Dann geht es darum, die Attributtabelle
durchzugehen
4

Für 1200 Punkte (oder sogar bis zu 12 Millionen Punkte?) Würde ich sie einfach als generische Sammlung speichern - in diesem Fall als sortierte Liste von Listen . Dies könnte vereinfacht werden, indem nur Punkte übersprungen werden, wenn Sie auf eine Situation mit mehreren Punkten stoßen, die denselben Abstand vom Ursprungspunkt haben. Aus Gründen der Leistung sollten Sie auch eine Hashtabelle anstelle einer SortedList verwenden und nach dem Einfügen aller Entfernungen einmal sortieren. Das würde allerdings noch ein paar Zeilen Code erfordern (?).

Ich hatte keine Zeit, dies zu testen, aber dieses c # könnte Ihnen den Einstieg erleichtern:

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
quelle
4

Ein Python-Geoverarbeitungsskript ist eine naheliegende Wahl:

  1. Verwenden Sie die Punktentfernung Werkzeug , um die Entfernung von Ihren Funktionen in Feature - Class B (die „Eingabe - Features“ Parameter des Werkzeugs) bis zu dem Punkt in Feature - Class A zu berechnen (die „Near - Features“ Parameter des Werkzeugs).
  2. Sortieren Sie die Tabelle nach der berechneten Entfernung.
  3. Wählen Sie die ersten 75% der Objekt-IDs in der Ausgabetabelle (Spalte "Input_FID") aus und verwenden Sie diese, um Ihre Auswahl aus den ursprünglichen Features in Feature-Class B zu treffen.
Philip
quelle
2

Ich hatte dieses Problem vor ein paar Jahren. Ich fand es einfacher, die Daten als "flache Daten" zu halten, alle Daten zu durchlaufen, die Entfernung manuell zu berechnen und dann die besten 75% zu nehmen (ich habe tatsächlich die oberen 10% behalten). Ich habe dann dasselbe in ArcIMS mit ihren Entfernungsberechnungen gemacht und es hat viel länger gedauert.

Das Puffern ist ein enormer Aufwand, aber mathematische Berechnungen sind eine große Stärke. Wenn Sie 12.000 Punkte puffern, werden Sie wahrscheinlich Probleme mit der Leistung haben.

Behaart
quelle
Ich [@Mapperz] habe die Kommentare gelöscht - Mod Tools Richtlinien haben diesen Beitrag markiert, weil er zu sinnlosem
Streit