|
BLOG
|
First of all, thank you for letting me know that this code and the discussions it has inspired have been extremely useful for streamlining your business processes. Since I have created this Blog, I have applied the concepts introduced here repeatedly myself. I want to keep this Blog focused on the core concepts of this technique that deal with the most common problems everyone can understand, but I have found numerous other ways to expand and adapt them to solve much more complex and unique problems that someday may justify the creation of a separate advanced level Blog Post. As far as your code, you should create a new forum post under the Python/Geoprocessing forum and include the code you want to have reviewed. Your post in that forum can be as unique to your needs as you want. I monitor that forum group, and if you mention my name or my blog post in your post I will certainly take a look at your code when I have time. Also, a lot of other Python users contribute to that forum that know more than I do about other aspects of Python and its optional modules who may offer alternative approaches or methods for solving your particular problem. Good luck.
... View more
02-08-2019
09:59 AM
|
0
|
0
|
33701
|
|
BLOG
|
The updateRows method should occur in the dedented position that is outside of the for loop. The for loop is iterating through the fields of a row and assigning each field with the corresponding item in a list which is stored as the value of the shared dictionary key. The row should only be updated once after all of the field values of the row have been have been transferred to the row from the dictionary.
... View more
02-08-2019
12:14 AM
|
0
|
0
|
33701
|
|
BLOG
|
The format won't work as described with all of those line returns. The label has to have the parcel as a header and then give a list of all related records below it in a single label. All of those returns will make the label too long if you have more than 2 or 3 related records under a given parcel. I coded a format that should look something like this: Parcel_no (folio): 999320100085 Related Record Count: 3 acct: A9928543 Permit_no: ABD2011-25964 dscr: DEMOLITION acct: A9928544 Permit_no: ABD2011-25965 dscr: DEMOLITION ... If you want to learn how to change the label format to suit your own tastes, you should search the web for Python string formatting examples that use the .format() method for building standard ArcMap labels and strings. All customization of the label occurs in Lines 37, 43 and 49. The record count in Line 43 is optional and can be commented out if you do not want it, and then only the Parcel_no (folio) will appear as the label if there are no related records. # Initialize a global dictionary for a related feature class/table
relateDict = {}
def FindLabel ( [PARCEL_NO] ):
# 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"C:\Taylor_maps\Permits\ResPermits.gdb\Export_Output"
# create a field list with the relate field first (folio),
# followed by sort field(s) (acct), then label field(s) (permit_no, dscr)
relateFieldsList = [ "folio" , "acct", "permit_num", "dscr"]
# 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 = [PARCEL_NO]
# start building a label expression.
# My label has a bold key value header in a larger font
expression = '<FNT name="Arial" size="12"><BOL>Parcel_No (folio)\r\n{}</BOL></FNT>'.format(labelKey)
# 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 += '\r\n<FNT name="Arial" size="10"><BOL>Related Record 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 += '\r\nacct: {}\r\nPermit_no: {}\r\ndscr: {}'.format(fieldValues[1], fieldValues[2], fieldValues[3])
# clean up the list variables after completing the for loop
del sortedList, fieldValues
else:
expression += '\r\n<FNT name="Arial" size="10"><BOL> </BOL></FNT>'
# return the label expression to display
return expression
... View more
02-01-2019
10:55 AM
|
1
|
0
|
18045
|
|
BLOG
|
The error message is due to the fact that the format of my example label is based on different field types and needs to be reformatted to match the fields you are using. The expression variable that formats your data into a label has to be customized. That part of the code is not generic and only works without modification for fields that match the data type or my original example fields. So what should your label look like? Write out an example label that presents the data the way you want it to appear, including any new line breaks, separator characters, and fixed text. Include a list of the actual values stored in each of the 4 fields so I know which parts of the label come from the fields and which parts come from a formatting string.
... View more
02-01-2019
09:10 AM
|
1
|
0
|
18045
|
|
BLOG
|
Both data sources have to include the field that contains Parcel numbers. So you are missing that field in the list of fields for the related table if [PARCEL_NO] and "acct" are not the fields that match each other. The first field in that list has to be the field that contains the values that exactly match the [PARCEL_NO] field. Please paste your code into a code sample window that preserves the code indentation. Make sure you are in this post directly, then press the Expand toolbar button then press the More button and choose Syntax Highlighter then drop down the Language options and choose Python. Then paste your code into the code sample window and hit the OK button to preserve the code indentation.
... View more
01-31-2019
03:15 PM
|
1
|
0
|
18045
|
|
POST
|
If your real goal is to make sure the aliases are shown with the exported shapefile in a layer, you can save a layer file of the layer you set up with aliases and they will be preserved. If you provide the layer file together with any exported shapefile to anyone then they can add the layer file to their map instead of the shapefile. If you use relative paths with standardized naming for your exported shapefiles and output them to the same directory as layer files set up for the standardized names, you can zip that directory and the receiver can add the layer file to their map rather than the shapefile and they shouldn't need to repoint the data source. At worst, the receiver may have to change the layer file data source to get everything working again.
... View more
01-04-2019
10:03 AM
|
1
|
1
|
7047
|
|
POST
|
Field aliases can only be saved in the data source in a geodatabase and these field aliases can be exported to another geodatabase, but not to a shapefile. Only geodatabase field aliases will be used when you check the "Use field alias as column header (optional)" button on the Table to Excel tool. When you set an alias in ArcMap you are setting a Layer field alias that only exists in that map. These aliases are never used by the Table to Excel tool and cannot be exported by that tool. The only way to preserve Layer Field Aliases is to select all or part of the records in a table view, press the Move to End of Table button to make sure you will output more than 2048 records, right click on the left-hand grey record selector for one of the records and choose the Copy Selected option. Then you can open Excel and hit the paste button. The records with be pasted into Excel and the Layer Field Aliases will be preserved. I just tested this method with 30,000 records and it worked without a problem. However, there are memory limits affecting this option, so at some point this option will fail if your data set becomes excessively large. This is from the "Understanding field properties, aliases and table display properties" help: "There are two types of field aliases: feature class field aliases (geodatabase only) and layer field aliases. You work with feature class field aliases in ArcCatalog on the Feature Class Properties dialog box. When a geodatabase feature class is added to ArcMap, its field aliases are used initially for the layer field aliases. However, after this there is no link between the two. Properties set in ArcMap will override the properties of the data source, but they will not be carried back to the data source. This means that if you change a layer field alias, it will not change the feature class field alias, and if you change a geodatabase field alias, it will not update the layer field alias for any existing layers based on the feature class."
... View more
01-03-2019
03:48 PM
|
1
|
3
|
7047
|
|
POST
|
I guess for points there is not an option to remove duplicate labels, and duplicates are produced by the code I gave you. I have modified the code to output a blank label if the apoint value has already created a label, so no duplicate labels will be created. You need to still modify line 11 for the path to your deej feature class (the code changed so it is line 10 and not line 9 that needs to change). Duplicate labels will be eliminated whether or not the points actually overlap. If you have some points that have the same apoint value but don't overlap and you want a label for each point when they don't overlap, then the code would have to examine the point geometry to only eliminate labels when the points actually overlap. I did not make the code do that. In order to even attempt to add subroutines for that I would need to know more about the scale of your map to determine how far apart the points have to be from each other before creating another label. That is complexity that I won't tackle, since I don't want to devote the time it would take to make code that will work for any random scale you may want to print. Someone else would have to contribute to this thread with ideas on how to tackle that if you want the labels to behave that way. # Initialize a global dictionary for a related feature class/table
relateDict = {}
dupDict = {}
def FindLabel ( [apoint] ):
# declare the dictionary global so it can be built once and used for all labels
global relateDict
global dupDict
# only populate the dictionary if it has no keys
if len(relateDict) == 0:
# Provide the path to the relate feature class/table
relateFC = r"C:\your_path\deej"
# create a field list with the relate field first (apoint),
# followed by sort field(s) (type), then label field(s) (name)
relateFieldsList = ["apoint", "type", "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 = [apoint]
# start building a label expression.
# My label has a bold key value header in a larger font
expression = '<FNT name="Arial" size="12"><BOL>{}</BOL></FNT>'.format(labelKey)
# determine if the label key is in the dictionary
if labelKey in relateDict:
if not labelKey in dupDict:
dupDict[labelKey] = labelKey
# sort the list of the list of fields
sortedList = sorted(relateDict[labelKey])
# process the sorted list
for fieldValues in sortedList:
symbol = ""
if fieldValues[0] == 1:
symbol = "<FNT name='Esri Cartography' size='12'><CLR blue='255'>Ê </CLR></FNT>"
elif fieldValues[0] == 2:
symbol = "<FNT name='Esri ERS Operations S1' size='12'><CLR red='255'>1 </CLR></FNT>"
elif fieldValues[0] == 3:
symbol = "<FNT name='Esri ArcPad' size='12'><CLR green='255'># </CLR></FNT>"
# append related data to the label expression
expression += '\n{0} - {1:.0f}'.format(symbol, fieldValues[1])
# clean up the list variables after completing the for loop
del sortedList, fieldValues
else:
expression = ""
else:
expression += '\n<FNT name="Arial" size="10"><BOL>apoint Count = 0</BOL></FNT>'
# return the label expression to display
return expression
... View more
12-17-2018
06:30 PM
|
2
|
0
|
2987
|
|
POST
|
This is not C++, it is Python. Anyway, did you change Line 9 to the path to your deej file? if the path is wrong or the feature class name is wrong, that error might occur. Please paste line 9 from the code you used and paste a picture of ArcCatalog showing the file path connection to your deej feature class. The other likely reason is that one of your field names is not actually apoint, type or name, which are listed in line 12. So are those the correct field names?
... View more
12-17-2018
07:33 AM
|
1
|
2
|
2987
|
|
POST
|
Try the code below in an advanced label expression by doing the following. 1. Change the parser to Python at the bottom of the label dialog. 2. Check the Advanced option checkbox. 3. Remove any code you see in the expression dialog box and paste the code below in this post into the expression text box and modify the path in line 9 of the code below (relateFC = r"C:\your_path\deej") from "C:\your_path\deej" to your actual deej feature class path. You have to change the path in line 9 to be the actual path to your deej point feature class, otherwise the code won't work.. If you have any problems please post the error message you get. # Initialize a global dictionary for a related feature class/table
relateDict = {}
def FindLabel ( [apoint] ):
# 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"C:\your_path\deej"
# create a field list with the relate field first (apoint),
# followed by sort field(s) (type), then label field(s) (name)
relateFieldsList = ["apoint", "type", "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 = [apoint]
# start building a label expression.
# My label has a bold key value header in a larger font
expression = '<FNT name="Arial" size="12"><BOL>{}</BOL></FNT>'.format(labelKey)
# 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])
# process the sorted list
for fieldValues in sortedList:
symbol = ""
if fieldValues[0] == 1:
symbol = "<FNT name='Esri Cartography' size='12'><CLR blue='255'>Ê </CLR></FNT>"
elif fieldValues[0] == 2:
symbol = "<FNT name='Esri ERS Operations S1' size='12'><CLR red='255'>1 </CLR></FNT>"
elif fieldValues[0] == 3:
symbol = "<FNT name='Esri ArcPad' size='12'><CLR green='255'># </CLR></FNT>"
# append related data to the label expression
expression += '\n{0} - {1:.0f}'.format(symbol, fieldValues[1])
# clean up the list variables after completing the for loop
del sortedList, fieldValues
else:
expression += '\n<FNT name="Arial" size="10"><BOL>apoint Count = 0</BOL></FNT>'
# return the label expression to display
return expression
... View more
12-16-2018
06:27 PM
|
1
|
4
|
2987
|
|
POST
|
As far as creating labels that cover a one to many relationship, see my blog on Creating Labels with Related Table Data. In your case the related table is the points themselves. You would use the apoint field as the dictionary key and the name field to build a list in the dictionary values. You would want to check the option to remove duplicate labels to avoid having all of the points with the same apoint value create copies of the label This label technique will be built to list all of the name values associated with a given apoint value, not just the set of names from the points that are currently visible on the map. To limit the label names to just the visible points you would need the points to have coordinate fields populated and set a definition query that limited the points to the set that falls within the display boundary coordinates. I don't think you can use graphic pictures in a label, but you can use fonts that contain those characters using the Window Character Map utility. For example, I created this label: Using this label expression: "<FNT name='Esri ERS Operations S1' size='12'><CLR red='255'>1 </CLR></FNT>" & [STREET_NAME] & vbcrlf & "<FNT name='Esri Cartography' size='12'><CLR blue='255'>Ê </CLR></FNT>" & [STREET_NAME] & vbcrlf & "<FNT name='Esri ArcPad' size='12'><CLR green='255'># </CLR></FNT>" & [STREET_NAME] I used filled symbols because I didn't find good versions of the unfilled symbols. Usually the symbol outline was too thin on the few unfilled symbols I found. Also I think it would be really challenging to find one or more fonts that gave all of the symbols the right thickness.
... View more
12-13-2018
08:39 AM
|
2
|
6
|
2987
|
|
POST
|
You did not check the Python option at the top of the Field Calculator. The code will definitely not work if the VB Script option is checked.
... View more
11-27-2018
07:24 AM
|
0
|
0
|
1821
|
|
POST
|
if scrolling through the table records is the issue, in addition to the two workarounds mentioned in May 28, 2017 post, you can type a record number in the record number text box that is higher than 2048, like 2050, to move to past the record scrolling sticking point. After that the record set counter may say there are only *4000 records in the table, but the down arrow or scroll bar will scroll the records beyond the 4096th record and adjust the record counter display to the next set of 2000 records until the last record is reached. However, the original workarounds are necessary if the objective is to use the Find functionality on the full record set.
... View more
11-26-2018
02:54 PM
|
1
|
0
|
1824
|
|
POST
|
How can you say a File Geodatabase is not a database? Are you saying only an Enterprise Geodatabase is a database? If so, what is the distinguishing feature that makes one a database and the other not? For my uses a File Geodatabase is a database, so is Access or a Personal Geodatabase. If you are saying a File Geodatabase is not easily deployed to people that do not use ArcGIS or Pro, then I have to agree that it has definite limitations.
... View more
10-30-2018
08:33 AM
|
0
|
1
|
4223
|
|
POST
|
I just upgraded from Windows 7 to Windows 10 and found that the path I got from the Run Standalone Scriptshelp page that ran propy.bat in Task Scheduler under Windows 7 does not work under Windows 10. "c:\Program Files\ArcGIS\Pro\bin\Python\scripts\propy.bat" works for me in Windows 7, but not in Windows 10. c:\Progra~1\ArcGIS\Pro\bin\Python\scripts\propy.bat works for both Windows 7 and Windows 10. So Scott from City of Greenville was correct that the path from the help page didn't work, at least under Windows 10.
... View more
10-16-2018
09:38 AM
|
1
|
2
|
4548
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 03-24-2026 11:37 PM | |
| 1 | 03-24-2026 08:01 PM | |
| 6 | 02-23-2026 08:34 AM | |
| 1 | 03-31-2025 03:25 PM | |
| 1 | 03-28-2025 06:54 PM |
| Online Status |
Offline
|
| Date Last Visited |
yesterday
|