¿Se pueden combinar / fusionar etiquetas para puntos superpuestos en una sola etiqueta?

12

Tengo puntos que representan ubicaciones de muestra. A menudo, se tomarán múltiples muestras en la misma ubicación: múltiples puntos con la misma ubicación pero diferentes ID de muestra y otros atributos. Me gustaría etiquetar todos los puntos que se ubican conjuntamente con una sola etiqueta, con texto apilado que enumera todas las ID de muestra de todos los puntos en ese lugar.

¿Es esto posible en ArcGIS utilizando el motor de etiquetado normal o Maplex? Sé que podría solucionar esto creando una nueva capa con todos los ID de muestra para cada ubicación en un valor de atributo, pero me gustaría evitar crear nuevos datos solo para el etiquetado.

Básicamente quiero ir de esto:

ingrese la descripción de la imagen aquí

Para esto (para el punto más alto):

ingrese la descripción de la imagen aquí

Sin hacer ninguna edición manual de las etiquetas.

Dan C
fuente
¿Cuántos puntos hay en tu conjunto de datos?
Hornbydd

Respuestas:

11

Una forma de hacer esto es clonando la capa, usando consultas de definición y etiquetándolas por separado, usando la posición de etiqueta superior izquierda para la primera capa y la izquierda inferior para la segunda.

Agregue el entero de tipo THEFIELD a la capa y complételo con la siguiente expresión:

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

Llámalo por:

FirstOrOthers( !Shape! )

Cree una copia de la capa en la tabla de contenido, aplique la consulta de definición THEFIELD = 1.

Aplicar la consulta de definición THEFIELD = 2 para la capa original.

Aplicar diferentes ubicaciones de etiquetas fijas

ingrese la descripción de la imagen aquí

ACTUALIZACIÓN basada en comentarios a la solución original:

Agregue el campo COORD y complételo usando

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

Resuma este campo usando first y last para la etiqueta. Vuelva a unir esta tabla al original usando el campo COORD. Seleccione los registros donde los primeros <> últimos y concatene la primera y la última etiqueta en un campo nuevo usando

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

Use Count_COORD y THEFIELD para definir 2 'capas diferentes' y campos para etiquetarlas:

ingrese la descripción de la imagen aquí

Actualización n. ° 2 inspirada en la solución @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 ""

ACTUALIZACIÓN Noviembre de 2016, es de esperar que dure.

Debajo de la expresión probada en 2000 duplicados, funciona como encanto:

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
fuente
¡Hey, lo descifraste! ¡Agradable! ¡Sabía que había alguien mareado por ahí! Como esperaba, es un proceso muy iterativo, por lo que se ejecuta en un gran conjunto de datos y las etiquetas tardan en dibujarse para siempre (bueno, lo hizo en mis datos de prueba). Modifiqué tu estilo de código expandiendo algunas líneas. Encuentro lo minimalista, todo en una línea, difícil de seguir.
Hornbydd
1
@Hornbydd gracias por las ediciones. Esta tuerca era difícil de romper debido al comportamiento de la etiqueta (¿motor?). ¡Trata todos los parámetros de la función como cadenas! Es por eso que primero IF no funcionó sin f = int ([FID]). En cuanto a la velocidad, nunca la usaría en un set de más de 50 puntos. Tiene que convertirse a un script que complete el nuevo campo yendo a través del conjunto de datos solo dos veces: 1) buscar el cursor para compilar ambos diccionarios, 2) actualizar el cursor para leerlos NOTA: las primeras 3 líneas después de la declaración try son obsoletas, después de publicar la solución I se dio cuenta de que se pueden eliminar de forma segura.
FelixIP
FYI No he tenido la oportunidad de volver a esto, pero planeo darle un giro a su solución la próxima semana más o menos. También hay otra solución (la que usé en este caso) sin Python, también publicaré una respuesta al respecto.
Dan C
Encontramos en esta página en geonet. Me gustó el uso inteligente de los diccionarios globales, luego pensé en estas preguntas y respuestas y le agregué un enlace.
Hornbydd
@Hornbydd sí, es muy inteligente y detallado como todo de Richard y hará una gran diferencia en mi (la nuestra) solución. Se puede mejorar aún más eliminando algunas líneas que incluyen la primera. Sin embargo, según el tiempo de respuesta de OP, parece que perdió interés, yo tampoco me molesto
FelixIP
4

A continuación se muestra una solución parcial.

Esto entra en la expresión de etiqueta Avanzado. No es muy eficiente, por lo tanto, le pregunto sobre el número de puntos en su conjunto de datos. Entonces, para cada fila que se etiqueta, crea 2 diccionarios ddonde la clave es el XY y el valor es el texto y d2cuál es el objectID y el XY. Usando esa combinación de diccionarios, puede devolver una sola etiqueta, que es una concatenación con caracteres de nueva línea, en mi ejemplo concatena TARGET_FID. "sj" es el nombre de la capa en la tabla de contenido.

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]

Por qué esta es una solución parcial es que esto se hace para cada punto, no he sido capaz de pensar cómo apagaría todos los otros puntos apilados. Es por esto que creo que la solución definitiva es un python que crea una nueva capa de puntos únicos con una sola etiqueta construida a partir de la pila de puntos.

A continuación se muestra la salida de 3 puntos apilados, ya que puede ver que la etiqueta se crea para cada punto, ya que todos existen en la misma ubicación.

Ejemplo

Hornbydd
fuente