[GIS] Can labels for overlapping points be combined/merged into one label

arcgis-desktopattribute-tablelabelingmaplexoverlapping-features

I have points representing sample locations. Often, multiple samples will be taken in the same location: multiple points with the same location but different sample IDs and other attributes. I'd like to label all points which are co-located with a single label, with stacked text listing all the sample IDs of all the points in that spot.

Is this possible in ArcGIS using either the regular labeling engine or Maplex? I know I could work around this by creating a new layer with all the sample IDs for each location in one attribute value but I'd like to avoid creating new data just for labeling.

Basically I want to go from this:

enter image description here

To this (for the topmost point):

enter image description here

Without doing any manual editing of the labels.

Best Answer

One way of doing this is cloning the layer, using definition queries and labelling them separately, using upper-left only label position for the first layer and lower-left for second.

Add THEFIELD type integer to layer and populate it using expression below:

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

Call it by:

FirstOrOthers( !Shape! )

Create a copy of layer in the table of content, apply definition query THEFIELD=1.

Apply definition query THEFIELD=2 for original layer.

Apply different fixed label placement

enter image description here

UPDATE based on comments to original solution:

Add field COORD and populate it using

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

Summarise this field using first and last for label. Join this table back to original using COORD field. Select records where firs<>last and concatenate first and last label in a new field using

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

Use Count_COORD and THEFIELD to define 2 'different layers' and fields to label them:

enter image description here

Update #2 inspired by @Hornbydd solution:

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 ""

UPDATE November 2016, hopefully last.

Below expression tested on 2000 duplicates, works like charm:

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 "