Text Element Questions

1989
34
Jump to solution
08-14-2013 11:36 AM
GeoffOlson
Occasional Contributor
So I've got my text element function working in layout view, but it leaves me with two questions.  Can multiple rows be concatenated into the row.getValue or can it only find single fields?  Also, is it possible to return all feature records?

Here is the script I'm using to get the first result to fill the text box:

import arcpy  mxd = arcpy.mapping.MapDocument("Current") mapLyr = arcpy.mapping.ListLayers(mxd, "Detail_2013")[0]  concatElem = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "concat")[0]  rows = arcpy.SearchCursor(mapLyr.dataSource) row = rows.next()  typeElem.text = row.getValue("CONCAT")  mxd.save() del mxd, row, rows,


Any suggestions a much appreciated.
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
GeoffOlson
Occasional Contributor
I have a full working script!  Mzcoyle and Wayne, I couldn't have done this without you guys, so thank you so much for your patience and help!  I have to also thank South Kingstown, RI for their ESRI example, I wouldn't have been able to figure this out without their template.  Only one parameter was created and that was for the page number selection.

The tool takes the features in the data driven page map extent and lists the "CONCAT" field into two text elements on the screen.  The "CONCAT" field is a concatenated field of the feature's number on the map and the feature description.  Each feature's string is listed on a new line and the lines are divided so it appears as though there are two columns of text.  If there are an uneven number of lines, then the first column will have one more line than the second.

Here's the python code:
import arcpy, os  #set map doc and the layer to be used mxd = arcpy.mapping.MapDocument("Current") mapLyr = arcpy.mapping.ListLayers(mxd, "Detail_2013")[0]  #Get page number from data driven page - specified in the tool parameter dialogue box pageNum = arcpy.GetParameterAsText(0) ddp = mxd.dataDrivenPages arcpy.AddMessage(pageNum) pageID = mxd.dataDrivenPages.getPageIDFromName(pageNum) mxd.dataDrivenPages.currentPageID = pageID  #Set layer definition query, this contols the rowcount variable pageFieldValue = pageNum mapLyr.definitionQuery = '"pageNum" = %s' % pageNum  #Listing the text elements on the page concatElem1 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "concat1")[0] concatElem2 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "concat2")[0]  #Finds the number of features in the map and sets up the lists to evenly distribute into the two text elements/columns rowcount = int(arcpy.GetCount_management("Detail_2013").getOutput(0)) percolumn = round(rowcount / 2.0) count1 = 1 count2 = rowcount  #Specifies the features being used for the SearchCursor rows = arcpy.SearchCursor(mapLyr, "", "", "CONCAT") fieldrow  = arcpy.SearchCursor(mapLyr, "", "", "pageNum") currentpage = ""  text_var1 = str() text_var2 = str()  #The first for and if block limits the searched rows to the definition query #The seconded/indented for and if block adds the text fields to the text elements for row in fieldrow:     if currentpage != row.pageNum:         currentpage = row.pageNum         for row in rows:             if count1 <= percolumn:                 text_var1 += '{0}{1}'.format(row.getValue("CONCAT"), os.linesep)                 concatElem1.text = text_var1                 count1 += 1             elif count2 > percolumn:                 text_var2 += '{0}{1}'.format(row.getValue("CONCAT"), os.linesep)                 concatElem2.text = text_var2                 count2 - 1             else:                 pass     else:         pass  #Removed the definition query so all page numbers appear when the script is run next and refresh he layout view mapLyr.definitionQuery = "" arcpy.RefreshActiveView() del mxd, row, rows, rowcount, percolumn, count1, count2


And this part is what is in the validation field of the script tool:
class ToolValidator:   """Class for validating a tool's parameter values and controlling   the behavior of the tool's dialog."""    def __init__(self):     """Setup the Geoprocessor and the list of tool parameters."""     import arcpy     self.params = arcpy.GetParameterInfo()    def initializeParameters(self):     """Refine the properties of a tool's parameters.  This method is     called when the tool is opened."""     import arcpy, os, sys      #Reference Plat Index Layer to get unique Plat Numbers     mxd = arcpy.mapping.MapDocument("CURRENT")     mapLyr = arcpy.mapping.ListLayers(mxd, "Detail_2013")[0]      #Iterate rows in Plat Index Layer to generate unique name list     rows = arcpy.SearchCursor(mapLyr)     row = rows.next()      #Create and populate list     uniqueList = []     while row:       #If the value is not already in the list, append it       if row.getValue("pageNum") not in uniqueList:         uniqueList.append(row.getValue("pageNum"))       row = rows.next()            #Sort the list alphanumerically         uniqueList.sort()     self.params[0].filter.list = uniqueList     self.params[0].value = uniqueList[0]     return    def updateParameters(self):     """Modify the values and properties of parameters before internal     validation is performed.  This method is called whenever a parmater     has been changed."""     return    def updateMessages(self):     """Modify the messages created by internal validation for each tool     parameter.  This method is called after internal validation."""     return

View solution in original post

0 Kudos
34 Replies
MathewCoyle
Frequent Contributor
There are a few ways you could go about it. You can create a string variable and insert as many row values as you want is one way.

Here is an example of taking all values in the 'CONCAT' field.
rows = arcpy.SearchCursor(mapLyr.dataSource)
text_var = str()
for row in rows:
    text_var += '{0}{1}'.format(row.getValue("CONCAT"), os.linesep)

typeElem.text = text_var
0 Kudos
GeoffOlson
Occasional Contributor
Thanks for the reply.  I'm so excited it works!   As you can probably tell, I'm very new to scripting.  To take that one step further, is it possible to add a second column to the text element after 5 rows of text?  I don't expect you to script that, but just if you know it can be done and what functions would be used.  I'm looking at using example 2 from the arcpy graphic element section in the help file.  Now I'm really excited to work my way through the "Python Scripting for ArcGIS" workbook.
0 Kudos
GeoffOlson
Occasional Contributor
I've thought on this a little more and I think I figured out how to go about this.  Right now I've got one text element that the search cursor is listing its results.  By adding a second text element in the map layout, can the script start putting "overflow" rows in it?  My goal would be to take my current script:

import arcpy

mxd = arcpy.mapping.MapDocument("Current")
mapLyr = arcpy.mapping.ListLayers(mxd, "Detail_2013")[0]

addrElem = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "concat1")[0]


rows = arcpy.SearchCursor(mapLyr.dataSource)
text_var = str()
for row in rows:
    text_var += '{0}{1}'.format(row.getValue("CONCAT"), os.linesep)

addrElem.text = text_var

mxd.save()
del mxd, row, rows,


and I would like to add a GetCount_management so the total number of records on the map page are returned, then divide that by two and the second half of the records returned would go to "concat2."

I tried using gp.GetCount_management, but the Python windows says it doesn't know what "gp" is.  Is it part of the old arcgisscripting since import arcpy doesn't seem to know what it is?
0 Kudos
T__WayneWhitley
Frequent Contributor
arcpy does recognize it:

arcpy.GetCount_management...
0 Kudos
GeoffOlson
Occasional Contributor
Thank you, Wayne.

<--Noob.:(
0 Kudos
T__WayneWhitley
Frequent Contributor
...not really - I'm the noob for having to keep looking up the trick to get the result, as to convert to integer (I think directly a result object is returned), see this where the 'result' variable is the integer conversion:

result = int(arcpy.GetCount_management(lyrfile).getOutput(0))

http://resources.arcgis.com/en/help/main/10.1/index.html#//0017000000n7000000


Tricks!

Enjoy,
Wayne


EDIT-
Maybe this isn't directly relevant, then again maybe it is -- another trick I saw again today (which I had forgotten was available) is interactive help call:
>>> help(arcpy.GetCount_management)
Help on function GetCount in module arcpy.management:
 
GetCount(in_rows=None)
    GetCount_management(in_rows)
    
       Returns the total number of rows for a feature class, table, layer, or raster.
    
    INPUTS:
     in_rows (Table View or Raster Layer):
         The input feature class, table, layer, or raster. If a selection is defined on
         the input, only its rows are returned.
 
>>>  
0 Kudos
GeoffOlson
Occasional Contributor
Haha, yeah I just found that when I couldn't divide my result in half.  🙂

I just added these rows to the script:
rowcount = int(arcpy.GetCount_management("Detail_2013").getOutput(0))
percolumn = round(rowcount / 2.0)


I'm making improvements.  🙂

Now I just need to find out how to split the results.
0 Kudos
GeoffOlson
Occasional Contributor
So I've tried different ways of limiting the iterations for the text element results and I've made a little bit of progress.  I added an if statement to try and control which iterations go to which text element, but it didn't do what it was supposed to.  Instead, I just have two copies of the full text elements.

import arcpy, os

mxd = arcpy.mapping.MapDocument("Current")
mapLyr = arcpy.mapping.ListLayers(mxd, "Detail_2013")[0]

concat1Elem = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "concat1")[0]
concat2Elem = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "concat2")[0]

rowcount = int(arcpy.GetCount_management("Detail_2013").getOutput(0))
percolumn = round(rowcount / 2.0)


rows = arcpy.SearchCursor(mapLyr.dataSource)



crnum = int()
for crashnum in rows:
    crnum = row.getValue("Crash_Num")

if crnum <= percolumn:
    text_var = str()
    for row in rows:
        text_var += '{0}{1}'.format(row.getValue("CONCAT"), os.linesep)
    concat1Elem.text = text_var
else:
    text_var = str()
    for row in rows:
        text_var += '{0}{1}'.format(row.getValue("CONCAT"), os.linesep)
    concat2Elem.text = text_var

mxd.save()
del mxd, row, rows, crnum,

print "First column should have :" + str(percolumn) + " rows." #used to check that it calculated properly


I tried to use while and where but I couldn't figure out how or where to place those to get the script to run.
0 Kudos
MathewCoyle
Frequent Contributor
If you want to split the items half between each text element you can add a counter and if statement to your cursor to only do half the rows as defined by your getcount method previously. I'm sure there is a better way of doing this but I just can't think of it right now.

text_var = str()
count = 0
for row in rows:
    if count < percolumn:
        text_var += '{0}{1}'.format(row.getValue("CONCAT"), os.linesep)
        count += 1
    elif count == percolumn:
        concat1Elem.text = text_var
        text_var = str()
    else:
        text_var += '{0}{1}'.format(row.getValue("CONCAT"), os.linesep)
concat2Elem.text = text_var
0 Kudos