Могут ли метки для перекрывающихся точек быть объединены / объединены в одну метку?

12

У меня есть точки, представляющие образцы мест. Часто в одном и том же месте будут взяты несколько образцов: несколько точек с одним и тем же местоположением, но с разными идентификаторами образцов и другими атрибутами. Я хотел бы пометить все точки, которые совмещены с одной меткой, со сложенным текстом, перечисляющим все образцы идентификаторов всех точек в этом месте.

Возможно ли это в ArcGIS с использованием обычного механизма маркировки или Maplex? Я знаю, что мог бы обойти это, создав новый слой со всеми образцами идентификаторов для каждого местоположения в одном значении атрибута, но я бы хотел избежать создания новых данных только для маркировки.

В основном я хочу пойти от этого:

введите описание изображения здесь

К этому (для самой верхней точки):

введите описание изображения здесь

Не делая ручного редактирования надписей.

Дэн С
источник
Сколько точек в вашем наборе данных?
Хорнбидд

Ответы:

11

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

Добавьте целое число типа THEFIELD к слою и заполните его, используя выражение ниже:

aList=[]
def FirstOrOthers(shp):
 global aList
 key='%s%s' %(round(shp.firstPoint.X,3),round(shp.firstPoint.Y,3))
 if key in aList:
  return 2   
 aList.append(key)
 return 1

Позвоните по:

FirstOrOthers( !Shape! )

Создайте копию слоя в таблице содержания, примените определение запроса THEFIELD = 1.

Примените запрос определения THEFIELD = 2 для исходного слоя.

Применить другое фиксированное размещение метки

введите описание изображения здесь

ОБНОВЛЕНИЕ на основе комментариев к оригинальному решению:

Добавьте поле COORD и заполните его, используя

'%s %s' %(round( !Shape!.firstPoint.X,2),round( !Shape!.firstPoint.Y,2))

Суммируйте это поле, используя первый и последний для метки. Присоедините эту таблицу к оригиналу, используя поле COORD. Выберите записи, где первый <> последний и объединить первый и последний ярлык в новом поле, используя

'%s\n%s' %(!Sum_Output_4.First_MUID!, !Sum_Output_4.Last_MUID!)

Используйте Count_COORD и THEFIELD, чтобы определить 2 «разных слоя» и поля для их пометки:

введите описание изображения здесь

Обновление № 2, вдохновленное решением @Hornbydd:

import arcpy
def FindLabel ([FID],[MUID]):
  f,m=int([FID]),[MUID]
  mxd = arcpy.mapping.MapDocument("CURRENT")
  dFids={}
  dLabels={}
  lyr = arcpy.mapping.ListLayers(mxd,"centres")[0]
  with arcpy.da.SearchCursor(lyr,["FID","SHAPE@","MUID"]) as cursor:
    for row in cursor:
       FD,shp,LABEL=row
       XY='%s %s' %(round(shp.firstPoint.X,2),round( shp.firstPoint.Y,2))
       if f == FD:
         aKey=XY
       try:
          L=dFids[XY]
          L+=[FD]
          dFids[XY]=L
          L=dLabels[XY]
          L=L+'\n'+LABEL
          dLabels[XY]=L
       except:
          dFids[XY]=[FD]
          dLabels[XY]=LABEL
  Labels=dLabels[aKey]
  Fids=dFids[aKey]
  if f == Fids[0]:
    return Labels
  return ""

ОБНОВЛЕНИЕ Ноябрь 2016, надеюсь, продлится.

Ниже выражение проверено на 2000 дубликатов, работает как шарм:

mxd = arcpy.mapping.MapDocument("CURRENT")
lyr = arcpy.mapping.ListLayers(mxd,"centres")[0]
dFids={}
dLabels={}
fidKeys={}
with arcpy.da.SearchCursor(lyr,["FID","SHAPE@","MUID"]) as cursor:
 for FD,shp,LABEL in cursor:
  XY='%s %s' %(round(shp.firstPoint.X,2),round( shp.firstPoint.Y,2))
  fidKeys[FD]=XY
  if XY in dLabels:
   dLabels[XY]+=('\n'+LABEL)
   dFids[XY]+=[FD]
  else:
   dLabels[XY]=LABEL
   dFids[XY]=[FD]

def FindLabel ([FID]):
  f=int([FID])
  aKey=fidKeys[f]
  Fids=dFids[aKey]
  if f == Fids[0]:
    return dLabels[aKey]
  return "
FelixIP
источник
Эй, ты взломал это! Ницца! Я знал, что там кто-то был вундеркиндом! Как я и ожидал, это очень итеративный процесс, поэтому он запускается на большом наборе данных, и надписи на нем требуются всегда (хорошо, как на моих тестовых данных). Я изменил ваш стиль кода, расширив несколько строк. Я нахожу минимализма, все на одной линии трудно следовать.
Хорнбидд
1
@ Hornbydd спасибо за изменения. Эту гайку было трудно сломать из-за поведения этикетки (двигателя?). Он обрабатывает все параметры функции как строки! Вот почему первый IF не работал без f = int ([FID]). Что касается скорости, я бы никогда не использовал ее на наборе, превышающем 50 баллов. Он должен быть преобразован в скрипт, который заполняет новое поле, пройдя набор данных только дважды: 1) поиск курсора для компиляции обоих словарей, 2) обновление курсора для чтения из них ПРИМЕЧАНИЕ: первые 3 строки после оператора try устарели, после публикации решения I понял, что они могут быть безопасно удалены.
FelixIP
К вашему сведению, у меня не было возможности вернуться к этому, но я планирую дать вашему решению волнение на следующей неделе или около того. Есть также другой обходной путь (тот, который я использовал в этом случае) без Python, я также опубликую ответ об этом.
Дан С
Сталкивался эту страницу на геосетки. Мне понравилось умное использование глобальных словарей, затем я подумал об этом вопросе и добавил ссылку на него.
Хорнбидд
@Hornbydd Да, он очень умный и детальный, как и все, что есть у Ричарда, и будет иметь огромное значение для моего (нашего) решения. Можно еще улучшить, удалив несколько строк, включая самую первую. Однако, исходя из времени ответа от OP, кажется, что он потерял интерес, я тоже не беспокоюсь
FelixIP
4

Ниже приведено частичное решение.

Это входит в выражение ярлыка Advance. Это не очень эффективно, поэтому я спрашиваю о количестве точек в вашем наборе данных. Таким образом, для каждой строки, которая помечена, создается 2 словаря, dключом которых является XY, а значением - текст, а d2также objectID и XY. Используя эту комбинацию словарей, он может возвращать одну метку, которая является конкатенацией с символами новой строки, в моем примере это конкатенация TARGET_FID. «sj» - это имя слоя в оглавлении.

import arcpy
def FindLabel ( [OBJECTID] ):
  ob = str([OBJECTID])
  mxd = arcpy.mapping.MapDocument("CURRENT")
  d ={}
  d2 = {}
  lyr = arcpy.mapping.ListLayers(mxd,"sj")[0]
  with arcpy.da.SearchCursor(lyr,["OID@","SHAPE@XY","TARGET_FID"]) as cursor:
    for row in cursor:
      objID = str(row[0])
      temp = row[1]
      tup = str(temp[0]) + "," + str(temp[1])
      d2[objID] = tup
      txt = str(row[2])
      if tup in d:
        v = d[tup] 
        v = v + "\n" + txt
        d[tup] = v
      else:
        d[tup] = txt  
  temp = d2[ob]
  return d[temp]

Почему это частичное решение заключается в том, что это делается для каждой точки, я не смог придумать, как бы вы отключили все остальные сложенные точки. Именно поэтому я думаю, что окончательным решением является некий питон, который создает новый слой из отдельных точек с одной меткой, созданной из стека точек.

Ниже приведен вывод 3 сложенных точек, поскольку вы можете видеть, что метка создается для каждой точки, поскольку все они существуют в одном и том же месте.

пример

Hornbydd
источник