seleccionar un porcentaje (75%) de un grupo de puntos en función de la distancia desde un punto separado en ArcGIS?

9

Esto es específico de ArcGIS.

Tengo archivos de forma de 2 puntos Ay B, el primero ( A) es un único punto que contiene un lat largo, el segundo ( B) es una multitud de puntos (más de 12k) que contienen cada uno su lat y largo. Lo que intento hacer es automatizar la selección del 75% de Blos puntos del shapefile en función de la distancia desde el shapefile A. En otras palabras, quiero seleccionar el 75% más cercano de los Bpuntos de shapefile al punto de un shapefile A.

Furlong
fuente
¿Es aceptable una solución programática?
Kirk Kuykendall
Por cierto, solicité que Esri permitiera que Shapefield se usara en un ITableSortCallback personalizado, pero me dijeron que no había justificación para esto. Este caso de uso muestra lo contrario.
Kirk Kuykendall
@Kirk Kuykendall Sí, en realidad sería preferible una solución programática ya que este es un proceso que tendré que repetir más de 1k veces. Tengo aproximadamente 1200 puntos separados y cada uno de esos puntos tiene otro archivo de forma con un promedio de 12k puntos a su alrededor. Necesito encontrar una manera de seleccionar fácilmente el 75% más cercano de los puntos circundantes para todos ellos. Hacerlo manualmente está fuera de discusión.
Furlong
Quizás este comentario está fuera del alcance adecuado de un comentario, pero ¿cuándo y por qué sería útil ese análisis? Esto es para mi propia aclaración; perdona mi lentitud
Nathanus
1
Considere el uso de software estadístico. Si tuviera que fusionar los 1200 archivos de forma, creando un campo de identificación de origen durante la fusión, podría unir las coordenadas del punto central correspondiente y calcular todas las distancias de 1200 * 12k = 14.4M. Lo que necesita entonces es una lista de los percentiles 75 de distancia por identificación de fuente: eso tomaría unos diez segundos con Stata (comercial) o R (fuente abierta). (Si usa ArcGIS para esto,
infórmenos

Respuestas:

5

Puede hacer un Buffer de Anillo Múltiple en el archivo de forma A, y luego hacer una unión espacial del Buffer al archivo de forma B. Cuando hace una unión espacial de polígonos y puntos, obtiene un recuento del número de puntos en cada polígono en el atributo tabla de la unión. Luego, al examinar el número total de puntos dentro de los búferes, puede obtener dentro del 75% de los puntos en el archivo de forma B.

Un enfoque ligeramente diferente sería escribir esto en Python y verificar el 75% en un bucle, pero si es un cálculo único, es posible que no lo necesite.

djq
fuente
44
Sería más simple, más rápido y más preciso realizar una unión espacial de A a B, calcular el tercer cuartil del campo [distancia] resultante y seleccionar todos los registros inferiores a esa distancia.
Whuber
¡No sabía que era posible unir puntos espacialmente! Estoy de acuerdo, esta sería una forma mucho mejor de hacerlo.
djq
@Andy Por el contrario, la unión es una relación de punto más cercano. No se basa en ningún atributo tabulado en absoluto. Además, en el software Arc * (volviendo a ArcView 2), la distancia se calcula automáticamente como resultado de la unión.
whuber
1
@whuber, lo sé! De ahí la retractada (¡declaración eliminada!) Supongo que podría hacerlo mediante uniones de tabla de atributos (y calcular la distancia usted mismo), pero eso sería innecesario dado el contexto. Supongo que el punto que me gustaría reiterar es que simplemente se calcula la distancia entre 1 punto, no se necesitan bucles, buffers o procedimientos iterativos.
Andy W
1
@Furlong Si lee el ejemplo de Unión espacial: help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//... puede hacerse una idea de cómo ejecutar esto en Python. Luego, se trata de
revisar
4

Por 1200 puntos (¿o incluso hasta 12M puntos?), Simplemente los puse en la memoria como una Colección Genérica, en este caso, una Lista de listas ordenadas . Esto podría simplificarse simplemente saltando puntos cuando se encuentre con una situación con múltiples puntos que están a la misma distancia del punto de origen. Además, para el rendimiento, considere usar una tabla hash en lugar de una SortedList y ordenar una vez después de insertar todas las distancias. Sin embargo, eso requeriría algunas líneas de código más (?).

No tuve tiempo para probar esto, pero este C # podría ayudarlo a comenzar:

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

Un script de geoprocesamiento de Python es una opción obvia:

  1. Utilice la herramienta Distancia de puntos para calcular la distancia desde sus entidades en la clase de entidad B (el parámetro "Entidades de entrada" de la herramienta) hasta el punto en la clase de entidad A (el parámetro "Entidades cercanas" de la herramienta).
  2. Ordenar la tabla por la distancia calculada.
  3. Seleccione el primer 75% de los objectids en la tabla de salida (la columna "Input_FID") y utilícelos para hacer su selección de las características originales en la clase de entidad B.
Philip
fuente
2

Tuve este problema hace unos años. Me resultó más fácil mantener los datos como 'datos planos', recorrer todos los datos y calcular manualmente la distancia, luego tomar el 75% superior (en realidad, mantuve el 10% superior). Luego hice lo mismo en ArcIMS usando sus cálculos de distancia y me llevó mucho más tiempo.

El almacenamiento en búfer es una gran sobrecarga, pero los cálculos matemáticos son un punto fuerte. Si almacena 12k puntos, creo que tendrá problemas de rendimiento.

Peludo
fuente
Yo [@Mapperz] eliminé los comentarios: las pautas de las herramientas de modificación marcaron esta publicación porque se degradó en disputas sin sentido ...
Mapperz