selecionando uma porcentagem (75%) de um grupo de pontos com base na distância de um ponto separado no ArcGIS?

9

Isso é específico do ArcGIS.

Eu tenho shapefiles de 2 pontos Ae B, o primeiro ( A) é um único ponto que contém um lat long, o segundo ( B) é uma infinidade de pontos (acima de 12k) que contêm cada lat e long. O que estou tentando fazer é automatizar a seleção de 75% dos Bpontos do shapefile com base na distância do shapefile A. Em outras palavras, eu quero selecionar os 75% mais próximos dos Bpontos do shapefile para Ao único ponto do shapefile .

Furlong
fonte
Uma solução programática é aceitável?
Kirk Kuykendall
BTW, solicitei que a Esri permitisse que o Shapefield fosse usado em um ITableSortCallback personalizado, mas foi informado que não havia justificativa para isso. Este caso de uso mostra o contrário.
Kirk Kuykendall 5/05
@Kirk Kuykendall Sim, na verdade, seria preferível uma solução programática, pois esse é um processo que terei que repetir mais de 1k vezes. Eu tenho aproximadamente 1200 pontos separados e cada um desses pontos tem outro shapefile com, em média, 12k pontos ao seu redor. Eu preciso descobrir uma maneira de selecionar facilmente os 75% mais próximos dos pontos circundantes para todos eles. Fazê-lo manualmente está fora de questão.
Furlong
Talvez esse comentário esteja fora do escopo adequado de um comentário, mas quando e por que essa análise seria útil? Isto é para minha própria elucidação; perdoe minha lentidão.
Nathanus
11
Considere usar software estatístico. Se você mesclar todos os 1200 shapefiles, criando um campo de ID de origem durante a mesclagem, junte as coordenadas do ponto central correspondentes a ele e calcule todas as distâncias de 1200 * 12k = 14,4M. O que você precisa então é uma lista dos 75º percentis de distância por ID da fonte: isso levaria cerca de dez segundos com Stata (comercial) ou R (código aberto). (Se você usar o ArcGIS para isso, informe-nos quanto tempo leva para o cálculo. :-)
whuber

Respostas:

5

Você pode criar um buffer de anel múltiplo no shapefile A e, em seguida, fazer uma junção espacial do buffer para o shapefile B. Quando você faz uma junção espacial de polígonos e pontos, obtém uma contagem do número de pontos em cada polígono no atributo tabela da junção. Então, examinando o número total de pontos nos buffers, você pode obter 75% dos pontos no shapefile B.

Uma abordagem um pouco diferente seria criar um script em Python e verificar os 75% em um loop, mas se for um cálculo único, talvez você não precise disso.

djq
fonte
4
Seria mais simples, mais rápido e mais preciso realizar uma junção espacial de A a B, calcular o terceiro quartil do campo [distância] resultante e selecionar todos os registros abaixo dessa distância.
whuber
Eu não sabia que era possível juntar pontos espacialmente! Eu concordo, isso seria uma maneira muito melhor de fazê-lo.
DJQ
@ Andy Pelo contrário, a união é uma relação de ponto mais próximo. Não é baseado em nenhum atributo tabulado. Além disso, no software Arc * (voltando ao ArcView 2), a distância é calculada automaticamente como resultado da junção.
whuber
11
@ Whuber, eu sei! Daí a retraída (declaração excluída!) Suponho que você poderia fazê-lo através da junção da tabela de atributos (e calculando a distância), mas isso seria desnecessário, considerando o contexto. Eu acho que o ponto que eu gostaria de reiterar é que ele está simplesmente calculando a distância entre 1 ponto, nenhum loop ou buffers ou procedimentos iterativos são necessários.
Andy W
11
@ Longlong Se você ler o exemplo de Junção espacial: help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//…, poderá ter uma idéia de como executar isso em python. Então, é uma questão de correr através da tabela de atributo e escolhendo valores que correspondem aos seus critérios
DJQ
4

Para 1200 pontos (ou mesmo até dizer pontos 12M?) Eu tinha acabado de colocá-los na memória como uma coleção genérica - neste caso, um SortedList de listas . Isso pode ser simplificado ao pular pontos quando você se deparar com uma situação com vários pontos que estão à mesma distância do ponto de origem. Além disso, para obter desempenho, considere usar uma tabela de hashtags em vez de uma SortedList e classificar uma vez após inserir todas as distâncias. Isso levaria mais algumas linhas de código (?).

Não tive tempo de testar isso, mas esse c # pode ajudar você a começar:

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

Um script de geoprocessamento Python é uma escolha óbvia:

  1. Use a ferramenta Distância do ponto para calcular a distância entre seus recursos na classe de recurso B (o parâmetro "Recursos de entrada" da ferramenta) até o ponto na classe de recurso A (o parâmetro "Recursos próximos" da ferramenta).
  2. Classifique a tabela pela distância calculada.
  3. Selecione os primeiros 75% dos objectids na tabela de saída (a coluna "Input_FID") e use-os para fazer sua seleção dos recursos originais na classe de recurso B.
Philip
fonte
2

Eu tive esse problema alguns anos atrás. Achei mais fácil manter os dados como 'dados simples', percorrendo todos os dados e calculando manualmente a distância, depois obtendo os 75% superiores (na verdade, eu mantive os 10% superiores). Fiz o mesmo no ArcIMS usando seus cálculos de distância e levou muito mais tempo.

O buffer é uma sobrecarga enorme, mas os cálculos de matemática são um forte ponto forte. Se você colocar 12k pontos em buffer, acho que você terá problemas de desempenho.

Peludo
fonte
I [@Mapperz] apagado os comentários - diretrizes ferramentas mod sinalizado este post porque degradada em brigas sem sentido ...
Mapperz