3

I am developing a series of maps in ArcGIS 10 and don't have a lot of space to label the features on the map. This is why I thought I would number each feature in the dataframe through and then export the labels as a list and put them in the map legend.

So a list in the following way is created and added to the legend

SO
1 Label
2 Label
3 Label

My current workflow to do this is the following: I am adding an attribute 'number' manually for example for all the orange SO points, then I label them with the number. I then export it as a table into Excel and then into Illustrator to generate a nice looking table and copy it back into ArcMap as an image.

Is there an easier way to do this in ArcGIS, I have a lot of maps to do and doing this manually takes a lot of time? Can you think of a better solution to do this?

10
  • Did you try just doing it with a legend in ArcGIS? Are you running into a problem where you need to export to Illustrator?
    – timlohnes
    Commented Sep 14, 2015 at 20:50
  • yes I tried that but you only get the labels that are labelled in the legend. I'd like to have the features numbered through and then have a list of the numbered features plus their label in the legend. So far I could not find any solution to do this within ArcGIS.
    – redshoe
    Commented Sep 14, 2015 at 21:02
  • 2
    If you add BOTH the number and label to the SO featureclass, then show the table, hide all the other columns then add the table to the layout view, you would get a similar looking graphic for inclusion in the legend without Illustrator. Most importantly, those reccuring tasks could be scripted. Commented Sep 14, 2015 at 21:09
  • 1
    Is this a legend or just a table for all visible points in layout view? I have python solution for point table changing with change of data driven pages
    – FelixIP
    Commented Sep 15, 2015 at 6:05
  • 1
    If you have the Maplex (an extension in 10.0, ships by default with 10.1 or maybe not until 10.2), you can look at Key Numbering. resources.arcgis.com/en/help/main/10.2/index.html#/…
    – recurvata
    Commented Sep 15, 2015 at 15:58

2 Answers 2

2

There are 2 scripts at work.

First creates attachment – text file - in data driven pages polygon stored in FGDB, name in TOC = Pages.

Data sourced into attachment table from layer called ‘pnts’, it has to have page definition query active. To control appearance of future table you’ll need text element in your layout called TABLE. This is what tool expects as parameters:

enter image description here

The values in field list are field names from ‘pnts’ that you want to show:

enter image description here enter image description here

Yes you have to change list to suit you needs.

Script iterates through pages and does:

  • Remove existing attachment
  • Create attachment from values taken from pnts table within current DDP.

    (I usually create a small buffer around pages, intersect it with pnts. This create 2 pnts where buffers overlaps)

I use is Calibri Light font for text in the TABLE.

Script:

import arcpy, traceback, os, sys, numpy
from arcpy import env
env.overwriteoutput=True

folder=arcpy.GetParameterAsText(0)
allNames=arcpy.GetParameterAsText(1)
fldNames=allNames.split(';')
table=r'in_memory\attach'


#Reference MXD and layers
try:
  def showPyMessage():
    arcpy.AddMessage(str(time.ctime()) + " - " + message)
  def isLayerExist (mxd,lName):
    layers = arcpy.mapping.ListLayers(mxd,lName)
    if len(layers)==0:
            raise NameError,'\n'+lName + " layer not found. Exiting.."+'\n'
    result=layers[0]
    return result

  mxd = arcpy.mapping.MapDocument("CURRENT")
  thePagesLayer = isLayerExist(mxd,"Pages")
  thePointsLayer = isLayerExist(mxd,"pnts")
  ddp = mxd.dataDrivenPages
  fld = ddp.pageNameField.name
  Page_Names=arcpy.da.TableToNumPyArray(thePagesLayer, fld)
  for elm in arcpy.mapping.ListLayoutElements(mxd):
    if elm.name == "TABLE":
      tableTxt = elm
      x=elm.elementPositionX
      y=elm.elementPositionY


##   THING TO CHANGE !!!!!    
  formatS="{:5d}{:8.2f}{:8.2f}{:8.2f}{:8.2f}{:8.2f}{:8.2f}{:8.2f}"

  for pageID in range(1, ddp.pageCount+1):
    arcpy.AddMessage(pageID)
    ddp.currentPageID = pageID
    arcpy.RefreshActiveView()
    fOut=folder+os.sep+Page_Names[pageID-1][0]+".txt"
    arcpy.SelectLayerByAttribute_management(thePointsLayer)
    linkValue=Page_Names[pageID-1][0]
    attachName=Page_Names[pageID-1][0]+".txt"
    arcpy.CreateTable_management('in_memory', 'attach')
    arcpy.AddField_management(table, "Page", "TEXT", "", "", 25)
    arcpy.AddField_management(table, "Page2", "TEXT", "", "", 250)
    curT = arcpy.da.InsertCursor(table,("Page","Page2"))
    theRow=(linkValue,fOut)
    curT.insertRow(theRow)
    arcpy.RemoveAttachments_management(thePagesLayer,
                                       fld, table,
                                       "Page")
    textB=""
    tbl=arcpy.da.TableToNumPyArray(thePointsLayer,fldNames)
    tbl=numpy.sort(tbl)
    if len(tbl)>0:
      m=0
      for rec in tbl:
  ##   THING TO CHANGE !!!!!    
        bit=formatS.format(rec[0],rec[1],rec[2],rec[4],rec[6],rec[3],rec[5],rec[7])
        textB+=bit+'\n'
        m+=1
        if m>54: break
      tableTxt.text = textB
      arcpy.SelectLayerByAttribute_management(thePointsLayer, "CLEAR_SELECTION")
      tableTxt.elementPositionX=x
      tableTxt.elementPositionY=y
      arcpy.RefreshActiveView()
    fileO = open(fOut, 'w')
    fileO.write(textB)
    fileO.close()
    arcpy.AddAttachments_management(thePagesLayer, fld,
                                    table, "Page", "Page2")
    arcpy.Delete_management(fOut)

except:
    message = "\n*** PYTHON ERRORS *** "; showPyMessage()
    message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
    message = "Python Error Info: " +  str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()

Output example I am using to control how prints will look like:

enter image description here

Note grey part is separate element here. You also have to change text format line in above script.

Second script does printing (export to pdf, using DDP name), assumes DDP layer name = Pages (the one with attachmet) and there is text element called TABLE in the layout

import arcpy, traceback, os, sys
from arcpy import env
env.overwriteoutput=True

folder=arcpy.GetParameterAsText(0)
aTable=arcpy.GetParameterAsText(1)


#Reference MXD and layers
try:
    def showPyMessage():
        arcpy.AddMessage(str(time.ctime()) + " - " + message)
    def isLayerExist (mxd,lName):
        layers = arcpy.mapping.ListLayers(mxd,lName)
        if len(layers)==0:
            raise NameError,'\n'+lName + " layer not found. Exiting.."+'\n'
        result=layers[0]
        return result

    mxd = arcpy.mapping.MapDocument("CURRENT")
    thePagesLayer = isLayerExist(mxd,"Pages")
    ddp = mxd.dataDrivenPages
    fld = ddp.pageNameField.name
    diction={}
    both=arcpy.da.TableToNumPyArray(thePagesLayer, (fld,"OBJECTID"))
    for row in both:
        diction[row[0]]=row[1]
    Page_Names=[row[0] for row in both]
    del both
    #Reference page layout elements
    for elm in arcpy.mapping.ListLayoutElements(mxd):
        if elm.name == "TABLE":
            tableTxt = elm
            x=elm.elementPositionX
            y=elm.elementPositionY

    for pageID in range(1,ddp.pageCount+1):
    ##  for pageID in range(1,3):
        ddp.currentPageID = pageID
        baseName=Page_Names[pageID-1]
        OID=diction[baseName]
        query='REL_OBJECTID = %s' %str(int(OID))
        with arcpy.da.SearchCursor(aTable,'DATA',query) as cursor:
            for row in cursor:
                binaryRep = row[0]
                textB=binaryRep.tobytes()
            if len(textB)>0:
                tableTxt.text = textB
            else:
                tableTxt.text = "            "
        tableTxt.elementPositionY=y
        arcpy.RefreshActiveView()
        ddp.exportToPDF(folder+os.sep + baseName + ".pdf","CURRENT")
        arcpy.AddMessage('Exported %i %s' %(pageID,baseName))
except:
    message = "\n*** PYTHON ERRORS *** "; showPyMessage()
    message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
    message = "Python Error Info: " +  str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()

In above example points are labelled by SectionID and table provides perfect reference.

This couple saved me weeks of time...

I am using 2 scripts because formatting is a hard part, so I run first script with only 2 layers - points and pages on a very basic mxd. Second works fine and I run it on the map with multiple layers, symbology sorted etc

This is an upper right corner of one of the output pages:

enter image description here

3
  • thank you so much. this looks very promising. I will have a look into it and probably modify the script to my needs, but this will save an enormous amount of time for sure! thank you @FelixIP!
    – redshoe
    Commented Sep 25, 2015 at 0:49
  • It is a life saver. Formatting line is a bit of challenge, the rest is piece of cake
    – FelixIP
    Commented Sep 25, 2015 at 1:04
  • 1
    @redshoe have a look at much cooler solution here gis.stackexchange.com/questions/170707/… note points in 2nd dataframe support page def.query from the first
    – FelixIP
    Commented Nov 21, 2015 at 3:58
2

Here are the steps to get a key number next to your label in a dynamic legend.

You symbolize however you want on the main map, then copy the layer to make a dummy layer for the legend where there is no symbolization but all the features are listed by name or whatever field you want. See below, the symbolized layer at the bottom and the top layer has no symbolization, but all the name values added.

enter image description here

Double click on the legend layer, the top POI layer, and add description to each value. Symbology tab > Right click on Value or Label > Edit Description and type the number. This is a very manual part, but if you have one layer for your whole map series, then it will be worth it. If you have lots of layers for this procedure, might need to look at one of the other solutions listed.

Add legend and only have the legend layer included. Right click on Legend > Properties > Items tab > click on legend layer > Style and pick the one highlighted here.

enter image description here

Then click Properties to tweak the Label Description setup however you like. To get what is shown in my final image below, use these settings.

enter image description here

enter image description here

Back in the Items tab for Font, choose Apply to the Class Description, make it bold and right justified.

To have it limit the legend to what is on each map, make sure to check "Only show classes that are visible in the current map extent".

Hope this makes sense.

enter image description here

2
  • I think this would be a much better answer if you included some instructions of how you achieved that labelling and legend.
    – PolyGeo
    Commented Sep 14, 2015 at 22:36
  • yes this is exactly what I am looking for. How did you achieve that?
    – redshoe
    Commented Sep 15, 2015 at 7:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.