selezionando una percentuale (75%) di un gruppo di punti in base alla distanza da un punto separato in ArcGIS?


9

Questo è specifico di ArcGIS.

Ho 2 shapefile di punti Ae B, il primo ( A) è un singolo punto che contiene un lat long, il secondo ( B) è una moltitudine di punti (oltre 12k) che contengono ciascuno il loro lat e long. Quello che sto cercando di fare è automatizzare la selezione del 75% dei Bpunti dello shapefile in base alla distanza dallo shapefile A. In altre parole, voglio selezionare il 75% più vicino dei Bpunti del file di forma per Aun solo punto del file di forma.


È accettabile una soluzione programmatica?
Kirk Kuykendall,

A proposito, ho chiesto a Esri di consentire a Shapefield di essere utilizzato in un ITableSortCallback personalizzato ma mi è stato detto che non c'era giustificazione per questo. Questo caso d'uso mostra diversamente.
Kirk Kuykendall,

@Kirk Kuykendall Sì, in realtà sarebbe preferibile una soluzione programmatica in quanto questo è un processo che dovrò ripetere più di 1 volta. Ho circa 1200 punti separati e ognuno di questi punti ha un altro shapefile con circa 12k punti attorno. Devo trovare un modo per selezionare facilmente il 75% più vicino dei punti circostanti per tutti. Farlo manualmente è fuori discussione.
Furlong,

Forse questo commento è al di fuori del campo di applicazione di un commento, ma quando e perché una tale analisi sarebbe utile? Questo è per la mia personale spiegazione; perdona la mia lentezza.
Nathanus,

1
Prendi in considerazione l'utilizzo di software statistico. Se dovessi unire tutti i 1200 shapefile, creando un campo ID sorgente durante l'unione, potresti unire le coordinate del punto centrale corrispondenti a quello e calcolare tutte le distanze 1200 * 12k = 14.4M. Ciò di cui hai bisogno è quindi un elenco dei 75 ° percentili di distanza per ID sorgente: ciò richiederebbe circa dieci secondi con Stata (commerciale) o R (open source). (Se usi ArcGIS per questo, facci sapere quanto tempo ci vuole per il calcolo. :-)
whuber

Risposte:


5

È possibile creare un buffer ad anello multiplo sul file di forma A, quindi eseguire un'unione spaziale del buffer al file di forma B. Quando si esegue un'unione spaziale di poligoni e punti, si ottiene un conteggio del numero di punti in ciascun poligono nell'attributo tabella del join. Quindi, esaminando il numero totale di punti all'interno dei buffer, è possibile ottenere entro il 75% dei punti nel file di forma B.

Un approccio leggermente diverso sarebbe quello di scrivere questo script in Python e verificare il 75% in un ciclo, ma se si tratta di un calcolo una tantum potrebbe non essere necessario.


4
Sarebbe più semplice, veloce e accurato eseguire un join spaziale da A a B, calcolare il terzo quartile del campo [distanza] risultante e selezionare tutti i record a meno di quella distanza.
whuber

Non sapevo che fosse possibile unire spazialmente i punti! Sono d'accordo, questo sarebbe un modo molto migliore di farlo.
djq,

@Andy Al contrario, l'unione è una relazione del punto più vicino. Non si basa su alcun attributo tabulato. Inoltre, nel software Arc * (tornando ad ArcView 2), la distanza viene calcolata automaticamente come risultato del join.
whuber

1
@whuber, lo so! Da qui la frase ritirata (dichiarazione cancellata!) Suppongo che potresti farlo attraverso i join della tabella degli attributi (e calcolando la distanza tu stesso) ma ciò non sarebbe necessario dato il contesto. Immagino che il punto che vorrei ribadire sia che sta semplicemente calcolando la distanza tra 1 punto, non sono necessari loop o buffer o procedure iterative.
Andy W,

1
@Furlong Se leggi l'esempio di Join spaziale: help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//… puoi avere un'idea di come eseguirlo in Python. Quindi, si tratta di scorrere la tabella degli attributi e scegliere i valori che corrispondono ai tuoi criteri
djq

4

Per 1200 punti (o addirittura per dire 12 milioni di punti?), Li metterei semplicemente in memoria come una raccolta generica, in questo caso un elenco di elenchi ordinati . Ciò potrebbe essere semplificato semplicemente saltando i punti quando ci si imbatte in una situazione con più punti che si trovano alla stessa distanza dal punto di origine. Inoltre, per prestazioni, considera l'utilizzo di una tabella hash invece di una SortedList e l'ordinamento una volta dopo aver inserito tutte le distanze. Ciò richiederebbe qualche altra riga di codice (?).

Non ho avuto il tempo di testarlo, ma questo c # potrebbe farti iniziare:

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

4

Uno script di geoprocessing di Python è una scelta ovvia:

  1. Utilizzare lo strumento Distanza punto per calcolare la distanza dalle funzioni nella classe di caratteristiche B (il parametro "Funzioni di input" dello strumento) al punto nella classe di caratteristiche A (il parametro "Funzioni vicine" dello strumento).
  2. Ordina la tabella per la distanza calcolata.
  3. Seleziona il primo 75% degli objectids nella tabella di output (la colonna "Input_FID") e usali per effettuare la tua selezione dalle funzionalità originali nella classe di caratteristiche B.

2

Ho avuto questo problema qualche anno fa. Ho trovato più facile mantenere i dati come "dati piatti", scorrere tutti i dati e calcolare manualmente la distanza, quindi prendere il 75% (ho effettivamente mantenuto il 10%). Ho quindi fatto lo stesso in ArcIMS usando i loro calcoli della distanza e ci è voluto molto più tempo.

Il buffering è un enorme sovraccarico, ma i calcoli matematici sono un forte fattore. Se tamponi 12k punti, penso che avrai problemi di performace.


Ho [@Mapperz] cancellato i commenti - le linee guida per gli strumenti mod hanno segnalato questo post perché si è trasformato in inutili battibecchi ...
Mapperz
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.