выбрать процент (75%) группы точек на основе расстояния от одной отдельной точки в ArcGIS?

9

Это специфично для ArcGIS.

У меня есть 2-точечные шейп-файлы, Aи Bпервая ( A) - это отдельная точка, содержащая длинный лат, вторая ( B) - множество точек (более 12 КБ), каждая из которых содержит свои широту и длину. Я пытаюсь автоматизировать выбор 75% Bточек шейп - файла на основе расстояния от шейп-файла A. Другими словами, я хочу выбрать ближайшие 75% Bточек шейп A- файла в одну точку шейп - файла .

Фарлонг
источник
Является ли программное решение приемлемым?
Кирк Куйкендалл
Кстати, я попросил Esri разрешить использование Shapefield в настраиваемом ITableSortCallback, но мне сказали, что для этого нет никаких оснований. Этот вариант использования показывает иное.
Кирк Куйкендалл
@Kirk Kuykendall Да, на самом деле предпочтительнее программное решение, так как это процесс, который мне придется повторять более 1 000 раз. У меня есть примерно 1200 отдельных точек, и у каждой из этих точек есть другой шейп-файл, в среднем по 12 000 точек вокруг него. Мне нужно найти способ легко выбрать ближайшие 75% окружающих точек для них всех. Делать это вручную просто невозможно.
Furlong
Возможно, этот комментарий выходит за рамки самого комментария, но когда и почему такой анализ будет полезен? Это для моего собственного разъяснения; прости мою медлительность.
Натанус
1
Рассмотрите возможность использования статистического программного обеспечения. Если бы вам пришлось объединить все 1200 шейп-файлов, создав поле идентификатора источника во время слияния, вы могли бы присоединить к нему соответствующие координаты центральной точки и вычислить все расстояния 1200 * 12k = 14,4M. Тогда вам нужен список 75-го процентиля расстояния по идентификатору источника: это займет около десяти секунд со Stata (коммерческий) или R (с открытым исходным кодом). (Если вы используете ArcGIS для этого, дайте нам знать, сколько времени потребуется для вычислений. :-)
whuber

Ответы:

5

Вы можете создать множественный кольцевой буфер для шейп-файла A, а затем выполнить пространственное объединение буфера с шейп-файлом B. Когда вы выполняете пространственное соединение полигонов и точек, вы получаете количество точек в каждом полигоне в атрибуте. таблица соединения. Затем, изучив общее количество точек в буферах, вы можете получить в пределах 75% точек в шейп-файле B.

Немного другой подход заключается в том, чтобы написать скрипт на Python и проверить на 75% в цикле, но если это однократное вычисление, вам это может не понадобиться.

djq
источник
4
Было бы проще, быстрее и точнее выполнить пространственное соединение от А до В, вычислить третий квартиль результирующего поля [расстояние] и выбрать все записи, меньшие, чем это расстояние.
uber
Я не знал, что можно было пространственно соединить точки! Я согласен, это был бы намного лучший способ сделать это.
DJQ
@Andy Напротив, соединение является отношением ближайшей точки. Он не основан ни на каких табличных атрибутах вообще. Кроме того, в программном обеспечении Arc * (возвращаясь к ArcView 2), расстояние автоматически вычисляется в результате объединения.
whuber
1
@ ш, я знаю! Следовательно, отозванный (удаленный оператор!) Я предполагаю, что вы могли бы сделать это путем соединения таблицы атрибутов (и самостоятельно рассчитать расстояние), но это было бы излишним, учитывая контекст. Я думаю, что я хотел бы повторить, что это просто вычисление расстояния между 1 точкой, никаких циклов или буферов или итерационных процедур не требуется.
Энди У,
1
@Furlong Если вы прочитали пример Spatial Join: help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//…, вы можете получить представление о том, как запустить это в python. Затем нужно пройти через таблицу атрибутов и выбрать значения, которые соответствуют вашим критериям
djq
4

Для 1200 точек (или даже до точки сказать 12M?) Я просто положил их в памяти как Generic Collection - в этом случае SortedList из списков . Это можно упростить, просто пропустив точки, когда вы столкнетесь с ситуацией, когда несколько точек находятся на одинаковом расстоянии от исходной точки. Также для производительности рассмотрите возможность использования хеш-таблицы вместо SortedList и сортировки один раз после вставки всех расстояний. Это заняло бы еще несколько строк кода (?).

У меня не было времени проверить это, но этот c # может помочь вам начать:

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

Скрипт геообработки Python является очевидным выбором:

  1. Используйте инструмент « Расстояние до точки» , чтобы рассчитать расстояние от ваших объектов в классе пространственных объектов B (параметр «Входные объекты» инструмента) до точки в классе пространственных объектов A (параметр «Ближайшие объекты» инструмента).
  2. Сортировка таблицы по рассчитанному расстоянию.
  3. Выберите первые 75% объектов в выходной таблице (столбец «Input_FID») и используйте их для выбора из исходных объектов в классе пространственных объектов B.
Филипп
источник
2

У меня была эта проблема несколько лет назад. Я обнаружил, что легче сохранять данные как «плоские данные», циклически просматривая все данные и вручную вычисляя расстояние, а затем взяв верхние 75% (я фактически сохранил верхние 10%). Затем я сделал то же самое в ArcIMS, используя их расчеты расстояния, и это заняло намного больше времени.

Буферизация - это огромные накладные расходы, но математические расчеты - это сильная сторона. Если вы буферизуете 12 тыс. Баллов, я думаю, у вас будут проблемы с производительностью.

волосатый
источник
Я [@Mapperz] удалил комментарии - руководство по инструментам мода пометило это сообщение, потому что оно
переросло