È possibile combinare / unire etichette per punti sovrapposti in un'unica etichetta?


12

Ho punti che rappresentano posizioni campione. Spesso, più campioni vengono prelevati nella stessa posizione: più punti con la stessa posizione ma ID campione e altri attributi diversi. Vorrei etichettare tutti i punti che si trovano in una singola etichetta, con un testo in pila che elenca tutti gli ID campione di tutti i punti in quel punto.

Questo è possibile in ArcGIS utilizzando il normale motore di etichettatura o Maplex? So che potrei aggirare il problema creando un nuovo livello con tutti gli ID campione per ogni posizione in un valore di attributo, ma vorrei evitare di creare nuovi dati solo per l'etichettatura.

Fondamentalmente voglio passare da questo:

inserisci qui la descrizione dell'immagine

A questo (per il punto più in alto):

inserisci qui la descrizione dell'immagine

Senza eseguire alcuna modifica manuale delle etichette.


Quanti punti ci sono nel tuo set di dati?
Hornbydd,

Risposte:


11

Un modo per farlo è clonare il livello, usando query di definizione ed etichettandole separatamente, usando solo la posizione dell'etichetta in alto a sinistra per il primo livello e in basso a sinistra per il secondo.

Aggiungi il tipo intero THEFIELD al layer e popolalo usando l'espressione seguente:

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

Chiamalo con:

FirstOrOthers( !Shape! )

Crea una copia del livello nella tabella dei contenuti, applica la query di definizione THEFIELD = 1.

Applica la query di definizione THEFIELD = 2 per il livello originale.

Applicare diversi posizionamenti di etichette fisse

inserisci qui la descrizione dell'immagine

AGGIORNAMENTO basato sui commenti alla soluzione originale:

Aggiungi il campo COORD e popolalo usando

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

Riassumi questo campo usando first e last per l'etichetta. Unisciti a questa tabella con l'originale usando il campo COORD. Seleziona i record in cui i primi <> ultimi e concatenano la prima e l'ultima etichetta in un nuovo campo usando

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

Usa Count_COORD e THEFIELD per definire 2 'diversi livelli' e campi per etichettarli:

inserisci qui la descrizione dell'immagine

Aggiornamento n. 2 ispirato alla soluzione @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 ""

AGGIORNAMENTO Novembre 2016, si spera duri.

Sotto l'espressione testata su 2000 duplicati, funziona come un incantesimo:

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 "

Ehi, l'hai rotto! Bello! Sapevo che c'era qualcuno sfrigolante là fuori! Come mi aspettavo, è un processo molto iterativo, quindi esegui un set di dati di grandi dimensioni e le etichette impiegano per sempre a disegnare (bene, lo ha fatto sui miei dati di test). Ho modificato il tuo stile di codice espandendo alcune righe. Trovo il minimalista, tutto su una linea difficile da seguire.
Hornbydd,

1
@Hornbydd grazie per le modifiche. Questo dado era difficile da rompere a causa del comportamento dell'etichetta (motore?). Tratta tutti i parametri della funzione come stringhe! Questo è il motivo per cui il primo IF non ha funzionato senza f = int ([FID]). Per quanto riguarda la velocità, non la userei mai su un set superiore a 50 punti. Deve essere convertito in script che popola il nuovo campo esaminando il set di dati solo due volte: 1) cerca il cursore per compilare entrambi i dizionari, 2) aggiorna il cursore per leggere da essi NOTA: le prime 3 righe dopo l'istruzione try sono obsolete, dopo aver pubblicato la soluzione I realizzato che possono essere rimossi in modo sicuro.
FelixIP,

FYI Non ho avuto la possibilità di tornare a questo, ma ho intenzione di dare alla tua soluzione un vortice nella prossima settimana o giù di lì. C'è anche un'altra soluzione (quella che ho usato in questo caso) senza Python, posterò anche una risposta.
Dan C

Sono arrivato su questa pagina su geonet. Mi è piaciuto l'uso intelligente dei dizionari globali, poi ho pensato a queste domande e risposte e ho aggiunto un link ad esso.
Hornbydd,

@Hornbydd sì, è molto intelligente e dettagliato come tutto ciò che proviene da Richard e farà un'enorme differenza per la mia (nostra) soluzione. Uno può essere ulteriormente migliorato rimuovendo alcune righe che include la prima. Tuttavia, in base al tempo di risposta dell'OP sembra che abbia perso interesse, non mi preoccupo neanche
FelixIP

4

Di seguito è una soluzione parziale.

Questo va nell'espressione dell'etichetta Advance. Non è molto efficiente, quindi mi chiedo il numero di punti nel set di dati. Quindi per ogni riga che viene etichettata crea 2 dizionari in dcui la chiave è la XY e il valore è il testo e d2quale è l'ID oggetto e la XY. Utilizzando quella combinazione di dizionari è in grado di restituire una singola etichetta che è una concatenazione con caratteri di nuova riga, nel mio esempio sta concatenando TARGET_FID. "sj" è il nome del layer nel sommario.

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]

Perché questa è una soluzione parziale è che questo è fatto per ogni punto, non sono stato in grado di pensare a come si spengono tutti gli altri punti in pila. È per questo che penso che la soluzione definitiva sia un po 'di pitone che costruisce un nuovo livello di singoli punti con una singola etichetta costruita dalla pila di punti.

Di seguito è riportato l'output di 3 punti sovrapposti come puoi vedere l'etichetta viene creata per ciascun punto in quanto tutti esistono nella stessa posizione.

Esempio

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.