Select to view content in your preferred language

labeling a layer with the values of stand-alone table (that is associated to the layer with 1-Many relationship),

5068
23
Jump to solution
11-04-2016 01:03 PM
rawansaleh1
Occasional Contributor III

Hi All,

I wondering how could we labeling a layer with the values of stand-alone table (that is associated to the layer with 1-Many relationship),

 

For example, I wanted to label the parcels with their owners knowing that the parcel layer is associated with owners table with 1-Many relationship.

 

What might be the best practice to perform this task?

 

Thanks in advance,

Rawan

0 Kudos
23 Replies
RichardFairhurst
MVP Honored Contributor

For Question 1 simply remove or comment out lines 52 and 53.

  # else:
    # expression += '\n<FNT name="Arial" size="10"><BOL>Owner Count = 0</BOL></FNT>'

For your second question it looks like you have created you own code for relationships you did not give in your previous example.  Therefore I do not know what field or relationship you are talking about in your second question.  All I can say is that in general you would need to supply a new subroutine in the code that converts the table and field into a dictionary and process the relationship similar to the code I previously wrote.

For the last question you did not show me which fields are null in the Buiding_T table or the code that you are using for this new relationship.  I have to know what fields are null to identify why that is preventing the code from running for that feature.  In general nulls are a special case that have to be trapped to avoid such problems, but at this point I don't have the information I need to trap them.

I have already made the code as adaptable as I am going to, and from my perspective it is already simple to adapt to new situations for anyone with reasonable experience in Python.  I do not plan to make it simpler.

0 Kudos
rawansaleh1
Occasional Contributor III

Dear Richard Fairhurst,

Thank you very much.

I want to clarify about my second question, actually I create the relationship based on a field “Ref_B”, and in my case I need my label to be (Ref_B from the feature class, and the “Name” from related table) as shown below,

so I tired the following code and I got the following error.

# Initialize a global dictionary for a related feature class/table
relateDict = {}
def FindLabel ( [Ref_B], [Ref_B]):
  # declare the dictionary global so it can be built once and used for all labels
  global relateDict
  # only populate the dictionary if it has no keys
  if len(relateDict) == 0:
    # Provide the path to the relate feature class/table
    relateFC = r"D:\RelateLabeling\s.gdb\Buildings_T"
    # create a field list with the relate field first (Ref_B),
    # followed by sort field(s) (Ref_B), then label field(s) (NAME)
    relateFieldsList = ["Ref_B", "NAME"]
    # process a da search cursor to transfer the data to the dictionary
    with arcpy.da.SearchCursor(relateFC, relateFieldsList) as relateRows:
      for relateRow in relateRows:
        # store the key value in a variable so the relate value 
        # is only read from the row once, improving speed
        relateKey = relateRow[0]
        # if the relate key of the current row isn't found 
        # create the key and make it's value a list of a list of field values
        if not relateKey in relateDict:
          # [searchRow[1:]] is a list containing
          # a list of the field values after the key.
          relateDict[relateKey] = [relateRow[1:]]
        else:
          # if the relate key is already in the dictionary 
          # append the next list of field values to the 
          # existing list associated with the key
          relateDict[relateKey].append(relateRow[1:])
    # delete the cursor, and row to make sure all locks release
    del relateRows, relateRow
  # store the current label feature's relate key field value
  # so that it is only read once, improving speed
  labelKey = [Ref_B]
  # start building a label expression.
  # My label has a bold key value header in a larger font
  expression = u'<FNT name="Times New Roman" size="14"><BOL>' + Ref_B +'</BOL></FNT>'
  # determine if the label key is in the dictionary
  if labelKey in relateDict:
    # sort the list of the list of fields
    sortedList = sorted(relateDict[labelKey])
    # add a record count to the label header in bold regular font
    # expression += u'\n<FNT name="Times New Roman" size="12"><BOL>NAME Count = {}</BOL></FNT>'.format(len(sortedList))
    # process the sorted list
    for fieldValues in sortedList:
       # append related data to the label expression
       # my label shows a list of related
       # cross streets and measures sorted in driving order
       expression += u'\n' + fieldValues[0]
    # clean up the list variables after completing the for loop
    del sortedList, fieldValues
  else:
    expression += '\n<FNT name="Arial" size="12"><BOL>NAME Count = 0</BOL></FNT>'
  # return the label expression to display
  return expression


 

But I found workaround to solve this, I add a new field in the feature class with different name but have the same value as Ref_B and used this field in the code and that working fine.

 

 

And for the third question I found that if we remove all null values the code works fine.

 

Best,

Rawan

0 Kudos
RichardFairhurst
MVP Honored Contributor

You did not have to create a new field.  You just needed to send one field to the equation, since you no longer need two fields for your labels like you did before.  Before your key value was [ParcelBlockCommunity], but you did not want that to appear in the label and wanted [ParcelNumber] instead.  For your new code you only need [Ref_B] once, since it is both your key and your label value.  Try the code below instead. The change to line 53 should address the Null value issue and I commented out the Count = 0 label code.

I have added a section for all the variables you need to set in lines 3 and 7 through 10 to make the code easier to modify.  You should not need to alter the code below those lines, unless you wanted to change the label to a new format.

# Initialize a global dictionary for a related feature class/table
relateDict = {}
def FindLabel ( [Ref_B]):
  # declare the dictionary global so it can be built once and used for all labels
  global relateDict
  # set user variables here
  keyField = [Ref_B]
  labelField = [Ref_B]
  FC = r"D:\RelateLabeling\s.gdb\Buildings_T"
  fieldList = ["Ref_B", "NAME"]
  # only populate the dictionary if it has no keys
  if len(relateDict) == 0:
    # Provide the path to the relate feature class/table
    relateFC = FC
    # create a field list with the relate field first (Ref_B),
    # followed by sort field(s) (Ref_B), then label field(s) (NAME)
    relateFieldsList = fieldList
    # process a da search cursor to transfer the data to the dictionary
    with arcpy.da.SearchCursor(relateFC, relateFieldsList) as relateRows:
      for relateRow in relateRows:
        # store the key value in a variable so the relate value 
        # is only read from the row once, improving speed
        relateKey = relateRow[0]
        # if the relate key of the current row isn't found 
        # create the key and make it's value a list of a list of field values
        if not relateKey in relateDict:
          # [searchRow[1:]] is a list containing
          # a list of the field values after the key.
          relateDict[relateKey] = [relateRow[1:]]
        else:
          # if the relate key is already in the dictionary 
          # append the next list of field values to the 
          # existing list associated with the key
          relateDict[relateKey].append(relateRow[1:])
    # delete the cursor, and row to make sure all locks release
    del relateRows, relateRow
  # store the current label feature's relate key field value
  # so that it is only read once, improving speed
  labelKey = keyField
  # start building a label expression.
  # My label has a bold key value header in a larger font
  expression = u'<FNT name="Times New Roman" size="14"><BOL>' + labelField +'</BOL></FNT>'
  # determine if the label key is in the dictionary
  if labelKey in relateDict:
    # sort the list of the list of fields
    sortedList = sorted(relateDict[labelKey])
    # add a record count to the label header in bold regular font
    # expression += u'\n<FNT name="Times New Roman" size="12"><BOL>NAME Count = {}</BOL></FNT>'.format(len(sortedList))
    # process the sorted list
    for fieldValues in sortedList:
      # append related data to the label expression
      # Skip the value if it is Null
      if fieldValues[0] != None:
        expression += u'\n' + fieldValues[0]
    # clean up the list variables after completing the for loop
    del sortedList, fieldValues
  # else:
    # expression += '\n<FNT name="Arial" size="12"><BOL>NAME Count = 0</BOL></FNT>'
  # return the label expression to display
  return expression‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
rawansaleh1
Occasional Contributor III

Dear Richard Fairhurst ,

 

Thank you very much, that exactly what I’m looking for.

Thanks for your massive effort.

 

Best,

Rawan

0 Kudos