Czy etykiety nakładających się punktów można łączyć / scalać w jedną etykietę?

12

Mam punkty reprezentujące przykładowe lokalizacje. Często wiele próbek zostanie pobranych w tej samej lokalizacji: wiele punktów o tej samej lokalizacji, ale różne identyfikatory próbek i inne atrybuty. Chciałbym oznaczyć wszystkie punkty, które znajdują się w tej samej etykiecie, a tekst w stosie zawiera wszystkie identyfikatory próbek wszystkich punktów w tym miejscu.

Czy jest to możliwe w ArcGIS przy użyciu zwykłego silnika do etykietowania lub Maplex? Wiem, że mogłem obejść ten problem, tworząc nową warstwę ze wszystkimi przykładowymi identyfikatorami dla każdej lokalizacji w jednej wartości atrybutu, ale chciałbym uniknąć tworzenia nowych danych tylko na potrzeby etykietowania.

Zasadniczo chcę od tego zacząć:

wprowadź opis zdjęcia tutaj

Do tego (najwyższy punkt):

wprowadź opis zdjęcia tutaj

Bez ręcznej edycji etykiet.

Dan C.
źródło
Ile punktów jest w twoim zestawie danych?
Hornbydd

Odpowiedzi:

11

Jednym ze sposobów na to jest klonowanie warstwy, używanie zapytań definicji i etykietowanie ich osobno, przy użyciu pozycji etykiety tylko w lewym górnym rogu dla pierwszej warstwy i lewej dolnej dla drugiej.

Dodaj liczbę całkowitą typu THEFIELD do warstwy i wypełnij ją, używając wyrażenia poniżej:

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

Nazwij to:

FirstOrOthers( !Shape! )

Utwórz kopię warstwy w spisie treści, zastosuj zapytanie definicji THEFIELD = 1.

Zastosuj zapytanie definicji THEFIELD = 2 dla oryginalnej warstwy.

Zastosuj inne ustalone położenie etykiety

wprowadź opis zdjęcia tutaj

AKTUALIZACJA na podstawie komentarzy do oryginalnego rozwiązania:

Dodaj pole COORD i wypełnij je, używając

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

Podsumuj to pole, używając pierwszego i ostatniego dla etykiety. Dołącz tę tabelę z powrotem do oryginału, używając pola COORD. Wybierz rekordy, w których jodły <> trwają, i połącz pierwszą i ostatnią etykietę w nowym polu za pomocą

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

Użyj Count_COORD i THEFIELD, aby zdefiniować 2 „różne warstwy” i pola do ich oznaczenia:

wprowadź opis zdjęcia tutaj

Aktualizacja nr 2 inspirowana rozwiązaniem @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 ""

AKTUALIZACJA Listopad 2016, mam nadzieję, że będzie trwał.

Poniżej wyrażenia przetestowanego na 2000 duplikatach, działa jak urok:

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
źródło
Hej, złamałeś to! Ładny! Wiedziałem, że jest tam ktoś świszczący! Tak jak się spodziewałem, jest to bardzo iteracyjny proces, więc uruchom na dużym zbiorze danych, a etykiety narysują na zawsze (dobrze zrobiłem na moich danych testowych). Poprawiłem twój styl kodu, rozszerzając kilka linii. Uważam, że minimalistyczny, wszystkie na jednej linii, jest trudny do naśladowania.
Hornbydd
1
@Hornbydd dzięki za zmiany. Ta nakrętka była trudna do złamania z powodu zachowania etykiety (silnika?). Traktuje wszystkie parametry funkcji jak ciągi znaków! Właśnie dlatego pierwszy JEŻELI nie działał bez f = int ([FID]). Jeśli chodzi o szybkość, nigdy nie użyłbym jej na zestawie większym niż 50 punktów. Musi zostać przekonwertowany na skrypt wypełniający nowe pole, przechodząc przez zestaw danych tylko dwa razy: 1) kursor wyszukiwania, aby skompilować oba słowniki, 2) zaktualizuj kursor, aby z nich odczytać UWAGA: pierwsze 3 linie po instrukcji try są przestarzałe, po opublikowaniu rozwiązania I zdałem sobie sprawę, że można je bezpiecznie usunąć.
FelixIP
Do twojej wiadomości Nie miałem okazji wrócić do tego, ale planuję dać ci rozwiązanie w najbliższym tygodniu. Jest też inne obejście (to, którego użyłem w tym przypadku) bez Pythona, opublikuję odpowiedź na ten temat.
Dan C
Przekroczyłem tę stronę na geonet. Podobało mi się sprytne wykorzystanie globalnych słowników, potem pomyślałem o tym pytaniu i dodałem link do niego.
Hornbydd,
@ Hornbydd tak, jest bardzo inteligentny i szczegółowy jak wszystko od Richarda i znacznie zmieni moje (nasze) rozwiązanie. Można go jeszcze ulepszyć, usuwając kilka wierszy, w tym pierwszy. Jednak na podstawie czasu reakcji z PO wydaje się, że stracił zainteresowanie, ja też nie zawracam sobie głowy
FelixIP
4

Poniżej znajduje się częściowe rozwiązanie.

Jest to zgodne z wyrażeniem Advance. To niezbyt wydajne, dlatego pytam o liczbę punktów w twoim zestawie danych. Tak więc dla każdego wiersza, który zostanie oznaczony, buduje 2 słowniki, w dktórych kluczem jest XY, a wartością jest tekst, a d2który jest objectID i XY. Korzystając z tej kombinacji słowników, jest w stanie zwrócić pojedynczą etykietę, która jest konkatenacją ze znakami nowego wiersza, w moim przykładzie jest to konkatenacja TARGET_FID. „sj” to nazwa warstwy w spisie treści.

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]

Dlaczego jest to częściowe rozwiązanie, ponieważ robi się to za każdym razem, nie byłem w stanie wymyślić, jak wyłączyć wszystkie pozostałe punkty. To dlatego myślę, że ostatecznym rozwiązaniem jest jakiś python, który buduje nową warstwę pojedynczych punktów z pojedynczą etykietą zbudowaną ze stosu punktów.

Poniżej przedstawiono wynik 3 ułożonych w stos punktów, jak widać, że etykieta jest tworzona dla każdego punktu, ponieważ wszystkie one istnieją w tym samym miejscu.

Przykład

Hornbydd
źródło